Ошибка TypeScript: ReferenceError: exports is not defined при сборке
Причина ошибки
Ошибка ReferenceError: exports is not defined возникает из-за несоответствия между системой модулей, которую генерирует TypeScript, и тем, как Node.js обрабатывает эти модули в вашем окружении. Вы используете "module": "commonjs", что заставляет TypeScript генерировать код с exports и require. Однако Node.js может не распознавать exports как глобальную переменную, если вы запускаете файлы напрямую без правильной настройки.
По умолчанию Node.js работает с CommonJS (CJS), где exports — это псевдоним для module.exports. Но если ваш проект настроен как ES-модуль (например, в package.json указано "type": "module"), то exports не определён, и возникает ошибка. В вашем случае, судя по всему, Node.js ожидает ES-модули, а TypeScript генерирует CommonJS.
Решение 1: Использовать CommonJS (рекомендуется для Node.js)
Если вы хотите использовать CommonJS (стандарт для Node.js), убедитесь, что ваш package.json не содержит "type": "module". Если файл package.json есть, удалите эту строку или измените на "type": "commonjs". Затем скомпилируйте TypeScript как обычно:
tsc
node dist/main.js
Убедитесь, что в tsconfig.json указано "module": "commonjs" (как у вас). После компиляции должен получиться рабочий код.
Решение 2: Использовать ES-модули (современный подход)
Если вы предпочитаете ES-модули (import/export), измените настройки TypeScript и Node.js:
- В
package.jsonдобавьте"type": "module". - В
tsconfig.jsonизмените"module": "ESNext"или"module": "ES2020". - Скомпилируйте и запустите:
tsc && node dist/main.js.
Пример обновлённого tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"outDir": "./dist",
"rootDir": "./src",
"moduleResolution": "node"
}
}
Обратите внимание: при использовании ES-модулей в Node.js файлы должны иметь расширение .mjs или быть в папке с "type": "module". TypeScript автоматически сгенерирует .js файлы, но Node.js будет воспринимать их как ES-модули благодаря настройке в package.json.
Решение 3: Использовать ts-node для разработки
Если вы не хотите каждый раз компилировать код, установите ts-node и tslib:
npm install -D ts-node tslib @types/node
Затем запускайте напрямую:
npx ts-node src/main.ts
Этот инструмент автоматически обрабатывает модули и не требует настройки package.json.
Проверка окружения
Чтобы убедиться, что проблема именно в модулях, выполните команду node -e "console.log(typeof exports)". Если вернёт undefined, значит Node.js работает в режиме ES-модулей. Если вернёт object — CommonJS. Это поможет выбрать правильное решение.
Рекомендую начать с Решения 1 (CommonJS), так как оно наиболее стабильно для серверных приложений на Node.js. Если вы изучаете современный стандарт, переходите к Решению 2 (ES-модули).
<<Альтернативный подход: Использовать модуль "NodeNext"
В TypeScript 4.7+ появилась поддержка нового режима модулей "NodeNext", который автоматически определяет, какую систему модулей использовать на основе package.json. Это избавляет от ручной настройки.
Обновите tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "./dist",
"rootDir": "./src"
}
}
Теперь TypeScript будет следовать правилам Node.js: если в package.json есть "type": "module", он сгенерирует ES-модули; если нет — CommonJS. Это делает конфигурацию более гибкой и меньше подверженной ошибкам.
Важно: при использовании "module": "NodeNext" в импортах нужно указывать расширение файла (например, import { add } from './math.js'), даже в TypeScript-коде. Это соответствует поведению Node.js. Пример:
// main.ts
import { add, PI } from './math.js';
console.log(add(2, 3));
console.log(PI);
Этот подход особенно полезен, если вы планируете публиковать пакет в npm, так как он соответствует современным стандартам и работает как с CommonJS, так и с ES-модулями.