Module Resolution
Алгоритм разрешения модулей в Node.js, TypeScript и bundler-ах различается принципиально; путаница с полями exports, main, module, расширениями файлов и conditions — источник 80% проблем при публикации npm-пакетов.
// Node.js ESM resolution (строгий):// 1. Bare specifier: 'lodash' → node_modules + "exports" field// 2. Relative path: './utils.js' → расширение ОБЯЗАТЕЛЬНО!// 3. Absolute URL: 'file:///…'
// Node.js CJS resolution (мягкий):// 1. require('lodash') → node_modules/lodash/package.json → "main"// 2. require('./utils') → utils.js → utils/index.js → utils.json// (автоматически добавляет .js / /index.js — в ESM этого нет!)
// TypeScript добавляет свои правила:// "moduleResolution": "bundler" | "node16" | "nodenext" | "classic"// В node16/nodenext: .ts файл импортируется через .js расширение!// import { fn } from './utils.js'; // ← .js, не .ts — это правильно// package.json "exports" field: приоритет над "main"// {// "main": "./dist/index.cjs", // legacy, если нет exports// "module": "./dist/index.esm.js", // НЕ стандарт Node.js, только bundler hint// "exports": {// ".": {// "import": "./dist/index.mjs", // ESM// "require": "./dist/index.cjs", // CJS// "types": "./dist/index.d.ts" // TypeScript// },// "./utils": {// "import": "./dist/utils.mjs",// "require": "./dist/utils.cjs"// }// }// }// Если "exports" определён → ТОЛЬКО перечисленные пути доступны// import 'lib/src/internal' → ERR_PACKAGE_PATH_NOT_EXPORTED (капсуляция!)// Conditions: Node.js и bundler применяют разные наборы// Node.js встроенные: "import", "require", "node", "default"// Пользовательские: node --conditions=production app.js
// Webpack: conditionNames: ['browser', 'import', 'module', 'default']// Vite: conditionNames: ['browser', 'module', 'import', 'default']
// Subpath patterns (Node 16+):// "exports": {// "./features/*": {// "import": "./dist/features/*.mjs",// "require": "./dist/features/*.cjs"// }// }// import 'my-lib/features/auth' → ./dist/features/auth.mjs
// "imports" (self-referencing внутри пакета):// "imports": { "#utils": "./src/utils.mjs" }// → import '#utils' внутри пакета (не экспортируется наружу)Итог: Module resolution — многоуровневый алгоритм, зависящий от типа модуля (CJS/ESM), среды (Node/bundler) и конфигурации exports; правильная настройка exports обязательна для dual-package публикации.