第 2 章:模块系统与 npm
模块系统决定了代码怎么拆分、怎么复用。这一章讲清 Node 的两套模块规范(CommonJS 和 ESM)、加载机制,以及 npm 包管理。
2.1 两套模块规范
Node 历史上用的是 CommonJS,后来逐步支持了浏览器的 ESM(ES Modules)。现在两套并存,你需要分清差别:
| 维度 | CommonJS | ESM |
|---|---|---|
| 语法 | require() / module.exports | import / export |
| 加载时机 | 运行时同步加载 | 编译时静态解析 |
| 默认值 | this 指向 module.exports | 顶层 this 为 undefined |
| 动态导入 | 需 require 变量路径 | 原生支持 import() |
| 适用 | 老项目、Node 生态传统 | 新项目、前端通用 |
CommonJS 写法:
javascript
// math.js —— 导出
function add(a, b) { return a + b; }
module.exports = { add };
// app.js —— 导入
const { add } = require('./math');
console.log(add(1, 2)); // 3ESM 写法(文件后缀 .mjs,或在 package.json 里设 "type": "module"):
javascript
// math.mjs —— 导出
export function add(a, b) { return a + b; }
// app.mjs —— 导入
import { add } from './math.mjs';
console.log(add(1, 2)); // 3选型建议:新项目直接用 ESM(
"type": "module"),与前端生态一致、支持 tree-shaking;维护老代码时能读懂 CommonJS 即可。
2.2 模块加载机制
require('./foo') 背后有一套解析规则,理解它能避免「找不到模块」的坑:
require('./foo')
│
▼
① 核心模块?(fs/http/path...)──是──► 直接返回内置模块
│ 否
▼
② 相对/绝对路径?(./ ../ /)──是──► 按路径解析文件
│ 否
▼
③ node_modules 查找 ──► 逐级向上查找 node_modules/foo
│
▼
④ 文件解析顺序:
foo.js → foo.json → foo.node → foo/(目录,找 index.js)关键规则:
node_modules逐级向上找:当前目录没有,就往父目录找,直到根目录。这也是「依赖提升」的原理;- 同名解析顺序:
foo.js优先于foo/目录(目录内找index.js或package.json的main字段)。
一个常见坑:项目里 require('foo') 找不到,大概率是 foo 没装、装错位置、或 main 字段指向了不存在的文件。
2.3 package.json 与依赖管理
每个 Node 项目的「身份证」就是 package.json,核心字段:
json
{
"name": "my-app",
"version": "1.0.0",
"type": "module", // 声明用 ESM
"main": "index.js", // 被 require 时的入口
"scripts": { // 常用命令
"dev": "node --watch index.js",
"start": "node index.js"
},
"dependencies": { // 生产依赖
"express": "^4.19.0"
},
"devDependencies": { // 开发依赖(测试、构建工具等)
"nodemon": "^3.0.0"
}
}版本号语义(^4.19.0):
^4.19.0 ──► 兼容 4.x(允许 4.20、4.30,不允许 5.0)
~4.19.0 ──► 兼容 4.19.x(只允许补丁更新)
4.19.0 ──► 锁定精确版本用
npm install会按^规则装最新兼容版本;package-lock.json记录精确版本,保证团队/CI 环境一致。lock 文件要提交进 git。
2.4 常用 npm 命令
bash
npm init -y # 快速生成 package.json
npm install # 按 package.json 安装全部依赖
npm install express # 安装并写入 dependencies
npm install -D jest # 安装并写入 devDependencies
npm uninstall xxx # 卸载
npm update # 按版本规则升级
npm run dev # 执行 scripts 里的 dev 命令
npm list # 查看已装依赖树2.5 本章小结
| 要点 | 说明 |
|---|---|
| 两套规范 | CommonJS(require)vs ESM(import),新项目推荐 ESM |
| 加载顺序 | 核心模块 → 路径 → node_modules 逐级向上 |
| package.json | 项目身份证,scripts / dependencies 是核心 |
| 版本号 | ^ 兼容大版本,~ 兼容补丁,lock 文件保证一致性 |
下一章预告
模块组织好了,下一步是 Node 的灵魂——异步编程。回调地狱怎么破?Promise 和 async/await 怎么选?事件又是怎么回事?