Node.js 包管理(npm)
npm(Node Package Manager)是世界上最大的开源软件仓库——上百万个第三方库,几乎你想要的功能都有现成包。装一个库就 npm install 几秒钟搞定,这种"组装式"开发效率是 Node 最大的红利。这一章把 npm 工程化的方方面面讲透。
1. npm 是什么?
npm 做三件事:
- 仓库(registry):一个公共服务器(npmjs.com),存放所有人发布的包。
- 命令行工具(CLI):
npm命令,用来安装、卸载、发布包。 - 依赖管理:通过
package.json和node_modules管理项目依赖。
装完 Node 你就自动有了 npm,不用单独装。下面从最常用的命令开始。
2. 安装依赖:install 全家桶
# 初始化项目(生成 package.json)
npm init -y
# 安装包:默认装进 dependencies
npm install express
# 简写:npm i express
# 安装多个
npm i express cors body-parser
# 安装指定版本
npm i express@4.18.0
npm i express@^4.18.0 # 兼容 4.18.x 的最新版
npm i express@latest # 最新版
# 安装开发依赖(只在开发时用,不进生产)
npm i --save-dev nodemon
# 简写:npm i -D nodemon
# 全局安装命令行工具
npm i -g pm2
# 全局包可以在任意目录直接敲命令名运行
# 卸载
npm uninstall express
# 简写:npm un expressdependencies vs devDependencies是新手最常混淆的点:
dependencies:生产环境也要用的包。比如 express、lodash、数据库驱动。部署时必须装。devDependencies:只在开发时用的包。比如测试工具(jest)、构建工具(vite、webpack)、格式化工具(eslint、prettier)、热重启工具(nodemon)。生产环境用npm install --production不会装这些,能省体积。
判断标准:"这个包 import 到运行代码里了吗?"是 → dependencies;只在开发流程(build/test/lint)用 → devDependencies。
3. package.json:项目的身份证
每个 Node 项目根目录都有一个 package.json,它是项目的"身份证",记录项目信息和依赖:
{
"name": "my-app", // 项目名(小写、无空格)
"version": "1.4.2", // 语义化版本号
"description": "我的应用",
"main": "index.js", // 入口文件(被 require 时加载)
"type": "module", // module 用 ESM,commonjs 用 CJS
"scripts": {
"dev": "nodemon index.js",
"start": "node index.js",
"build": "vite build",
"test": "jest",
"lint": "eslint ."
},
"dependencies": { // 生产也要用
"express": "^4.18.2"
},
"devDependencies": { // 只在开发时用
"nodemon": "^3.0.0",
"jest": "^29.0.0"
},
"engines": {
"node": ">=18.0.0" // 指定 Node 版本要求
}
}node_modules 不要提交 git——它可能几百 MB 甚至几 GB,而且可以通过 package.json + package-lock.json 完全还原。把它加进 .gitignore。
4. scripts:自定义命令
scripts 是 package.json 最实用的字段——把常用命令起个简短名字,用 npm run xxx 执行:
// package.json 的 scripts 字段是最常用的功能
// 它让你用 "npm run 命令名" 执行任意 shell 命令
{
"scripts": {
"dev": "nodemon index.js",
"start": "node index.js", // start 特殊:可直接 npm start
"test": "jest",
"build": "vite build",
"lint:fix": "eslint . --fix"
}
}
# 运行脚本
npm run dev # 任意脚本都用 npm run
npm start # start 可省略 run(快捷别名)
npm test # test 同样可省略
# 串行/并行
# 串行用 &&
npm run lint && npm run test
# 并行用 &
npm run watch:css & npm run watch:js好处是统一团队命令——不管你的项目用 webpack 还是 vite、测试用 jest 还是 mocha,团队成员只要敲 npm run dev / npm run build / npm test 就行,不用记各种工具的具体参数。新人入职看一眼 package.json 的 scripts,就知道这个项目怎么跑。
5. npx:一次性执行命令
npx 用来执行 npm 包提供的命令行工具,不需要先全局安装。这对脚手架工具特别有用:
# npx:执行包的命令,不用先全局安装
# 临时执行一次性命令,执行完不残留
npx create-react-app my-app
npx create-vite latest
npx degit user/repo my-folder
# 也用于执行本地 node_modules 里的命令(等价于 npm run)
npx eslint .
# 用指定版本的包
npx -p package@1.0.0 command-name
# 现代替代:npm 7+ 内置了类似能力
npm create vite@latest # 等价于 npx create-vitenpx 会临时下载包、执行命令、执行完不残留。比"全局装一堆工具"干净得多。
6. 语义化版本号(SemVer)
npm 的版本号遵循 SemVer 规则:主版本.次版本.修订号(如 1.4.2)。理解它才能正确管理依赖:
# 语义化版本号(SemVer):主版本.次版本.修订号
# 1 . 4 . 2
# major minor patch
# major(主版本):不兼容的破坏性更新(从 1.x 升到 2.x 要改代码)
# minor(次版本):向后兼容的新功能(从 1.4 升到 1.5 不会破)
# patch(修订):向后兼容的 bug 修复(从 1.4.2 升到 1.4.3)
# package.json 里的版本前缀
"express": "4.18.2" # 必须精确这个版本
"express": "^4.18.2" # ^ 兼容:>=4.18.2 <5.0.0(允许 4.x 内升级)
"express": "~4.18.2" # ~ 近似:>=4.18.2 <4.19.0(允许 4.18.x)
"express": "*" # 任意版本(危险,别用)
"express": ">=4.0.0" # 大于等于 4.0.0package.json 里 ^ 和 ~ 前缀的含义必须搞清楚——它决定了 npm install 时能升到什么版本。生产项目推荐用 ^(允许次版本升级,既安全又能拿到 bug 修复)。
7. lock 文件:锁住依赖
这是工程化最容易踩坑的地方。package.json 写的是版本范围(如 ^4.18.2),不同时间 npm install 装到的具体版本可能不同——这会导致"在我电脑上能跑、在你那不行"。lock 文件就是来解这个的:
# package-lock.json 的作用:锁定确切版本
# 假设 package.json 写 "express": "^4.18.2"
# 你 npm install 时,可能装了 4.18.2、4.18.3、4.19.0...
# 不同时间安装,版本可能不同 → "在我电脑上是好的"问题
# package-lock.json 记录了:
# express 实际装的是 4.19.2
# express 的依赖的依赖也都精确到具体版本
# 整棵依赖树的精确状态
# 别人 clone 你的项目后 npm install
# npm 会读 lock 文件,装出和你完全一致的依赖版本
# 重要习惯:
# ✅ 提交 package-lock.json 到 git
# ✅ 删除 node_modules 后能 npm install 复现
# ❌ 别手改 package-lock.json
# ❌ 别把 node_modules 提交到 git(太大)所以团队协作铁律:提交 lock 文件。npm 用 package-lock.json,yarn 用 yarn.lock,pnpm 用 pnpm-lock.yaml。一个项目里只用一个包管理器,不要 npm 和 yarn 混着用,lock 会打架。
8. 升级与维护
# 查看过期的依赖
npm outdated
# Package Current Wanted Latest
# express 4.18.2 4.19.2 5.0.0
# react 17.0.2 17.0.2 18.2.0
# 升级到 Wanted 范围内的最新(安全)
npm update
# 升级到 Latest(可能破坏性)
npm i express@latest
# 大版本升级用专用工具(自动改代码)
npx npm-check-updates -u # 把 package.json 全升到 latest
npm install
# 删除 node_modules 重装(修复怪问题)
rm -rf node_modules package-lock.json
npm install升级分两种:npm update 在 SemVer 范围内升级(相对安全);跨大版本升级(如 express 4 → 5、react 17 → 18)要小心,通常有 breaking changes,要看迁移指南。大项目升级前务必有完整测试覆盖。
9. 发包:把自己写的库发到 npm
# 1. 注册账号:到 npmjs.com 注册
# 2. 命令行登录
npm login
# 输入用户名、密码、邮箱、OTP(开了两步验证)
# 3. 准备 package.json
# name 必须全网唯一(scoped 包用 @前缀避免冲突)
# 比如 "@yourname/myutils"
# main 指向入口文件
# version 必须是新版本(已发的不能重复)
# 4. 发布
npm publish
# scoped 包默认是私有的(收费),公开发布要加参数
npm publish --access public
# 5. 更新版本后再发
# 先改 version,再 npm publish
# 或用 npm version 命令自动改
npm version patch # 1.0.0 → 1.0.1
npm version minor # 1.0.0 → 1.1.0
npm version major # 1.0.0 → 2.0.0
npm publish发包是参与开源社区的基本功。从一个工具函数、一个组件库开始,你的代码就能被全世界开发者用到。
10. pnpm / yarn:替代选择
npm 不是唯一选择。其他流行的包管理器:
- yarn:Facebook 出品,早期比 npm 快、有 workspaces。现在差距不大。
- pnpm:用硬链接共享依赖,磁盘占用极低(多个项目共用一份 node_modules),安装飞快。强烈推荐给 monorepo(多包仓库)。
- bun:最新的 JS 运行时,自带包管理器,速度比 npm 快几十倍。
初学用 npm 就够了;项目大了、磁盘吃紧、或做 monorepo,再考虑 pnpm。
小结
npm 是 Node 工程化的命脉。记住几条:dependencies 放生产、devDependencies 放开发;scripts 统一团队命令;提交 lock 文件;SemVer 的 ^ ~ 含义;node_modules 永远别提交。下一篇学最经典的 Web 框架 Express,把前面学的 HTTP 模块包装成优雅的 API 服务。
← 上一篇 Node.js 异步编程
下一篇 Node.js Express 框架 →