前言
Hello 大家好!我是壹甲壹!
对于平常只会用到简单的 npm 命令的我来说,面试的时候就被考官按在地上摩擦过
- 请问
package.json中版本~1.2.3和^1.2.3有什么区别? - 请问执行
npm install时,是怎么安装依赖包的?相同的依赖包怎么处理?
面试结果可想而知,于是便有了这篇文章,好好总结下 npm 相关的知识啦
一、npm 安装
当我们在安装 node 后,npm 也会一起安装好,此时需要另外两个包来协助开发
nvm管理 node 版本nrm管理 npm 的源,国内一般都使用taobao或cnpm源
详细安装信息,请参考 Node.js的3m安装法
二、npm 命令
2.1 npm init
npm init 命令用来初始化项目
- 直接执行
npm init, 会依次询问name, version, description等配置信息,比较麻烦 - 添加
--yes或-y后缀,直接生成package.json文件,配置信息使用默认值 (默认值在npm config中定义), 可手动修改
对于每个项目而言,例如 author.name , author.email 都是固定的,可以给这些字段设置默认值
// 查看所有配置信息
npm config list --json
// 设置默认值
npm config set init.author.name "userName"
npm config set init.author.email "userEmail"
接下来,执行 npm init -y, 生成的 package.json 文件如下
{
"name": "pkg-a",
"version": "1.0.0",
"description": "",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "userName <userEmail>",
"license": "ISC"
}
2.2 npm install
npm install 命令用来全局安装或本地安装第三方的依赖。npm install 简写为 npm i
2.2.1 global
npm i create-react-app -g 会进行全局安装,安装成功后,可在终端任何地方使用 create-react-app 命令。
- 全局安装路径
执行 npm root -g 输出全局安装路径为
/Users/xxx/.nvm/versions/node/v14.2.0/lib/node_modules
(Tip: 此时可以看出 nvm 管理node 版本时,每个版本都有对于的 node_modules )
- 全局使用
之所以能够全局使用,是因为将 xxx/v14.2.0/lib/node_modules 目录下每个依赖的可执行文件软链接 到 xxx/v14.2.0/bin 目录下。
每个依赖包的可执行文件在其 package.json 文件中的 bin 字段指定
{
"name": "create-react-app",
"bin": {
"create-react-app": "index.js"
}
}
那么,在 xxx/v14.2.0/bin 目录就会创建 create-react-app 命令,在执行该命令时,就是在执行 index.js 文件
2.2.2 local
npm i moment --save 会在当前项目进行安装,安装成功后,需要在项目中引入后,才能使用
依赖来源
npm i 默认会从 npm registry 上去下载依赖的模块 (使用 nrm 切换),除此之外,还有哪些安装途径呢?
- from folder
可以从本地的文件夹中安装 pkg。本地创建
pkg-a文件夹,并通过npm init -y进行初始化,接下来执行npm i ~/pkg-a就可以安装了,成功之后pkg-a的值为相对链接的 file 协议地址
- from tarball
对于👆的本地模块
pkg-a, 执行npm pack命令就可对其打包了接下来,就可以执行
npm i ~/pkg-a/pkg-a-1.0.0.tgz安装模块了,安装成功后pkg-a的值为相对链接的 file 协议地址
npm install tarball 比较适合离线安装包或者包不想发布的 npm 源上,但需要手动维护
- from http(s) url
前面介绍的是本地包,对于已经发布的依赖,例如
react,使用npm view react可以查看最新版本的 react 压缩包地址
此时可以直接使用
npm install [https://r.cnpmjs.org/react/download/react-16.13.1.tgz](https://r.cnpmjs.org/react/download/react-16.13.1.tgz) 来安装 react。安装完成后,在 package.json 中 react 值为 https 地址
npm install http(s) 比较适合不想发布的 npm 源上,但需要别人也能安装
- from git
我们还可以从 git 上安装,还以 react为例,执行 npm i [https://github.com/facebook/react.git](https://github.com/facebook/react.git) 来安装
以上就是其它的几种 npm install 方式,在日常开发中还是推荐从 npm 源上面安装依赖
依赖分类
对于不同的依赖功能不同,常见会将依赖分成 开发环境依赖 和 生产环境依赖,例如 babel 属于开发依赖,而react 就属于生产依赖了。在 npm install 时可以添加不同的后缀来区分依赖,--save (-S) 表示生产依赖,下载的依赖会保存到 package.json 的 dependencies 字段中,而 --save-dev (-D) 表示开发依赖,会保存到 devDependencies 字段中。
在 npm5 中,不添加后缀,下载的依赖默认会保存到 dependencies
除去 -S -D后缀,npm install 还存在以下后缀
-P:--save-prod, 当保存到dependencies字段中, 当不存在-D或-O时,-P就是默认值-O:--save-optional, 保存到optionalDependencies字段中--no-save, 将不会进行保存-B:--save-bundle, 不仅保存到dependencies字段,还会保存到bundleDependencies列表中 (可选)-E:--save-exact, 不仅保存到dependencies字段,还会锁定pkg的准确版本,而不是使用一个范围 不加-E,版本^16.13.1是一个范围,表示的是>=16.13.1 < 17.0.0这个范围加上
-E, 就会锁定react的版本
(Tips: 关于 dependencies 这些字段,以及 ^16.13.1表示的具体版本范围,后续 package.json 中会讲解)
安装位置
本地安装是,所有的依赖都会放到 ./node_module/ 文件夹下面,同时每个依赖的可执行文件都会软链接到 ./node_module/bin/ 目录下,这样就可以在 package.json 中设置 script 时使用到这些命令,如
2.2.3 How to Work?
当仅执行 npm install 时,npm 会根据 package.json 来安装项目依赖,到底是如何工作的呢?
这部分请参考 npm install 如何工作 - node_modules 目录结构
总结如下,若想实践,可通过下面 Tips来切换 npm 版本
- **npm 2 ** 递归安装依赖
缺点:重复安装相同版本的依赖包
Tips: 执行 nvm install 4.2.0 后,node 版本 4.2.0 ,npm 版本 2.14.7
- npm 3 扁平化管理, 在安装时遍历整个依赖树,计算出最合理的文件夹安装方式, 避免重复安装
Tips: 执行 nvm install 6.9.0 后,node 版本 6.9.0 ,npm 版本 3.10.8
- npm 5
增加 package-lock.json 文件, 锁定依赖版本,确保任何环境运行 npm install 得到相同的 node_modules 结 构。禁用命令 npm config set package-lock false
2.3 npm view(info)
npm view(info) xxx ,查看包 xxx 的一些信息,最新稳定版本,在线压缩包地址,依赖等信息。
2.4 npm home(docs)
npm home(docs) xxx ,都会打开在线 github 地址,前提需要在包 xxx 的 package.json 文件中设置 homepage 字段
2.5 npm repo(bugs)
npm repo(bugs) xxx, 跳转到对应的 github repo页面,前言也是需要配置
2.6 npm ls
显示依赖 tree
三、package.json
一个项目的全部信息都在 package.json 文件中了,具体看下有哪些属性吧
3.1 必备属性
如果该项目打包发布到 npm 源上,那么 name 和 version 两个字段是必须的
3.2 version
版本号必须能够被 node-semver 正确解析。
3.2.1 版本号
标准版本号格式为: X.Y.Z , 有下面几点说明
- X.Y.Z 均为非负整数,X: 主版本号、Y:此版本号、Z:修订号。每个元素依次递增
- 任何修改都要用新的版本号发布
- 当 X 为 0 时(0.y.z),此时属于开发初期,任务公共API 都可能改变,属于非稳定期。1.0.0 用于界定公共 API 的形成
- 修改 Z, 必须在做了向下兼容的修正时才递增,例如 修复 bug
- 修改 Y, 必须在有向下兼容的新功能时才递增,当 Y 修改后,Z 必须归 0
- 修改 X, 必须在有任何不兼容的修改被加入公共 API 时递增,当 X 修改后, Y, Z 必须归 0
**
3.2.2 预发版本号
eg: 2.1.0-beta.1
- alpha(α):预览版,或者叫内部测试版
- beta(β):测试版,或者叫公开测试版
- rc(release candidate):最终测试版本
预发版本表明当前版本并非稳定,可能不符合要求。
3.2.3 版本号优先级
版本优先级也就是指版本的高低
- 首先记住
2.1.0-beta的优先级低于2.1.0,先有预发,再有稳定; - 对于正常版本格式
X.Y.Z,都是数值,比较每一位大小就OK; - 而对于预发版本,有数字比数值大小,非数字比较每个字符的 ASCII 大小;
所以: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0
3.2.4 范围版本号
(1)运算符:> , >=, <, <=
- 正常:
>= 1.2.7, 那么匹配的版本可以是1.2.7,1.2.8,3.4.2 - 预发:
>1.2.3-alpha.3,那么匹配的版本的X.Y.Z必须是1.2.3
(2)字符范围:X.Y.Z - A.B.C
1.2.3 - 2.3.4, 那么匹配的版本范围是>=1.2.3 <=2.3.41.2 - 2.3.4,第一个版本缺失,会进行补零,所以匹配的版本范围是>=1.2.0 <=2.3.41.2.3 - 2.3,第二个版本缺失,会要求匹配的版本的X.Y两位不得大于 2.3,也就是< 2.4.0, 所以版本范围是>=1.2.3 <2.4.0,
(3)X-Range: 1.2.X , 1.2.x, 1.2.*
*, 匹配任意版本,也就是>= 0.0.01.2.x,匹配的版本 X.Y 两位不变,所以版本范围是>=1.2.0 < 1.3.01.x,匹配的版本 X 位不变,所以版本范围是>=1.0.0 < 2.0.0
(4)Tilde Ranges : ~
如果Y被指定,则允许Z被改变;如果没有,允许Y被改变
~1.2.3,Y被指定为 2, 那么匹配的范围为>=1.2.3 <1.3.0~1.2,Y被指定为 2, 那么匹配的范围为>=1.2.0 <1.3.0~1, 没有指定 Y, 那么 Y 可以被改变,匹配的范围为>1.0.0 <2.0.0
(5)Garet Range: ^
匹配的版本,会保证最左边的第一个非 0 位不修改
^1.2.3, 最左边非 0 位为 X 位,所以匹配的范围为>=1.2.3 <2.0.0^0.2.3, 最左边非 0 位为 Y 位,所以匹配的范围为>=0.2.3 <0.3.0^1.2.x, 当版本缺失,缺失位会降到 0 ,所以匹配的范围位>=1.2.0 <2.0.0
3.3 dependency
3.3.1 dependencies
生产环境依赖,对应 npm install 时后缀 -S
3.3.2 devDependencies
开发环境依赖,对应 npm install 时后缀 -D
3.3.3 peerDependencies
同等依赖,如果安装了依赖包 pkg-a, 最好也安装下 pkg-a 对应的依赖
// pkg-a package.json
{
"peerDependencies": {
"jquery": "2.2.0"
}
}
上面表示 pkg-a 的运行依赖于 jquery,所以当 npm install pkg-a 时,控制台会提示以下信息
在 npm 2.x 版本时,peerDependencies 会被强制安装,3.0 版本后不被强制安装
3.3.4 bundleDependencies
捆绑依赖, 也叫 bundledDependencies,属性值是个数组
// pkg-a package.json
{
"bundledDependencies": [
"moment"
]
}
当 npm pack 时会将捆绑依赖一同打包,在安装 tgz 压缩包时,捆绑依赖也会被安装。但注意捆绑依赖并没有指定版本号
3.3.5 optionalDependencies
可选依赖,属性值为对象。当项目依赖 pkg A, 但 pkgA 安装失败或者找不到并不会影响项目的运行,就可以在 optionalDe.... 中指定 pkgA 了
3.4 homepage
指定项目主页,设置后可通过 npm docs(info) xxx 打开
3.5 bugs
指定项目 issues 页面, 设置后通过 npm bugs xxx 可打开
3.6 license
3.7 main
指定项目入口文件,当 require(xxx) 时,返回的就是入口文件导出的内容
3.8 bin
当 pkg 中的可执行文件需要安装到 PATH 中,可在 bin 中指定。以 http-server 为例
"bin": {
"http-server": "./bin/http-server",
"hs": "./bin/http-server"
}
当 http-server 全局安装,会将执行文件软连接到 xxx/node/v14.2.0/bin/http-server 中,本地安装就会链接到 ./node_module/bin/http-server 中。
可执行文件需要在文件顶部增加 #!/usr/bin/env node 指定 node 执行
3.9 config
设置 config 可通过 npm_package_config_xxx 来获取,但同名变量会被本地 npm config 所覆盖
3.10 script
这部分请参考 阮一峰 npm scripts 使用指南
四、npx
npx 命令是 npm v5.2 之后引入的新命令,npx 可以帮我们直接执行 node_modules/.bin文件夹下的文件
- 执行脚本
npx webpack
这样就省略了配置scripts脚本
- 避免安装全局模块
全局安装的模块会带来很多问题,例如:多个用户全局安装的模块版本不同
npx create-react-app react-project
我们可以直接使用 npx 来执行模块,它会先进行安装,安装执行后会将下载过的模块删除,这样可以一直使
最新版本
五、npm 发布
npm 包的发布比较简单
- 首先使用 nrm 切换到 npm 官方源
- 使用
npm login进行登录(提前注册) npm publish(确保 name 是唯一值)- 对于不想打包的可在
.npmignore文件中进行忽略
六、参考链接
本文使用 mdnice 排版