nodejs 包管理工具 npm 依靠 package.json 文件进行依赖管理。
package.json 文件中的 dependencies 与 devDependencies 配置,决定了下载一个包后还需要如何下载依赖包;依赖包后面声明的版本配置则决定了其位置如何存放。
在一个目录下,如果存在 package.json,那么执行命令 npm install
,则会安装相关依赖包到当前目录下的 node_modules 目录中。如果加了 -g 参数则会安装到全局。
一个 package.json 文件的示例:
{ "name": "demo", "main": "index.js", "version": "1.0.0", "description": "demo by lzw.me", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "fis3 server start --type node --www ./output --no-daemon --no-browse", "dev": "fis3 release qa -wLcd ./output", "qa": "fis3 release -wcd ./output", "release": "fis3 release production" }, "config": { "port": "1337" }, "repository": { "type": "git", "url": "http://github.com/lzwme/demo.git" }, "keywords": [ "lzw.me", "demo" ], "author": "demo", "license": "ISC", "dependencies": { "antd": "^0.12.4", "react": "^0.14.3", "react-dom": "^0.14.3", "react-router": ">=2.0.0", "redux": "~3.0.5" }, "devDependencies": { "babel-core": "^6.3.26", "babel-preset-es2015": "^6.3.x", "babel-preset-react": "^6.3.x", "node-sass": ">=3.4.2" } }
dependencies 与 devDependencies 是最常见的依赖声明,此外还有 optionalDependencies。
dependencies
dependencies 列举了当前包/应用的依赖。安装一个包时,添加了参数 --save
,则会将该包添加到当前目录下 package.json 文件中的 dependencies 中。
npm install <package_name> --save
如果只安装当前 package.json 下的 dependencies 依赖,可使用命令:
npm install --production
devDependencies
安装一个包时,添加了参数 save-dev
,则会将该包添加到当前目录下 package.json 文件中的 devDependencies 中。
npm install <package_name> --save-dev
devDependencies 与 dependencies 的主要区别是区分开发与生产环境。例如在生产环境中,当设置了 set NODE_ENV="production"
,则在执行 npm install
时, devDependencies 列表不会被安装。
如果只安装当前 package.json 下的 devDependencies 依赖,也可使用命令:
npm install --dev
# npm3 中使用命令:
npm install --only=dev
optionalDependencies
添加了 –optional 参数,则尝试安装 optionalDependencies 中列出的依赖。这些依赖是可选的,默认不会被安装。
npm install –-save-optional
save 参数简写
在 npm3 中,–save、–save-dev 和 –save-optional、–save-bundle、–save-exact 都有对应的简写:
-S: --save
-D: --save-dev
-O: --save-optional
-B: --save-bundle
-E: --save-exact 与 --save, --save-dev or --save-optional 一起使用,保证
save-exact
save-exact 与 –save, –save-dev 或 –save-optional 一起使用,用于设置要求保存为精确的版本号。如:
npm install jquery --save-exact --save
依赖包与版本号
版本号的设置对 npm install
下载包的目录结构起着决定性作用。 在 npm3 中对包管理作了大幅度的优化,全局兼容的版本会尽量安装在 node_modules 根目录下,不兼容的版本则会安装在依赖包内部的 node_modules 下。
GNU 规范版本号命名方法
常见的 npm 包命名方法以 GNU 规范为主。GNU 软件命名方案如下:
主版本号.子版本号[ .修正版本号 [ 编译版本号]]
即:
Major_Version_Number.Minor_Version_Number[Revision_Number[.Build_Number]]
一般约定的版本变更规则为:
- 主版本号:有重大变更,不对上一个变更版本作兼容保证时修改
- 子版本号:有新的功能增加时修改
- 修正版本号:一般为 bug 修复,功能增强
- 编译版本号:一般是编译器在编译过程中自动生成的,只定义其格式
- 从主版本号开始,有一级变更则后面的版本归零。
有些版本还会添加前缀标签,如:v1.0.0
。npm 默认识别的前缀即为 v
,也可以通过修改配置改变它。例如改为 s:
npm config set tag-version-prefix='s'
npm 版本修饰前缀与依赖含义
在依赖声明列表中,我们看到各包的后面还会带着版本号,版本号前则有不同的前缀修饰。npm 正是通过这种前缀修饰决定版本下载方式。
当安装一个包并添加了 –save 等参数要求保存到 package.json 中时,默认使用的是 ^。通过修改 save-prefix
配置,可以修改这个默认的设置。如:
npm config set save-prefix='~'
常见的版本号表达式示例:
表达式 | 版本范围 |
>=1.2.7 | 大于等于1.2.7 |
>=1.2.7 <1.3.0 | 1.2.7,1.2.8,1.2.9 |
1.2.3 – 2.3.4 | >=1.2.3 <=2.3.4 |
1.2 – 2.3.4 | >=1.2.0 <=2.3.4 |
1.2.3 – 2.3 | >=1.2.3 <2.4.0 |
1.2.3 – 2 | >=1.2.3 <3.0.0 |
* | >=0.0.0 |
1.x(等价于1.X) | >=1.0.0 <2.0.0 |
1.2.x | >=1.2.0 <1.3.0 |
“”(等价于*) | >=0.0.0 |
1(等价于1.x.x) | >=1.0.0 <2.0.0 |
1.2(等价于1.2.x) | >=1.2.0 <1.3.0 |
~1.2.3(>=1.2.3 <1.(2+1).0) | >=1.2.3 <1.3.0 |
~1.2(>=1.2.0 <1.(2+1).0) | >=1.2.0 <1.3.0 |
~1(>=1.0.0 <(1+1).0.0) | >=1.0.0 <2.0.0 |
~0.2.3(>=0.2.3 <0.(2+1).0) | >=0.2.3 <0.3.0 |
~0.2(>=0.2.0 <0.(2+1).0) | >=0.2.0 <0.3.0 |
~0(>=0.0.0 <(0+1).0.0) | >=0.0.0 <1.0.0 |
~1.2.3-beta.2 | >=1.2.3-beta.2 <1.3.0 |
^1.2.3 | >=1.2.3 <2.0.0 |
^0.2.3 | >=0.2.3 <0.3.0 |
^0.0.3 | >=0.0.3 <0.0.4 |
^1.2.3-beta.2 | >=1.2.3-beta.2 <2.0.0 |
^0.0.3-beta | >=0.0.3-beta <0.0.4 |
^1.2.x | >=1.2.0 <2.0.0 |
^0.0.x | >=0.0.0 <0.1.0 |
^0.0 | >=0.0.0 <0.1.0 |
^1.x | >=1.0.0 <2.0.0 |
^0.x | >=0.0.0 <1.0.0 |
npm 使用习惯建议
修改 npm 默认仓库
另外值得一提的是,在国内环境下,推荐使用 cnpm代替 npm,或者执行如下设置来默认使用淘宝提供的仓库:
npm config set registry https://registry.npm.taobao.org
npm config set disturl https://npm.taobao.org/dist
定期执行版本过期检测与升级
依赖越来越多,出现问题的概率也随之增加。那么定期的更新是有必要的。npm 提供了三个重要的命令来帮助你做这件事情:
npm shrinkwrap
包依赖的版本声明、安装先后顺序以及后续的升级,随之带来的 node_modules 目录结构也完全不同。那么这个命令可以帮你对该目录作结构检测与调整。
npm outdated --depth 9999
该命令会列出当前安装的包是否过时了,你可以根据新版本的情况再作决定是否要执行 npm update
。这是一个比较安全的升级做法。 depth 参数可对依赖检测深度作限制。
npm update
这是一个重要但又需要谨慎的命令。经验而谈,如非必须,在工作时间内尽量不要执行全局的更新。
如果没有每周更新包依赖的习惯,一次更新可能涉及的内容非常多。大量的更新耗时不说,出问题了后的情况是比较头疼的事情。
根据 npm outdated 列出的列表作选择性更新是可取的。
在开发中使用 shrinkwrap
不严格的版本号限制,也带来了版本号的不确定性。如果要控制上线的风险,我们就必需要解决这个问题,这时候,就需要使用 npm shrinkwrap
这个命令来解决问题。
npm shrinkwrap 可以按照当前项目 node_modules 目录内的安装包情况生成稳定的版本号描述。通过 shrinkwrap 命令,我们可以保证在所有环境下安装得到稳定的结果。
引入新依赖包
在开发过程中,引入一个新包的流程如下:
npm-install PACKAGE_NAME@VERSION --save
获取特定版本的包- 测试功能
- 在代码仓库中提交 shrinkwrap / package.json 描述
npm install 在运行时会对 package.json 中的依赖做校验,如果你直接修改 package.json 文件,或者是指定了一个非严格的版本号,在运行的时候都会做更新检查,防止遗漏。
值得注意的是,因为 npm-install 会进行依赖对比和校验,在安装新包的时候需要带上 --save
参数。否则,在自动更新 shrinkwrap 描述之前,脚本会自动移除多余的依赖包,导致你新安装的包被删除。
升级依赖包
npm outdated
获取项目所有依赖的更新信息- npm install PACKAGE_NAME@VERSION –save 获取特定版本的包
- 测试功能
- 在代码仓库中提交
shrinkwrap / package.json
描述
package.json 文件中指定了一个非严格的版本号的依赖在运行 npm-install 的时候会做自动更新检查,无需指定版本号,如果你不希望进行自动更新,请在 package.json 中使用严格版本号。
删除依赖包
npm-uninstall PACKAGE_NAME --save
删除这个包- 测试功能
- 在代码仓库中提交 shrinkwrap / package.json 描述
可以看到,在实际使用中没有引入额外的流程,对开发者基本没有学习的负担。但仍然注意,不建议开发者执行 npm update
命令更新所有的依赖。
相关参考
https://docs.npmjs.com/getting-started/using-a-package.json
https://docs.npmjs.com/misc/config
https://docs.npmjs.com/cli/shrinkwrap
这段中的参数是不是应该是–save而不是–dev?
dependencies 列举了当前包/应用的依赖。安装一个包时,添加了参数 –dev,则会将该包添加到当前目录下 package.json 文件中的 dependencies 中。
是的,感谢指正