Node模块相关梳理

6 阅读1分钟

本文主要梳理一下Node中关于模块化的一些字段

Node.js 运行时如何加载模块

1.type

{
    "type": "module"
}

可选值

  • "module" → ES Module(ESM)
  • "commonjs"(默认)→ CommonJS(CJS)
文件type=moduletype=commonjs
.jsESMCJS
.mjsESMESM
.cjsCJSCJS

2.main

旧时代入口(CommonJS 入口)

{
    "main": "index.js"
}

3.module

不是 Node 标准字段!是给打包工具(webpack/rollup)用的ESM入口

{
  "module": "dist/index.esm.js"
}

4.exports

官方推荐,完全替代 main + module

  • 控制入口
  • 区分 ESM / CJS
  • 控制子路径导出
{
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}

访问方式

import x from 'pkg'
import y from 'pkg/utils'

// 下面这样是不允许的
import z from 'pkg/dist/xxx'

5.types/typings

给 TypeScript 用的类型入口

{
  "types": "dist/index.d.ts"
}

TypeScript / 构建工具如何解析模块

这些字段不在 package.json,而是在 tsconfig.json。有些字段名和package.json里是一样的,注意区分

1.module

{
  "compilerOptions": {
    "module": "ESNext"
  }
}

决定 TS 编译输出的模块格式,常见:

  • CommonJS
  • ESNext
  • NodeNext

2.moduleResolution

{
  "compilerOptions": {
    "moduleResolution": "NodeNext"
  }
}

决定 TS 如何解析 import 路径

常见模式

node(旧)

  • 不支持 ESM package 规则
  • 忽略 exports

👉 已逐渐淘汰

node16

②模拟 Node 16 行为:

  • 支持 type
  • 支持 exports
  • 根据 .js/.mjs/.cjs 判断

nodenext(推荐)

👉 完整模拟 Node ESM 行为

支持:

  • exports
  • imports
  • 条件导出
  • ESM / CJS 混用

👉 写现代库必须用这个

总结

1️⃣ Node 运行规则

  • type
  • exports
  • main

👉 决定:代码怎么执行

2️⃣ 构建 / TS 规则

  • module
  • moduleResolution

👉 决定:代码怎么被编译 & 找到依赖

最佳实践

package.json

{
  "type": "module",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  },
  "types": "./dist/index.d.ts"
}

tsconfig.json

{
  "compilerOptions": {
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "declaration": true,
    "outDir": "dist"
  }
}