Как опубликовать библиотеку для ESM и CJS
Вопрос
Как бы ты настроил package.json библиотеки, чтобы её можно было подключать и через import, и через require?
Попробуйте сами
Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.
Показать ответ и разбор
Коротко
Что должно прозвучать в ответе
Поле exports с условиями import / require / types
Отдельные сборки: .js (ESM) и .cjs, или наоборот .mjs и .js с нужным type
Типы для обеих версий (types-условие первым)
Закрыть внутренние пути: всё, чего нет в exports, недоступно
Помнить про dual package hazard: не держать состояние в модуле или делать ESM-обёртку над CJS
Как вариант: выпускать только ESM, раз Node 22 умеет require(esm)
Что могут спросить следом
- Почему условие types должно идти первым?
- Что сломается, если убрать main и оставить только exports?
Разбор
Главный инструмент это поле exports с условными экспортами. Для точки "." я указываю types для TypeScript, import на ESM-сборку и require на CJS-сборку. Порядок важен: условия проверяются сверху вниз, поэтому types ставлю первым.
Сборку делаю двумя файлами, например index.js при "type": "module" и index.cjs. Всё, чего нет в exports, закрыто, так пользователи не завяжутся на внутренние файлы.
Опасность двух сборок в dual package hazard: если одно приложение загрузит библиотеку двумя путями, будет две копии с разным состоянием. Поэтому либо библиотека без состояния, либо ESM-вход делается тонкой обёрткой над CJS.
На 2026 год есть и простой путь: выпустить только ESM. Node 22.12+ умеет require() для ES-модулей без top-level await, так что CommonJS-потребители тоже смогут подключиться.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.