Это был обычный день установки патчей. Я исправил и обновил свои зависимости npm, не внося изменений в код, и внезапно некоторые из моих модульных тестов провалились.
Что за фигня!
Мои тесты провалились, поскольку Jest обнаружил неожиданный токен; они потерпели неудачу, потому что Jest не может обрабатывать пакеты только для ESM «из коробки». На самом деле Jest написан на CommonJS.
Но что это значит? Для этого нам нужно понять, почему существуют CommonJS и ESM.
На заре веб-разработки JavaScript в основном использовался для управления объектной моделью документа (DOM) с помощью таких библиотек, как jQuery. Однако появление Node.js также привело к использованию JavaScript для серверного программирования. Этот сдвиг увеличил сложность и размер баз кода JavaScript. В результате возникла потребность в структурированном методе организации кода JavaScript и управления им. Для удовлетворения этой потребности были введены модульные системы, позволяющие разработчикам разделить свой код на управляемые, повторно используемые блоки1.
CommonJS был создан в 2009 году и первоначально назывался ServerJS2. Он был разработан для серверного JavaScript и предоставляет соглашения для определения модулей. Node.js принял CommonJS в качестве системы модулей по умолчанию, что сделало его широко распространенным среди разработчиков серверной части JavaScript. CommonJS использует require для импорта и модуль.exports для экспорта модулей. Все операции в CommonJS синхронны, то есть каждый модуль загружается индивидуально.
В 2015 году ECMAScript представил новую систему модулей под названием ECMAScript Modules (ESM), предназначенную в первую очередь для разработки на стороне клиента. ESM использует операторы импорта и экспорта, а его операции являются асинхронными, что позволяет загружать модули параллельно3. Изначально ESM предназначался для браузеров, а CommonJS — для серверов. Он все больше и больше становился стандартом для экосистемы JS. В настоящее время современные среды выполнения JavaScript поддерживают обе системы модулей. Браузеры начали поддерживать ESM изначально в 2017 году. Даже Typescript адаптировал синтаксис ESM, и всякий раз, когда вы его изучаете, вы также изучаете ESM подсознательно.
Правда в том, что пакетов, предназначенных только для CommonJS (CJS), гораздо больше, чем пакетов, предназначенных только для ESM4.
Однако существует четкая тенденция. Количество пакетов только для ESM или пакетов с двумя модулями растет, в то время как пакетов только для CJS создается все меньше. Эта тенденция подчеркивает растущее предпочтение ESM и поднимает вопрос о том, сколько пакетов, предназначенных только для CJS, активно поддерживается.
Интересное сравнение CommonJS и ESM включает в себя тесты производительности. Благодаря своей синхронной природе CommonJS работает быстрее при непосредственном использовании операторов require и import. Давайте рассмотрим следующий пример:
// CommonJS -> s3-get-files.cjs const s3 = require('@aws-sdk/client-s3'); new s3.S3Client({ region: 'eu-central-1' }); // ESM -> s3-get-files.mjs import { S3Client } from '@aws-sdk/client-s3'; new S3Client({ region: 'eu-central-1' });
Я использовал aws-sdk S3-Client, поскольку он поддерживает два модуля. Здесь мы создаем экземпляр клиента, а затем выполняем его с помощью node:
hyperfine --warmup 10 --style color 'node s3-get-files.cjs' 'node s3-get-files.mjs' Benchmark 1: node s3-get-files.cjs Time (mean ± σ): 82.6 ms ± 3.7 ms [User: 78.5 ms, System: 16.7 ms] Range (min … max): 78.0 ms … 93.6 ms 37 runs Benchmark 2: node s3-get-files.mjs Time (mean ± σ): 93.9 ms ± 4.0 ms [User: 98.3 ms, System: 18.1 ms] Range (min … max): 88.1 ms … 104.8 ms 32 runs Summary node s3-get-files.cjs ran 1.14 ± 0.07 times faster than node s3-get-files.mjs
Как видите, s3-get-files.cjs и, следовательно, CommonJS работают быстрее.
Меня вдохновила публикация в блоге Buns.
Однако, если вы хотите создать свою JS-библиотеку, вам необходимо объединить ее. В противном случае вы отправите все node_modules. Используется esbuild, поскольку его можно связывать с CJS и ESM. Теперь давайте проведем тот же тест для встроенной версии.
hyperfine --warmup 10 --style color 'node s3-bundle.cjs' 'node s3-bundle.mjs' Benchmark 1: node s3-bundle.cjs Time (mean ± σ): 62.1 ms ± 2.5 ms [User: 53.8 ms, System: 6.7 ms] Range (min … max): 59.5 ms … 74.5 ms 45 runs Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options. Benchmark 2: node s3-bundle.mjs Time (mean ± σ): 45.3 ms ± 2.2 ms [User: 38.1 ms, System: 5.6 ms] Range (min … max): 43.0 ms … 59.2 ms 62 runs Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options. Summary node s3-bundle.mjs ran 1.37 ± 0.09 times faster than node s3-bundle.cjs
Как видите, s3-bundle.mjs теперь быстрее, чем s3-bundle.cjs. Файл ESM теперь работает даже быстрее, чем отдельный файл CommonJS, поскольку он приводит к меньшему размеру файла и более быстрому времени загрузки благодаря эффективному встряхиванию дерева — процессу, который удаляет неиспользуемый код.
Будущее модулей JavaScript, несомненно, склоняется к ESM. Это начинается при создании нового проекта NodeJS или даже проекта React. В каждом учебнике и статье используется оператор импорта, который, таким образом, является ESM. Несмотря на множество существующих пакетов CommonJS, тенденция меняется по мере того, как все больше разработчиков и сопровождающих принимают ESM из-за его преимуществ в производительности и современного синтаксиса. Другой вопрос также в том, сколько из этих проектов, предназначенных только для CJS, все еще поддерживаются.
ESM — это стандарт, который работает в любой среде выполнения, например NodeJS, Bun или Deno, а также в браузере без запуска на сервере. Нет необходимости конвертировать через Babel в CommonJS, поскольку браузер понимает ESM. Вы по-прежнему можете использовать Babel для преобразования в другую версию ECMAScript, но не следует конвертировать в CJS.
Вам следует разрабатывать только с использованием ESM, потому что каждая среда выполнения и браузер новее 2017 года понимают ESM.
Если ваш код не работает, возможно, у вас проблемы с устаревшими версиями. Рассмотрите возможность использования других инструментов или пакетов. Например, вы можете перейти с Jest на vitest или с ExpressJS на h3. Синтаксис остается прежним; единственная разница — это оператор импорта.
Основные выводы:
Чтобы начать, вы можете следовать этой Gist или получить вдохновляющую информацию здесь.
Для лучшего будущего JavaScript используйте ESM!
Презентация
https://www.freecodecamp.org/news/javascript-es-modules-and-module-bundlers/#why-use-modules ↩
https://deno.com/blog/commonjs-is-hurting-javascript ↩
https://tc39.es/ecma262/#sec-overview ↩
https://twitter.com/wooorm/status/1759918205928194443 ↩
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3