Npm Package 安装和版本管理
package 安装
package 通常有两种安装模式:
- 本地安装:默认安装方式,npm 会从当前目录开始逐级向上遍历寻找 package 的根目录(即有
package.json文件或node_modules目录的目录),如果未找到则把当前目录作为根目录。- 将 package 安装在根目录的
./node_modules下 - 将 package 的
bin安装在./node_modules/.bin下
- 将 package 安装在根目录的
- 全局安装:使用
-g指令,安装在$prefix/lib/node_modules和$prefix/lib/node_modules/.bin下。prefix:为 NodeJS 的安装位置,不同操作系统各有区别
- 锁定版本:使用
-exact参数安装的 package 会使用固定版本,例如 Prettier 等工具安装的时候应该固定版本,避免不同开发人员版本不同造成冲突。
package 更新
- 查看过期的包:
npm outdated - 兼容版本更新包:
npm update [package-name] - 非兼容版本更新:
npm install package-name@<version|latest>
语义化版本
npm version patch:更新补丁版本npm version minor:更新副版本npm version major:更新主版本
依赖管理
在项目中使用dependencies字段配置项目运行依赖的包,使用devDependencies配置项目开发依赖的包,,配置的依赖在npm install后都会下载到项目根目录下的node_modules目录中。配置使用键值对配置,key为包名value包版本。
{
"dependencies": {
"next": "^9.0.6",
"next-images": "^1.2.0",
}
}
版本控制
上面的例子中可以看到依赖包配置的版本除了语义化版本号,还有^修饰前缀,修饰符的作用限定安装规则,有以下选项:
- 只接受补丁版本更新:
1.0:只指定到副版本:1.0.x:使用 x 代表所有补丁版本~1.0.4:使用~前缀
- 接受副版本更新:
1:只指定主版本1.x:使用 x 代表所有副版本^1.0.4:使用^前缀
- 接受所有更新:
*x
- 固定版本:
1.0.4:明确指定版本号且无任何前缀
版本锁定&lockfile
npm 允许使用~ ^等修饰符进行版本控制的目的是为了能够自动的安装依赖包的问题修复和功能增强。但是依赖包的自动升级经常带来问题,一些是因为包管理者没有安装规范发布新版本,还有一种情况 A 按照新版本并使用新版本的功能开发,但是 B 仍然使用旧版本,B 在同步了 A 的代码后就会出现问题。
在多人开发的场景我们通常需要保证依赖的一致性,同时开发环境和生产环境也需要保证一致性(这点很重要)。
最直接的方法就是去掉版本修饰符,但是这样能解决问题吗?答案是并不能,因为你无法对依赖的依赖进行配置。npm5 提供package-lock.json文件来处理这个问题。
package-lock.jsonis automatically generated for any operations where npm modifies either the node_modules tree, or package.json.It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.
官方给出的介绍是package-lock.json会在 npm 更新node_modules tree和package.json的时候自动生成。它准确的描述了生成的 tree,以便在以后的安装中能够生成一致的 tree,无论是否有更新。
在执行npm install时如果存在lockfile配置文件时会按照配置文件的描述安装依赖。会忽略package.json配置,不会自动升级。npm 支持的 lockfile 配置文件按优先级优先级为:
npm-shrinkwrap.jsonpackage-lock.jsonyarn.lock
npm install和package-lock.json
- 如果只有一个
package.json文件,运行npm i会生成package-lock.json文件。 - 如果
package.json的 semver-range version 和package-lock.json中版本兼容,即使此时package.json中有新的版本,执行npm i也还是会根据package-lock.json下载。 - 如果手动修改了
package.json的 version ranges,且和package-lock.json中版本不兼容,那么执行npm i时package-lock.json将会更新到兼容package.json的版本。
TODO:package-lock.json被触发修改的场景:
package.json文件修改了registry的影响
在 CI、自动化测试等希望保证安装一致性的场景下推荐使用npm ci安装依赖,区别与npm install包括:
- 项目必须有 lockfile
- 只能用来初始化安装,不能用来安装单个包
- 当 lockfile 和
package.json不匹配是会报错,而不是更新 lockfile - 在执行
npm ci之前会移除node_modules目录 - 不会修改
package.json和 lockfile
TODO:在项目中使用 npm shrinkwrap 命令,会生成一个 npm-shrinkwrap.json 文件,将项目依赖锁定在当前在node_modules中使用的特定版本。在根目录运行npm install时,若发现存在npm-shrinkwrap.json和package-lock.json同时出现,会使用npm-shrinkwrap.json忽略package-lock.json。
| 位置 | 优先级 | |
|---|---|---|
package-lock.json |
只在根目录生效 | 低 |
npm-shrinkwrap.json |
任意目录 | 高 |
TODO:各种 dependence
dependencies: 业务依赖devDependencies: 开发依赖peerDependencies: 宿主环境依赖要求bundledDependencies/bundleDependencies: 打包依赖optionalDependencies: 可选依赖
TODO:非镜像包安装
- 如果依赖 git 仓库,需要本地安装 git
- 如果是 native node module,需要使用 node-gyp 编译,node-gyp 在不同的操作系统需要特定的运行环境