背景
在node出现之前,前端的模块文件引用都是通过手动下载到本地,当一个网站依赖的代码越来越多,程序员发现这是一件很麻烦的事情。
去 jQuery 官网下载 jQuery
去 BootStrap 官网下载 BootStrap
去 Underscore 官网下载 Underscore
……
有些程序员就受不鸟了 一个超级大神程序员 Isaac Z. Schlueter (以下简称 Isaaz)给出一个解决方案:用一个工具把这些代码集中到一起来管理吧!
这个工具就是npm,全称为 Node Package Manager,是一个基于 Node.js 的包管理器,也是 Node.js 社区最流行、支持的第三方模块最多的包管理器。
npm 最初只是Node.js 的包管理器,但随着前端技术的不断发展,它的定位变成了广义的包管理器,可以实现JavaScript、React、Vue、移动开发等包管理,是目前最大、生态最为健全的包管理器。
使用
npm 不需要单独安装,在安装 Node.js 时,就会连带着一起安装 npm 了。但是安装的 npm 不一定是最新的版本,可以使用以下命令来查看本地 npm 的版本:
npm -v
这里的 -v 是 --version 的缩写,表示版本。如果想升级 npm 版本,可以使用以下命令:
npm install npm@latest -g
这里@latest表示最新的版本,-g 是 --global 的缩写,表示全局安装。
除此之外,还可以使用help命令来查看npm帮助:
npm 命令 --help
比如查看 install 的参数形式:
npm install --help
其中--help可以简写为-h,上面命令的执行结果如下,可以看到install命令的很多形式: 常见的npm命令:
命令 | 作用 |
---|---|
npm -v | 查看 npm 版本。 |
npm init | 初始化后会出现一个 package.json 配置文件。可以在后面加上 -y ,快速跳过问答式界面。 |
npm install | 根据项目中的 package.json 文件自动下载项目所需的全部依赖。 |
npm install 包名 --save-dev(npm install 包名 -D) | 安装的包只用于开发环境,不用于生产环境,会出现在 package.json 文件中的 devDependencies 属性中。 |
npm install 包名 --save(npm install 包名 -S) | 安装的包需要发布到生产环境的,会出现在 package.json 文件中的 dependencies 属性中。 |
npm list | 查看当前目录下已安装的 node 包。 |
npm list -g | 查看全局已经安装过的 node 包。 |
npm --help | 查看 npm 帮助命令。 |
npm update 包名 | 更新指定包。 |
npm uninstall 包名 | 卸载指定包。 |
npm config list | 查看配置信息。 |
npm 指定命令 --help | 查看指定命令的帮助。 |
npm info 指定包名 | 查看远程 npm 上指定包的所有版本信息。 |
npm config set registry registry.npm.taobao.org | 修改包下载源,这里修改为了淘宝镜像。 |
npm root | 查看当前包的安装路径。 |
npm root -g | 查看全局的包的安装路径。 |
npm ls 包名 | 查看本地安装的指定包及版本信息,没有显示 empty。 |
npm ls 包名 -g | 查看全局安装的指定包及版本信息,没有显示 empty。 |
说完这些概念,下面就来看看 npm 在使用时有哪些实用的技巧。
2. 快速了解 package
一个npm项目里面有
文件 | 说明 |
---|---|
./node_modules | npm 包存放的文件夹。 |
package.json | npm 的 package。 |
package-lock.json | npm 锁定文件的说明。 |
.npmrc | npm 配置文件 |
凡是使用npm管理的项目,都需要初始化一个package.json文件。
可以使用以下命令来初始化一个包:
npm init
version
表明了当前的版本。name
设置了应用程序/软件包的名称。description
是应用程序/软件包的简短描述。main
设置了应用程序的入口点。private
如果设置为true
,则可以防止应用程序/软件包被意外地发布到npm
。scripts
定义了一组可以运行的 node 脚本。dependencies
设置了作为依赖安装的npm
软件包的列表。devDependencies
设置了作为开发依赖安装的npm
软件包的列表。engines
设置了此软件包/应用程序在哪个版本的 Node.js 上运行。browserslist
用于告知要支持哪些浏览器(及其版本)
这里对package文件不做过多描述,重点讲解2个小知识点。
package.json中的前缀^符号
~符号
*符号
代表了对包安装版本的不同策略
^符号
的意思: 版本号中最左边的非0数字的右侧都用最新的版本数- 例如: package.json中包版本为
^2.1.0
, 则下次会下载的版本为2.6.14 (2.最新.最新) - 例如: package.json中包版本为
^0.7.1
, 则下次会下载的版本为0.7.6 (0.7.最新)
- 例如: package.json中包版本为
~符号
的意思:Major
永远准确安装,Minor
给出的则准确安装否则装最新,Revision
永远装最新- 例如: package.json中包版本为
~2.0.3
, 则下次会下载的版本为2.0.8 (2.0.最新) - 例如: package.json中包版本为
~0
, 则下次会下载的版本为0.12.16 (0.最新.最新)
- 例如: package.json中包版本为
*符号
的意思: 直接下载这个包的最新版本- 例如: package.json中包版本为
*
, 则下次会下载的版本为2.6.14 (vue2的最新版)
- 例如: package.json中包版本为
package-lock.json
npm 的依赖版本管理非常宽松,同一个项目一天之内可能会 install 到不同版本的依赖,依赖包的升级有可能会给你的项目带来 bug。
场景:比如你的packgae.json的依赖是"react": "^17.0.2",因为有标识符^,所以如果react模块有在17大版本下更新的小版本17.0.3,npm install时候会自动安装17下的最新版本17.0.3
在场景情况下,你本地是"react": "^17.0.2",如果这时候react更新"react": "^17.0.3",别人npm install的时候,安装就是"react": "^17.0.3"。这样导致你们版本不一致,可能引起一些相关错误。
packagelock.json
用以锁定版本号,保证开发环境与生产环境的一致性,避免出现不兼容 API 导致生产环境报错。
建议项目需要提交lock文件,保证多人版本正确
3. 安装依赖 (install)
可以使用npm install命令来安装需要的包,如果想把这个包自动添加到package.json中,可以执行以下命令,这里以安装React为例:
npm install react --save
如果想要安装不同版本的包,可以这样:
// 安装最新版本
npm install react@latest
// 安装指定版本
npm install react@16.8.0
// 安装指定区间版本
npm install react@">=16.8.0 <17.0.1"
.
当使用npm安装依赖时,分为本地安装(local)和全局安装(global),它俩的区别就是是否包含-g参数:
命令 | 简写 | 说明 |
---|---|---|
无 | 无 | 将模块安装到本地node_modules目录下,但不保存在package.json中。 |
--save | -S | 将模块安装到本地node_modules目录下,同时保存到package.json中的dependencies配置项中,在生产环境下这个包的依赖依然存在。 |
--sava-dev | -D | 将模块安装到本地node_modules目录下,同时保存到package.json中的devDependencies配置项中,仅供开发时使用。 |
--global | -g | 安装的模块为全局模块,如果命令行模块,会直接链接到环境变量中。 |
需要注意,在执行npm install命令时,npm 5 之前只会下载,不会保存依赖信息。如果需要保存,就需要加上 --save 选项, npm 5 以后就可以省略 --save 选项了,它会自动保存。
执行完该命令之后,就会把^符号改为~符号。当再次安装新模块时,就从只允许小版本的升级变成了只允许补丁包的升级。
npm install 的 模块安装机制
简单来说: 确定首层依赖 --- 构建依赖树 --- 依赖树扁平化 --- 下载 先会通过压缩包地址去判断是否在缓存中存在该版本模块,如果有,就直接拿过来,如果没有,就回去远程仓库下载,下载完后放入缓存,并解压放到node_modules目录中,最后会去新增或者更新lock文件。
4. 安装依赖(CI )
npm ci
此命令类似于npm-install
,但它更适合用于生产和自动化环境,如测试平台,持续集成和部署。当它安装依赖时,默认是缓存优先的,它会充分利用缓存,从而加速装包。
总之,使用npm install
和使用的主要区别npm ci
是:
- 该项目必须有一个package-lock.json。
- 如果程序包锁中的依赖项与其中的依赖项不匹配
package.json
,npm ci
则将退出并显示错误,而不是更新程序包锁。 npm ci
只能一次安装整个项目:使用此命令无法添加单个依赖项。- 如果
node_modules
已经存在,它将在npm ci
开始安装之前自动删除。 - 它永远不会写入
package.json
或任何包锁:安装基本上是冻结的。
5. 搜索依赖
npm 为我们提供了search 命令,用于搜索npm仓库,它搜索的参数可以是一个字符串,也可以是一个正则表达式:
npm search react
搜索结果如下: 当然,我们也可以去node.js官网去找:www.npmjs.com/
想要找到一个合适的依赖包可能并不是一件容易的事。这时,可以使用网站npms.io/,这里将各个包的质量、受欢迎度、可维护性等指标做了量化。这些指标包括:是否使用了过时的依赖包、是否有代码检查配置、是否经过测试以及最近的版本是何时发布的等。
6. 更新、卸载依赖
npm 为我们提供了更新依赖版本的命令:
npm update [package name]
如果想要更新全局安装的模块,需要添加参数 -global:
npm update -global [package name]
当执行这两个命令时,它会先到远程仓库查询最新版本,然后查询本地版本。如果本地版本不存在,或者远程版本较新,就会安装。
如果想要更新该依赖包在package.json中的版本,就需要使用-S或者--save参数。需要注意的是,从npm v2.6.1 开始,npm update只会更新顶层的模块,而不更新依赖的依赖模块,而之前的版本是递归更新的。如果想要这种效果,可以使用以下命令:
npm --depth 9999 update
除了可以更新包之外,还可以删除指定的包:
npm uninstall [package name]
如果想要删除全局的包,需要添加参数 -global:
npm uninstall [package name] -global
7. 查找过时的包
npm 提供了一个命令来查看过时的依赖:
npm outdated
在我的项目中执行该命令,输出结果如下: 可以看到,这里列出了过时依赖的包名称、当前的版本、希望的版本、最新的版本、依赖在本地路径、依赖这个包的项目名称。
可以通过以下命令来检查npm包的最新版本:
// 展示包的信息
npm view <package-name>
npm v <package-name>
// 展示最新版本
npm v <package-name> version
// 展示所有版本
npm v <package-name> versions
8. 执行脚本
npm 不仅可以用于管理模块,还可以用于执行脚本。在package.json文件中有一个scripts字段,可以用于定义脚本命令,比如:
- 运行代码检查(linter)工具
- 配置环境变量
- 执行测试
- 本地启动项目
- 构建项目
- 精简(minify/uglify)JS 和 CSS
我们除了可以在package.json文件中查看有哪些命令,也可以使用以下命令来查看所有脚本命令:
npm run
我的项目中执行该命令之后的结果如下: 可以看到,这里定义了dev、build、build:test等命令,如果需要执行这些命令,只要这样执行即可:
npm run dev
npm run build
npm run xx && npm run xx 可以串行 // 比如做本地代码eslint 检测后+build 之类的
.
这里不在多说,这或许是我们平时用的最多的命令了,可以根据实际开发情况,来定制自己的npm命令。
9. 删除重复的包
我们可以通过运行npm dedupe命令来删除重复的依赖项。该命令通过删除重复包并在多个依赖包之间共享公共依赖项来简化整体的结构。它会产生一个扁平的、去重的树。
npm dedupe
npm ddp
10. 扫描漏洞
可以运行 npm audit 命令来扫描项目,来查找所有依赖项中存在的漏洞:
npm audit
来看我的项目扫描结果: 可以运行以下命令来自动安装所有易受攻击包的补丁版本:
npm audit fix
11. 列举已安装的包
可以通过以下命令来获取整个项目的包信息:
npm list
npm list命令以树型结构列出当前项目安装的所有模块,以及它们依赖的模块。 如果加上global参数,就会列出全局安装的模块:
npm list -global
也可以查看指定包的依赖,比如在我现在做的项目下,执行以下命令:
npm list react
还可以使用npm ls 命令来查看指定包的依赖信息:
npm ls react
可以使用--depth参数来限制搜索的深度:
12. 测试本地包
当我们在本地开发npm模块时,可以使用npm link命令来将本地的npm模块连接到对用的项目中去,便于对模块进行调试和测试。使用方式也很简单,在项目中执行以下命令:
npm link
执行完该命令之后,就会为这个npm包创建到全局,路径是 {prefix}/lib/node_modules/<package>
,它是一个快捷方式。之后我们就可以使用以下命令来在需要这个模块的项目中链接这个包:
npm link 模块名
这里的模块名就是依赖包的名称,也就是模块包的package.json文件中的name字段值。
如果不想继续使用了,执行以下命令来解除link即可:
npm unlink 模块名