介绍
本文是 JavaScript 高级深入浅出的第 21 篇,介绍了几种主流的包管理工具
正文
1. 代码共享方案
通过模块化开发,代码可以分为多个小的结构,在以后的开发中我们就可以通过模块化的方式来封装自己的代码,并且封装为一个工具。
通过模块化,我们可以让别人使用现成的解决方案,可以帮助到全世界的程序员。那么现在的问题在于,我们该如何共享自己的代码。
那么你肯定会想到,直接放在代码托管平台,例如 Github、Gitee,那么拉取就会变得很方便。但是这种方式的弊端在哪?升级会非常麻烦,版本控制会非常麻烦,依赖管理会非常麻烦。
方式二,使用一个专门的工具来管理依赖。
- 通过工具将代码发布到线上托管
- 其他人可以通过工具来下载、升级、删除我们发布的代码
显然,方式二肯定是要比方式一要更加方便的。
2. 包管理工具 npm
包管理工具 npm:
- Node Package Manager,也叫做 Node 包管理工具
- 但是目前不仅仅是 Node 的包管理工具了,在前端项目中我们也可以通过 npm 来管理依赖
- 例如 vue、react、koa、axios、babel、webpack、vite 等
使用 npm 需要确保自己的电脑安装了 Node,在 Node 安装过程中会自动安装 npm
npm 依赖查找地址:npmjs.com/
当我们推送一个包时,推送到了 npm 的 registry,下载这个包也是从 registry 下载的
2.1 npm 配置文件
当我们在初始化一个项目的时候,可以使用以下命令来生成一个配置文件(根目录会出现 package.json )。在配置文件中,会说明该项目依赖的包、版本、名称、描述等等。
npm init -y # -y 表示选项默认为 yes,路径出现中文会报错
以下是配置文件中常见的属性:
-
name:项目名称【必填】 -
version:项目版本【必填】 -
description:项目描述信息 -
author:项目作者(发布的时候用) -
license:开源协议(发布的时候用) -
private:项目是否是私有的,当值为 true 时,不可以将该项目发布出去 -
main:项目的入口文件,比如使用import axios from 'axios',就是从main属性查找文件的 -
script:用于配置一些脚本命令,可以通过npm run xxx来执行这个命令- 常用的
start、test、stop、restart在运行时不需要写run,例如:npm start
- 常用的
-
dependencies:放无论是生产环境还是开发环境都需要的依赖 -
devDependencies:放只有开发环境需要的依赖 -
peerDependencies:还有一种依赖关系叫做对等依赖,比如你需要的一个包是需要一个宿主依赖的,例如 ElementPlus 必须依赖 Vue3 -
engines:用于指定 Node 和 npm 的版本,在安装过程中,首先会检测对应的版本,如果不是就会报错- 也可以执行所在的操作系统
"os": ["darwin", "linux"],只是很少用到
- 也可以执行所在的操作系统
-
browserlist:用于配置打包后的浏览器的兼容情况参考,这个属性相当于是给一些打包工具所服务的
2.2 依赖的版本管理
我们会发现安装的依赖版本会是这样的 ^2.0.3 或 ~2.0.3 ,这是什么意思呢?
npm 的包需要遵从 semver 版本规范
- semver:semver.org/lang/zh-CN/
- npm semver:docs.npmjs.com/about-seman…
semver 版本规范为 X.Y.Z
- X 主版本号(major):当你做了不向下兼容的 API 修改,主版本号需要加 1 位
- Y 次版本号(minor):当你做了向下兼容的功能性新增,次版本号需要加 1 位
- Z 修订号(patch):当你做了向下兼容的问题修正,修订号需要加 1 位
- 次版本号改变,修订号重置为 0;主版本号改变,次版本号和修订号重置为 0
^ 和 ~ 的区别:
^:主版本号保持不变,次版本号和修订号安装最新版本~:主版本号和次版本号保持不变,修订号安装最新版本
package-lock.json 里面记录的是每个依赖安装的实际的版本
2.3 安装包
安装 npm 包分为两种情况:
- 全局安装(global install):
npm install @vue/cli -g - 局部安装(local install):
npm install vue
npm install 可以被简写为 npm i ,安装的依赖会存放在 node_modules 文件夹中。
全局安装
全局安装的包会安装在系统环境变量中的NODE_PATH文件夹中,一般我们在全局安装的都是一些工具包,如 vue、webpack 等项目需要的依赖还是要安装在项目中。
局部安装
# 默认 --save 依赖放进 dependencies
npm i vue
# -D 也就是 --save-dev,依赖放进 devDependencies
npm i webpack -D
2.4 npm install 原理
我们知道使用 npm install 指令可以安装一个依赖,但是他背后的原理是什么呢?
- 执行 npm install 后内部帮助我们做了什么操作?
- package-lock.json 又会有什么作用?
- 从 npm5 开始,npm 支持缓存策略,缓存有什么用呢?
解析:
在 npm install 时,需要确定是否有 package-lock.json
- 有 lock 文件
- 检测 lock 包中的版本是否和
package.json中的一致(会根据 semver 版本规范检测)- 如果不一致,就重新构建依赖关系,走顶层的流程
- 一致的情况下,有限去找缓存
- 没有找到,会从 registry 中下载,走顶层的流程
- 找到缓存,获取缓存中的压缩文件,解压到 node_modules 中
- 检测 lock 包中的版本是否和
- 没有 lock 文件
- 分析依赖关系,这是因为我们下载的依赖可能也依赖了其他包
- 从 registry 中下载包(如果设置了镜像,会从镜像服务器中下载)
- 获取压缩包后对压缩包进行缓存(从 npm5 开始有的)
- 将压缩包解压到项目的 node_modules 中
2.5 package-lock.json
以当前 LTS 版本 V8 版本为例
{
"name": "test",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"dependencies": {
"axios": {
"version": "0.26.0",
"resolved": "https://registry.npmmirror.com/axios/-/axios-0.26.0.tgz",
"integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
"requires": {
"follow-redirects": "^1.14.8"
}
},
"follow-redirects": {
"version": "1.14.9",
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.14.9.tgz",
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
}
},
"packages": {}
}
name:项目名称version:项目版本lockfileVersion:lock 文件版本requires:使用 requires 来追踪模块的依赖关系dependencies:项目的依赖version:依赖的实际版本resolved:记录下载的位置,也就是 registry 的位置requires:记录当前模块的依赖integrity:用于从缓存中获取索引,再通过索引获取压缩包文件
packages:包的实际位置映射
具体的属性说明请参考 这里
2.6 npm 常见命令
卸载包
npm uninstall package -g
npm uninstall package -D
npm uninstall package
强制重新构建
npm rebuild
清除缓存
npm cache clean
3. 包管理工具 yarn
yarn 是由 Facebook、Google、Exponent、Tilde 联合推出的 JS 包管理工具,主要是为了弥补 npm 早期的缺陷(如依赖管理混乱、下载速度慢等等)而诞生的。
以下为 npm 与 yarn 的对比
| Npm | Yarn |
|---|---|
| npm install | yarn install |
| npm install [package] | yarn add [package] |
| npm install --save [package] | yarn add [package] |
| npm install --save-dev [package] | yarn add [package] [--dev/-D] |
| npm rebuild | yarn install --force |
| npm uninstall [package] | yarn remove [package] |
| npm uninstall --save-dev [package] | yarn remove [package] |
| npm uninstall --save-optional [package] | yarn remove [package] |
| npm cache clean | yarn cache clean |
| rm -rn node_modules && npm install | yarn upgrade |
yarn 和 npm 不能混用,这是因为 yarn 也有自己的 lock 文件叫做 yarn.lock
4. 包管理工具 cnpm
cnpm 用于解决国内无法正常从 registry.npmjs.org/ 下载包的问题
可以通过 npm config get registry 来查看 registry 的下载地址
使用以下命令来设置国内镜像:
npm config set registry==https://registry.npmmirror.com
也可以来使用此国内镜像深度定制的包管理工具 cnpm
查看这里 获取更多 cnpm 的相关信息
但是要注意:
- 国内镜像并不是实时与 npm registry 更新(据官方说是 10 分钟同步一次)
- 不保证未来国内镜像是否仍然维护
所以一种推荐用法是:
- npm 的 registry 指向官方
- cnpm 的 registry 指向国内镜像
5. 包管理工具 pnpm
pnpm 则是一种新生代的包管理工具,这里是官方文档
为什么我们要使用 pnpm 而不是 yarn 呢?
- pnpm 可以节省磁盘空间
- pnpm 的下载速度更快
- pnpm 不会压平依赖关系树(node_modules 的嵌套关系不会很深)
- 很多大型项目的包管理工具也都切换成了 pnpm,例如 Vue
目前,pnpm 是非常推荐使用的。
另外,pnpm 也有锁文件 pnpm-lock.yaml
点击这里 查看更多使用 pnpm 的使用方法
6. npx
npx 随着 Node 的安装自动安装
npx 是 npm 在 5.2 版本之后自带的一个命令
- npx 的作用非常多,但是比较常见的命令是调用项目中的某个模块的指令
当我们想要使用一个工具时(例如 pnpm),我们想要在命令行中调用 pnpm,就必须要全局安装这个包。那我们该如何调用安装在项目中的某个包的指令呢?
可以在 package.json 的 scripts 中加入
方式一:直接找到文件执行:
./node_modules/.bin/webpack --version
方式二:使用 npm script 执行
{
"scripts": {
"webpack": "webpack --version"
}
}
# 运行 script 优先找 local
npm run webpack
方式三:直接通过 npx 执行
# 或者直接使用 npx
npx webpack
7. 发布自己的包
在发布包的时候要注意一点,package.json 中的 name、version、description、keyword 都是对应在 npmjs.com 上的
在 package.json 中有一个属性 repository,可以填写这个包对应的 url 地址
{
"repository": {
"type": "git",
"url": "your-git-repo-url"
}
}
7.1 登录
需要在命令行登入 npm
npm login
登陆成功后,命令行会出现这个信息
Logged in as your-username on https://registry.npmjs.org/.
7.2 发布
发布前将自己的 package.json 修改为合规的版本
使用以下命令发布自己的包
npm publish
7.3 更新包
- 修改版本号(符合 semver 规范)
- 重新发布
总结
本文介绍了目前主流的几种包管理工具,以及一些细节,希望会对你有所帮助