[JavaScript] Неудачный опыт миграции Electron приложения на ECMAScript модули
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Работая над своим стартовым шаблоном для Electron приложений я решил полностью отказаться от CommonJS модулей и использовать исключительно ECMAScript модули (далее ES модули или ESM). Я очень хочу иметь единый стиль кода везде. В моём проекте, как и у многих, непосредственно исходный код написан с использованием ES модулей, а всё остальное (тесты, файлы конфигурации, дополнительные скрипты для сборки) написано с использованием CommonJS модулей. Меня это сильно напрягает и я хочу чтобы всё было в одном стиле -- ESM.Кратко о модульных системах в NodeJSНачиная с 13-й версии NodeJS поддерживает две системы модулей:
- CommonJS: для подключения модуля используется функция require();
- ECMAScript: для подключения модуля используется ключевое слово import или функция import();
Важно знать:
- Вы не можете использовать в одном файле и require и import. Либо то, либо другое.
- В ES модуле вы можете подключить другой ES или CommonJS модуль.
- В CommonJS модуле вы можете подключать исключительно CommonJS модули.
Как NodeJS выбирает систему для конкретного файлаТут всё просто. Существует два расширения для файлов: .cjs и .mjs которые определяют что это CommonJS или ES модуль соответственно.Кроме этого, в package.json вы можете добавить свойство type со значением commonjs или module чтобы определить систему модулей по-умолчанию для файлов с расширением .js. Проблемы ElectronС чего начинается любое Electron приложение? С файла main.js (или background.js) -- точки входа, которая отвечает за запуск, создание окон, проверку обновлений, работу с системными api и так далее. Если сильно упростить, то обычно этот файл имеет такое содержимое:
const { app, BrowserWindow } = require('electron')
app.whenReady().then(() =>
new BrowserWindow().loadFile('index.html')
)
app.on('window-all-closed', () => app.quit())
Ничего особенного: подключение одной зависимости и вызов пары функций.Я хочу использовать по всему проекту ESM, поэтому установил в package.json "type": "module" и переписал main.js:
- const { app, BrowserWindow } = require('electron')
+ import { app, BrowserWindow } from 'electron'
И моё ещё не написанное приложение уже падает с ошибкой:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module
Это меня сильно удивило. Я использовал electron v12 у которого под капотом работает NodeJS 14.15. То есть ESM должны поддерживаться и работать. Файлы проекта подключаются как CommonJS модулиОказалось проблема в том, как electron, да и многие другие библиотеки, обрабатываются JavaScript файлы вашего проекта. А делают они это очень просто -- через вызов require:То есть когда вы запускаете
electron /path/to/main.js
Где-то внутри, electron вызывает
require('/path/to/main.js')
Вызывающий файл electron это CommonJS модуль. А наш файл main.js -- ES модуль. CommonJS модули не могут подключать ES модули. Отсюда и ошибка. И это главная проблема на пути к светлому ESM-будущему.Обходные путиПолучается я не могу использовать ES модули из-за архитектуры Electron. Это большая проблема, но всё-таки решаемая. К счастью, в моём проекте уже использовался сборщик. Так что я мог настроить его таким образом, чтобы преобразовывал ESM в CommonJS модули перед запуском Electron. Но чтобы nodeJS правильно определял какой это модуль конечные файлы нужно сохранять с расширением .cjs и это важно. Проблемы со сборщикамиК моему большому удивлению, это оказалось сложнее чем я предполагал. Некоторые инструменты не способны сохранять JavaScript в файлы с расширением не .js. Оно и логично, до недавних пор такой нужды не было.Например используя tsc или esbuild я не могу изменить расширение итоговых файлов, в том случае если собираю не один, а сразу несколько. Все файлы будут сохранены с расширением .js. Кроме этого многие сборщики/библиотеки думают про JavaScript файлы как про файлы исключительно с расширением .js. И когда приходит файл с расширением .cjs они не знают что с этим делать. Например Vite, с которым я работаю, имеет возможность настроить шаблон выходных файлов [filename].[hash].cjs. Но до недавних пор он не понимал какой loader использовать для .cjs и падал с ошибкой. Пришлось отправить отдельный PR (который уже принят) чтобы он воспринимал .cjs файлы как JavaScript.Проблемы с electron-builderС исходным кодом я разобрался относительно небольшой ценой. Теперь можно писать ES модули, и Vite будет преобразовывать их в CommonJS модули перед запуском Electron.Теперь, нужно обработанный код запаковать в исполняемое приложение. Для этого используется electron-builder. И тут меня ждали всё те же проблемы:
- electron-builder под капотом использует пакет read-config-file.
- read-config-file это CommonJS модуль, который использует require('/path/to/config.js') для чтения конфигурации в моём проекте.
- CommonJS модуль не может подключать ES модуль и падает с ошибкой.
Это означает, что я никак не смогу написать конфиг electron-builderкак ES модуль. Я решил пойти не компромисс и оставить конфиг electron-builder как CommonJS модуль с расширением .cjs. Это ставит крест на идее полностью отказаться от CommonJS модулей в проекте.Но, это не помогло.Дело в том, что read-config-file просто не воспринимает файлы .cjs как JavaScript:
if (config.endsWith('.js')) {
require(config)
} else {
// ... Это что угодно, но не JavaScript
}
Я отправил PR для исправления, но на момент публикации его так и не приняли.Подчеркну electron-builderв принципе не способен обрабатывать JavaScript файл конфигурации в проектах где в package.json указано "type": "module". Так что как временное решение пришлось переписать конфигурацию с .js на .json, отказавшись от некоторых возможностей.Проблемы с экосистемой в целомИ подобный подход встречается в очень многих библиотеках, что вызывает массу проблем, если вы хотите писать ES модулями.
- Например eslint. Я не могу написать конфиг для eslint как ESM. В документации так прямо и написано.И всё по той же причине -- где-то под капотом он использует require чтобы загрузить ваш .eslintrc.js. И единственный способ обойти это переименовать ваш файл в .eslintrc.cjs и продолжить использовать синтаксис CommonJS. А смена расширений снова приводит к некоторым проблемам. Так моя IDE отказывается определять .eslintrc.cjs как конфиг для eslint.
- Другой пример -- dotenv. В документации есть целый раздел посвященный ESM, возможным проблемам и вариантам их решения.
- Jest имеет экспериментальную, не стабильную и ограниченную поддержку ES модулей.
Больше проблем чем пользыВ какой-то момент я осознал, что желаемого мною результата не добиться. Я то и дело сталкиваюсь с проблемами, невозможностью использовать тот или иной пакет, вынужден идти на компромиссы и отказываться от каких-то возможностей. И это всё только на этапе подключения файлов. А ведь различий в модульных системах намного больше чем название одной функции. Так что мне пришлось отказаться от этой идеи на ближайшие несколько лет.
===========
Источник:
habr.com
===========
Похожие новости:
- [JavaScript, ReactJS] Поиск данных в столбцах таблицы с пагинацией (front-часть)
- [JavaScript, ReactJS, Карьера в IT-индустрии, TypeScript] Яндекс.Практикум запустил курс «React-разработчик»
- [Разработка веб-сайтов, JavaScript, Программирование, ReactJS] Разрабатываем чат на React с использованием Socket.IO
- [JavaScript, API] ExtendScript Работа с композициями
- [Высокая производительность, JavaScript, Программирование, Клиентская оптимизация, TypeScript] JavaScript нанобенчмарки и преждевременные тормоза
- [JavaScript, ООП] Создание квадратизированной галереи проектов на JS v 2.0
- [Ненормальное программирование, JavaScript, Разработка игр] Свежий взгляд на честное 3D в браузере
- [JavaScript, Программирование] Полезные расширения VS Code для JavaScript-разработчиков (перевод)
- [JavaScript, Программирование, Управление проектами, Управление продуктом, Карьера в IT-индустрии] Pet-проект для джуна. Или зачем и как выбрать pet project. (+личный опыт)
- [Информационная безопасность, Антивирусная защита, Разработка под MacOS] На 30 тысячах компьютеров с macOS нашли странный зловред, который ждёт команду
Теги для поиска: #_javascript, #_javascript, #_electron, #_esm, #_commonjs, #_javascript
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 09:43
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Работая над своим стартовым шаблоном для Electron приложений я решил полностью отказаться от CommonJS модулей и использовать исключительно ECMAScript модули (далее ES модули или ESM). Я очень хочу иметь единый стиль кода везде. В моём проекте, как и у многих, непосредственно исходный код написан с использованием ES модулей, а всё остальное (тесты, файлы конфигурации, дополнительные скрипты для сборки) написано с использованием CommonJS модулей. Меня это сильно напрягает и я хочу чтобы всё было в одном стиле -- ESM.Кратко о модульных системах в NodeJSНачиная с 13-й версии NodeJS поддерживает две системы модулей:
const { app, BrowserWindow } = require('electron')
app.whenReady().then(() => new BrowserWindow().loadFile('index.html') ) app.on('window-all-closed', () => app.quit()) - const { app, BrowserWindow } = require('electron')
+ import { app, BrowserWindow } from 'electron' Error [ERR_REQUIRE_ESM]: Must use import to load ES Module
electron /path/to/main.js
require('/path/to/main.js')
if (config.endsWith('.js')) {
require(config) } else { // ... Это что угодно, но не JavaScript }
=========== Источник: habr.com =========== Похожие новости:
|
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 09:43
Часовой пояс: UTC + 5