Двойной выходной формат ESM и CJS
Создавайте сборки в форматах ES-модулей и CommonJS с корректной настройкой поля exports в package.json
«Двойной выходной формат ESM и CJS» — бесплатный урок React Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.
Что такое ESM?
ESM (модули ECMAScript) — официальный стандарт модулей JavaScript, использующий синтаксис import и export. ESM можно анализировать статически: сборщики во время сборки могут точно определить, какие экспорты используются, что позволяет удалять неиспользуемый код. Современные браузеры и Node.js нативно поддерживают ESM.
Что такое CJS?
CJS (CommonJS) использует синтаксис require() и module.exports. Это исходная система модулей Node.js, которая по-прежнему нужна для совместимости со старыми средами Node.js, с Jest (исторически использовавшим CJS) и с кодом, в котором используется require(). CJS вычисляется динамически, поэтому удалять неиспользуемый код сложнее.
Двухформатный пакет: поставляйте оба формата
Современный пакет npm должен поставляться и в формате ESM, и в формате CJS для максимальной совместимости. Пользователи ESM (Vite, Next.js, современные сборщики) получают импорты с удалением неиспользуемого кода. Пользователи CJS (старые скрипты Node.js, Jest без настройки) получают совместимость с require(). Поле exports в package.json сообщает Node и сборщикам, какой формат использовать.
Поле exports
Поле exports в package.json — современный способ определить условные точки входа. Например: { '.': { 'import': './dist/esm/index.js', 'require': './dist/cjs/index.js', 'types': './dist/esm/index.d.ts' } }. Сборщики и Node.js версии 12 и выше считывают exports, чтобы автоматически выбрать подходящий формат.
Устаревшие поля main и module
Старые инструменты не понимают поле exports. Для совместимости также задайте: main, указывающее на вывод CJS (резервный вариант для старого require в Node), и module, указывающее на вывод ESM (подсказка для webpack/rollup, нестандартная, но широко поддерживаемая). Современные инструменты предпочитают exports, а старые используют main/module как резервный вариант.
Последствия type: module
Установка "type": "module" в package.json означает, что все файлы .js в пакете будут считаться ESM. Если вы поставляете оба формата, нужны явные расширения: при type: module используйте .mjs для файлов ESM и .cjs для файлов CJS или наоборот. tsup выполняет это автоматически.
Расширения .mjs и .cjs
Явное использование расширений файлов .mjs (ESM) и .cjs (CJS) обозначает формат независимо от поля type. Это устраняет неоднозначность. tsup может создавать файлы index.js (ESM) и index.cjs (CJS), когда формат задан как ['esm', 'cjs'], а поле type не указано, что соответствует наиболее распространённому соглашению.
Риск двухформатного пакета
Когда пакет предоставляет форматы ESM и CJS, сборщик пользователя может загрузить обе версии в одном процессе — например, версию ESM для основного приложения и версию CJS для теста Jest. Если в пакете есть состояние на уровне модуля, например контекст React, оба экземпляра будут иметь независимое состояние. Это и есть риск двухформатного пакета.
Снижение риска двухформатного пакета
Чтобы снизить этот риск, не храните состояние на уровне модуля в библиотеке (не используйте шаблоны синглтонов), точно задавайте условия exports, чтобы загружался только один формат, и документируйте, что тесты должны настроить сборщик на использование ESM. Этот риск особенно важен для библиотек с общими синглтонами.
Тестирование двухформатного вывода
Проверьте работу обоих форматов после сборки. Протестируйте CJS: node -e "const lib = require('./dist/cjs/index.js'); console.log(lib)". Протестируйте ESM: node --input-type=module --eval "import { Component } from './dist/esm/index.js'; console.log(Component)". Перед публикацией оба формата должны разрешаться без ошибок.
Экспорт нескольких точек входа
Поле exports поддерживает несколько точек входа: { '.': { import: './dist/esm/index.js', require: './dist/cjs/index.js' }, './utils': { import: './dist/esm/utils.js', require: './dist/cjs/utils.js' } }. Затем пользователи импортируют из 'your-lib' или 'your-lib/utils' и получают подходящий формат.
Поле exports в package.json
Каково основное назначение поля exports в package.json библиотеки?
Повторение урока: двухформатный вывод
ESM использует import/export и позволяет удалять неиспользуемый код. CJS использует require() для совместимости с Node.js. Поставляйте оба формата через поле exports в package.json с условиями import/require. Резервные варианты для старых инструментов: main (CJS) и module (ESM). Используйте расширения .mjs/.cjs или type: module для явного обозначения формата. После сборки протестируйте оба формата с помощью CLI node. Помните о риске двухформатного пакета при наличии состояния синглтона.
Часто задаваемые вопросы
Урок «Двойной выходной формат ESM и CJS» бесплатный?
Да — полный текст урока «Двойной выходной формат ESM и CJS» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.
Чему я научусь в уроке «Двойной выходной формат ESM и CJS»?
Создавайте сборки в форматах ES-модулей и CommonJS с корректной настройкой поля exports в package.json Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать React Academy?
Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Двойной выходной формат ESM и CJS»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке React Academy?
Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Сборка библиотек с Rollup и tsup
- Двойной выходной формат ESM и CJS
- Одноранговые зависимости и удаление неиспользуемого кода
- Публикация в npm и семантическое версионирование