npm 包管理器

npm(Node Package Manager)是 Node.js 的官方包管理工具,也是全球最大的开源软件注册中心。它允许开发者安装、共享和管理依赖包。本章将详细介绍 npm 的核心概念、常用命令、package.json 的配置,以及如何发布自己的包。

1. 什么是 npm?

npm 由三个主要部分组成:

  • 网站:用于浏览、搜索和了解包的信息(npmjs.com)。
  • 注册表(registry):一个大型的 JavaScript 软件数据库。
  • 命令行工具(CLI):开发者通过终端与 npm 交互的工具。

npm 随 Node.js 一起安装,因此安装 Node.js 后就可以直接使用 npm 命令。

2. 初始化项目:package.json

每个 Node.js 项目都应该有一个 package.json 文件,它记录了项目的元数据(名称、版本、描述)以及依赖列表。可以通过 npm init 命令交互式创建。

npm init
# 或使用默认值快速创建
npm init -y

生成的 package.json 示例:

{
  "name": "my-app",
  "version": "1.0.0",
  "description": "我的第一个 Node.js 应用",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

重要字段说明:

  • nameversion:包的唯一标识,如果要发布到 npm,这两个字段必须。
  • main:入口文件,当其他模块通过 require('my-app') 引入时,加载的就是这个文件。
  • scripts:定义可以通过 npm run 执行的命令。
  • dependenciesdevDependencies:生产环境和开发环境的依赖。

3. 安装依赖

3.1 安装包

# 安装到 dependencies(生产依赖)
npm install express

# 安装到 devDependencies(开发依赖,如测试框架)
npm install --save-dev jest

# 全局安装(作为命令行工具)
npm install -g nodemon

安装后,包会被下载到 node_modules 目录,并且相关信息会自动记录到 package.jsonpackage-lock.json 中。

3.2 安装指定版本

npm install lodash@4.17.21

3.3 卸载包

npm uninstall express
# 或
npm remove express

3.4 查看已安装的包

npm list          # 查看当前项目的依赖
npm list -g       # 查看全局安装的包
npm list --depth=0 # 只显示顶层依赖

4. 语义版本控制(SemVer)

npm 使用语义版本控制(Semantic Versioning,简称 SemVer)来管理包的版本。版本格式为:主版本号.次版本号.修订号

  • 主版本号:当做了不兼容的 API 修改。
  • 次版本号:当做了向下兼容的功能性新增。
  • 修订号:当做了向下兼容的问题修正。

package.json 中,我们可以指定依赖的版本范围:

  • "lodash": "4.17.21":精确版本。
  • "lodash": "^4.17.21":兼容次版本(允许安装 4.x.x 中 >=4.17.21 的最新版,但不会升级到 5.0.0)。
  • "lodash": "~4.17.21":大约等效于修订号(允许 4.17.x 的最新版,但不会升级到 4.18.0)。
  • "lodash": ">=4.17.21 <5.0.0":范围语法。
  • "lodash": "latest":始终安装最新版(不推荐)。

5. package-lock.json

package-lock.json 自动生成,它精确描述了 node_modules 树中每个包的版本和依赖关系,确保在不同机器上安装得到完全相同的依赖树。这个文件应该提交到版本控制中。

当运行 npm install 时,npm 会优先根据 lock 文件安装;如果 lock 文件不存在或与 package.json 冲突,则会更新 lock 文件。

6. npm scripts

scripts 字段可以定义常用的命令,通过 npm run <script-name> 执行。一些特殊命名的脚本可以直接运行(如 npm startnpm test)。

{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js",
    "build": "webpack --mode production",
    "test": "jest"
  }
}

执行方式:

npm start
npm run dev
npm test

脚本可以访问 node_modules/.bin 中的可执行文件,因此无需全局安装工具。

7. 依赖分类

  • dependencies:生产环境依赖,应用运行时需要(如 express、lodash)。
  • devDependencies:开发环境依赖,仅用于开发、测试、构建(如 jest、webpack、nodemon)。
  • peerDependencies:宿主依赖,告知 npm 该包需要某个包,但不会自动安装(常用于插件)。
  • optionalDependencies:可选依赖,安装失败不会导致整个安装失败。
  • bundleDependencies:打包依赖,发布时会将指定包一起打包。

8. 缓存与清理

npm 会缓存下载的包,以加速后续安装。可以通过以下命令管理缓存:

npm cache clean --force   # 清理缓存
npm cache verify           # 验证缓存完整性

9. 配置 npm

可以通过 npm config 命令查看和设置配置。常用配置:

npm config list                     # 列出所有配置
npm config set registry https://registry.npmmirror.com  # 设置镜像源
npm get registry                    # 查看当前源

10. 发布自己的包

要将自己的模块发布到 npm 上,需要先注册 npm 账号,然后登录:

npm login
# 输入用户名、密码和邮箱

确保 package.json 中的 name 在 npm 上唯一,然后运行:

npm publish

更新包时,需要修改版本号(遵循 SemVer),然后重新发布:

npm version patch  # 修订号+1
npm version minor  # 次版本号+1
npm version major  # 主版本号+1
npm publish

如果要取消发布(72小时内允许):

npm unpublish <package-name>@<version>

11. npx 命令

npx 是 npm 5.2+ 自带的一个工具,用于执行 node_modules 中的可执行文件,无需全局安装。例如:

npx create-react-app my-app   # 临时安装 create-react-app 并运行

npx 会先检查本地是否有该命令,如果没有则临时下载(执行后删除),非常适合执行一次性脚手架工具。

12. 私有包与作用域

npm 支持作用域(scoped)包,格式为 @scope/package-name。作用域包默认是私有的,需要付费账户才能发布私有包,但也可以公开。

npm publish --access public   # 发布公开的作用域包

13. 常见问题

  • 依赖版本冲突:可以使用 npm dedupe 尝试扁平化依赖树,或者使用 npm ls 查看冲突。
  • node_modules 体积过大:可以使用 npm prune 移除无关依赖,或使用工具如 npm-check
  • 安全漏洞:运行 npm audit 检查漏洞,npm audit fix 自动修复。
最佳实践:
  • 始终将 package-lock.json 提交到版本控制。
  • 使用 npm ci 代替 npm install 在 CI/CD 环境中,它更快且严格遵循 lock 文件。
  • 区分 dependenciesdevDependencies
  • 定期运行 npm outdated 查看可更新的包。

小结

npm 是 Node.js 生态中不可或缺的工具。掌握 npm 的基本命令和 package.json 的配置,能够让你更高效地管理项目依赖、执行脚本,甚至分享自己的模块。下一章我们将深入探讨 package-lock.json 的细节和 npm 的依赖解析算法。