Короткий пост о тривиальной вещи. Я в мире JS/Электрон. Я просто решил, что хочу упаковать свое приложение для Electron, но также и для обычного браузера. Почему ?
- А) Я могу сделать демо-версию приложения в Интернете!
- Б) Я могу использовать Кипарис для проверки!
Посмотрим, как далеко это зайдет, но в настоящее время я использую только две функции Electron/Desktop, которые можно легко имитировать в среде браузера:
- Чтение и запись конфигурации приложения => Электронный магазин / Локальное хранилище
- Чтение и запись файлов =› Node FS API / Локальное хранилище
Базовая структура
Простой. Давайте просто сосредоточимся на конфигурации приложения.
- Я определил общий «интерфейс» (AppConfig)
- Одна реализация-обертка ElectronStore (ElectronAppConfig)
- Вторая реализация, обертывающая локальное хранилище (LocalAppConfig).
Самый наивный подход
Я просто сохранил все 3 класса под /src
с помощью фабричного метода:
export function createAppConfig(appConfigSchema) { if (__electronEnv__) { const ElectronStore = require('electron-store'); return new ElelectronAppConfig(new ElectronStore({ schema:appConfigSchem})); } else { const defaults = Object .keys(appConfigSchema) .reduce((o, key) => ({...o, [key]: appConfigSchema[key]['default'] }),{}); return new LocalAppConfig(window.localStorage, defaults); } }
Затем в rollup.config.js
я использую plugin-replace для управления переменной __electronEnv__
:
import replace from '@rollup/plugin-replace'; const electronEnv = !!process.env.ELECTRON; plugins: [ replace({__electronEnv__: electronEnv}), ]
И, наконец, я обогащаю свои электронные задачи NPM с помощью переменной env в package.json
:
"electron": "ELECTRON=true run-s build pure-electron",
Вот и все, что касается наивного подхода. В большинстве случаев он работает (иногда возникает сбой с ошибкой require not found
, но обычно это решает перезагрузка).
Во всяком случае, пурист во мне хотел более четкой структуры, а встроенные require операторы казались странными.
Переход к более удовлетворительному подходу
Создайте еще одну папку рядом с /src
, назовем ее /includes
с тремя подпапками:
- api: AppConfig, …
- electron: index.js (содержит фабричные методы для всех электронных реализаций), ElectronAppConfig, …
- браузер: index.js (содержит фабричные методы для всех реализаций браузера), LocalAppConfig, …
Теперь используйте plugin-alias для псевдонима index.js нужной реализации во время сборки в rollup.config.js
:
import alias from '@rollup/plugin-alias'; const electronEnv = !!process.env.ELECTRON; const storagePackage = electronEnv ? 'electron' : 'browser'; plugins: [ alias({ entries: [ { find: 'storage', replacement: `./includes/${storagePackage}/index.js` } ] }) ]
И получите доступ к реализации в вашем основном коде:
import { createAppConfig } from 'storage'; const appConfig = createAppConfig(appConfigSchema);
Легкий. Здесь не слишком много усиления, но какая-то более четкая структура…
А теперь в машинописном тексте…
Как только я перешел к описанному выше подходу, я подумал: «Хорошо, давайте попробуем машинопись». Потому что это очевидно, если вы говорите об интерфейсах и реализациях, верно?
Я потерпел неудачу, используя точно такой же подход, но, к счастью, на помощь пришел машинописный текст path-mapping:
Вот rollup.config.js
часть:
import typescript from '@rollup/plugin-typescript'; plugins: [ typescript({ target: 'es6', baseUrl: './', paths: { storage: [`./includes/${storagePackage}/index.js`] } }) ]
Импорт работает так же, как и в предыдущем подходе!
Заключительные слова
Не уверен, что выполнил обещание о краткости, но поиск второго/третьего подходов занял у меня больше времени, чем ожидалось, и почти сводил меня с ума. Отчасти я виню свою неопытность в мире JS, отчасти то, что пространство для поиска такой проблемы кажется довольно запутанным. Тем не менее, может быть несколько альтернатив, которые стоит изучить:
- Динамические модули: https://medium.com/@leonardobrunolima/javascript-tips-dynamically-importing-es-modules-with-import-f0093dbba8e1
- Несколько пакетов (с отдельными зависимостями), управляемые с помощью… скажем, Lerna…
Если у вас есть отзывы или вдохновение, дайте мне знать!