一、用 nvm 管版本
nvm install 20
nvm use 20
nvm alias default 20
nvm ls
装 nvm 后,每个 shell 可以切换不同 Node 版本。项目里放一个 .nvmrc:
20.11.1
进入目录执行 nvm use 就自动切换(可配合 shell hook)。
为什么需要:不同项目依赖不同 Node 大版本,全局只能装一个,切版本比改代码省事。
二、package.json 的两类依赖
{
"dependencies": { "express": "^4.19.2" },
"devDependencies": { "typescript": "^5.4.0" },
"engines": { "node": ">=18" }
}
dependencies:运行时需要,生产环境要装。devDependencies:构建、测试、类型检查用,生产可以不装。peerDependencies:插件类库声明「我需要宿主提供某个包」,由使用方安装。
装错位置很常见:把 typescript 放 dependencies,生产镜像就白装了几十 MB。
三、版本号前缀的含义
| 写法 | 允许升级到 |
|---|---|
1.2.3 | 精确版本 |
^1.2.3 | 1.x.x(不改主版本) |
~1.2.3 | 1.2.x(不改次版本) |
>=1.2.3 | 任意更高版本 |
默认 npm install 会写 ^,所以协作时每个人装到的版本可能不同——这就是 lock 文件存在的意义。
四、lock 文件必须提交
package-lock.json(npm)、pnpm-lock.yaml、yarn.lock 锁定整棵依赖树的精确版本。提交后:
- 所有人装到完全一样的依赖。
- CI 与生产环境可复现。
安装命令的区别:
npm install # 可能更新 lock 文件
npm ci # 严格按 lock 安装,不改 lock(CI 用这个)
pnpm install --frozen-lockfile
npm ci 会先删掉 node_modules 再装,速度更快、结果更确定,是 CI 的标准做法。
五、npm、pnpm、yarn 怎么选
| 特点 | |
|---|---|
| npm | 自带,生态最广,v7+ 也支持 workspace |
| pnpm | 硬链接共享存储,安装快、磁盘占用小,依赖隔离更严格 |
| yarn | 早期以速度和 lock 著称,现在优势不明显 |
新项目推荐 pnpm:装得快、node_modules 体积小很多(同样的依赖,npm 可能 500MB,pnpm 只要 100MB 出头)。但要注意某些老工具对 pnpm 的符号链接结构不兼容。
不要在一个项目里混用多个包管理器,会生成两套 lock 文件,依赖树互相打架。
六、NODE_ENV 的作用
NODE_ENV=production npm start
很多库(Express、React)会根据它切换行为:开发模式保留调试信息、详细报错;生产模式做压缩和优化。忘记设置会导致:
- 生产环境跑着开发版 React,体积大一倍、速度慢。
- Express 每次请求都输出堆栈,性能下降。
在 Dockerfile 里显式 ENV NODE_ENV=production,不要依赖运行时环境。
七、node_modules 为什么那么大
- 依赖嵌套:每个包带自己的依赖,可能重复几十份。
- 包含源码、类型声明、测试、文档。
- 平台相关的二进制(
sharp、esbuild)。
应对:用 pnpm、生产安装加 --omit=dev、打包时用 bundler 把依赖打进产物。
八、常见报错
| 报错 | 原因 |
|---|---|
Cannot find module | 依赖没装、路径错、大小写不一致(Linux 区分大小写) |
ERR_OSSL_EVP_UNSUPPORTED | Node 17+ 与老 webpack 的 OpenSSL 兼容问题 |
EACCES | 全局安装权限问题,别用 sudo,改用 nvm |
Unsupported engine | Node 版本不满足 engines 要求 |
ERESOLVE unable to resolve dependency tree | 依赖冲突,用 --legacy-peer-deps 临时绕过并排查 |
listen EADDRINUSE | 端口被占用,换端口或结束进程 |
内存溢出(JavaScript heap out of memory)时设置 NODE_OPTIONS=--max-old-space-size=4096。
小结
用 nvm 管版本并写 .nvmrc;运行依赖和构建依赖分开;lock 文件必须提交,CI 用 npm ci;新项目试 pnpm;生产显式设 NODE_ENV=production。