基于 npm8。
npm:Node Package Manager,Node 包管理器,目前已经不仅仅作为 Node 的包管理工具,也作为前端的包管理工具来管理包。
npm 管理的包是存放在一个名为 registry 的仓库中的,发布一个包时是发布到 registry 上的,安装一个包时也是从 registry 上下载的。
安装 npm:
安装 Node 的过程中就会自动安装 npm 工具。
使用 npm:
-
进入目标文件夹。
-
在命令行中输入
npm install packagename
安装包。如果目标文件夹下有node_modules
目录,会自动将代码下载到node_modules
目录下;如果没有,那么会自动新建node_modules
目录并且将代码下载到node_modules
目录下。
-
通过 ES Module 中的 import 关键字和 CommonJS 中的
require()
函数引入时,会自动去node_modules
目录下查找指定的包,找到之后就可以在代码中使用了。
npm 管理的包的版本:
npm 管理的包通常都会遵循 semver 版本规范。semver 的版本规范 X.Y.Z
。
- X:major,主版本号。重大的版本更新,不兼容之前的版本。
- Y:minor,次版本号。新功能增加,但是兼容之前的版本。
- Z:patch,修订号。没有新功能,修复了之前版本的 bug。
X.Y.Z
:表示一个明确的版本号。
^X.Y.Z
:表示 X 保持不变,Y 和 Z 永远安装最新的版本。
~X.Y.Z
:表示 X 和 Y 保持不变,Z 永远安装最新的版本。
npm 的常用命令:
npm init
:
npm init
:创建 package.json
配置文件。
npm install
:
第一次
npm install
的时候会生成package-lock.json
,用于锁定依赖。
npm install
:通过 npm 安装包。可以分为两种:
-
npm install packagename -g
:全局安装。将包安装到操作系统,会自动将包下载安装到 node 管理的一个目录下,这个包会被自动添加到环境变量中。安装之后,可以在命令行中直接运行该包相关的命令。
一般用来安装工具类的包,也就是会直接在命令行中使用到相关的命令的包,例如:webpack、yarn 等。
将任何可执行程序下载安装到电脑中,并且将其添加到电脑的环境变量中,就都可以在命令行中直接运行。
-
npm install packagename
:局部安装。将包安装到当前目录下,会自动将包下载到当前文件夹的node_modules
目录下。安装之后,可以在项目中引入使用。
一般用来安装会在项目中引入使用的包,例如:react、axios 等。
局部安装又分为开发时依赖和生产时依赖。
npm install
安装开发时依赖和生产时依赖,npm install --save-dev
安装开发时依赖。直接运行
npm install
会根据package.json
中的依赖包进行下载。
npm install
安装指定版本:
如果想要安装包的指定版本,需要在包名后面使用@
连接版本号,packagename@版本号
。
使用别名在一个项目中安装同一个包的不同版本:
使用 别名@npm:packagename@版本号
。
以 Vue 为例:
npm install vue2@npm:vue@^2.6.14
npm install vue3@npm:vue@^3.2.37
安装完成后可以看到 package.json
有两个 Vue 的包。
// package.json
{
"dependencies": {
"vue2": "npm:vue@^2.6.14",
"vue3": "npm:vue@^3.2.37"
}
}
npm install
的原理:
npm install
会检测是否有 package-lock.json
文件:
- 如果没有
package-lock.json
文件,那么:- 分析、构建依赖关系:因为引入的包可能会依赖其他包,并且多个包之间可能会产生相同的依赖。
- 从 registry 仓库中下载压缩包。
- 对下载到的压缩包进行缓存,并生成
package-lock.json
文件。 - 将压缩包解压到项目的
node_modules
文件夹下。
- 如果有
package-lock.json
文件,那么:- 根据 semver 版本规范检测
package-lock.json
中包的版本是否和package.json
中的一致:- 如果一致的话,优先去查找缓存。找到的话,会获取缓存中的压缩文件,并且将压缩文件解压到
node_modules
文件夹中;如果没有找到的话,走步骤 1 的流程。 - 如果不一致的话,直接走步骤 1 的流程。
- 如果一致的话,优先去查找缓存。找到的话,会获取缓存中的压缩文件,并且将压缩文件解压到
- 根据 semver 版本规范检测
npm uninstall
:
npm uninstall
:卸载安装的某个包。
npm cache clean
:
npm cache clean
:清除 npm 缓存文件夹中的包。
可以通过
npm config get cache
来查看 npm 缓存文件夹的路径。
npm publish
:
npm publish
:通过 npm 发布包。
如果想要更新发布出去的包:需要先修改版本号,然后重新运行
npm publish
。
- 注册 npm 账号:在
https://www.npmjs.com/
中点击Sign Up
注册一个 npm 账号。 - 登录:在命令行工具中进入要发布的包的目录下,运行
npm login
,输入登录信息进行登录。
- 发布:运行
npm publish
即可发布出去。
npm unpublish
:
npm unpublish
:删除发布出去的包:
npm deprecate
:
npm deprecate
:让发布出去的包过期。仍然可以下载,只是会提醒已经过期。
npm run <cmd>
:
npm run <cmd>
:运行某个脚本命令。
package.json
配置文件:
运行 npm init
命令就会生成 package.json
配置文件,是一个记录着包的名称、版本号、描述、依赖的包等信息 JSON 对象。
项目中如果使用到 npm 的话,都需要创建一个配置文件。
npm init
:创建配置文件时需要手动填写信息。
npm init -y
:创建配置文件时使用默认信息。
package.json
配置文件中的常见字段:
-
name:包的名称。必填。
-
version:包的版本号。必填。
-
description:包的描述信息。
-
keywords:包的关键字。其他人可以通过关键字搜索到对应的包。
-
author:作者(项目开源发布时使用)。
-
license:开源协议(项目开源发布时使用)。
-
private:记录当前包是否是私有的。当属性值为 true 时,npm 是无法发布该包的,这是为了防止私有的包被发布出去。
-
main:指定包的入口文件。
例如:项目引用了一个叫 custom 的包,入口文件是
main.js
,存放的目录为node_modules/custom/main.js
;在index.js
中通过const custom = require('custom') 将其引入
。
问题:默认情况下,require('custom')
会去查找node_modules/custom
下的index.js
文件的,但这个包的入口文件是main.js
,此时找不到会导致报错。
解决方法:可以在node_modules/custom
下运行一次npm init
生成一个配置文件,其中配置"main: "main.js"
指定包的入口文件即可解决。 -
scripts:用于配置一些脚本命令,以 key/value 的形式。配置后就可以通过
npm run key命令
来运行后面配置的 value 脚本。value 脚本中的命令,会先去当前目录的
node_modules/.bin
下查找是否有对应的程序,如果有的话,就用它运行;没有的话,才去环境变量中查找。npm start
和npm run start
其实是等价的。对于常用的 start、stop、restart、test 等,npm 允许省略掉 run 直接运行。在
"scripts"
里配置"start": "node index.js"
,运行node index.js
和运行npm run start
,效果是一样的。 -
dependencies:指定无论是开发环境还是生产环境都依赖的包。也就是,运行
npm install
安装的包会被记录在 dependencies 字段中。例如:Vue、React、axios 等。运行
npm install
,npm 就会根据package.json
中的 dependencies 字段将其中包含的包都下载到node_modules
文件夹下。
因此,如果需要将项目共享给其他人时,不需要给出node_modules
文件夹,node_modules
文件夹中包的名称及其版本号都被记录在了package.json
中,其他人只需要运行npm install
即可将其都下载下来。 -
devDependencies:只在开发环境中依赖的包。也就是,运行
npm install --save-dev
安装的包会被记录在 devDependencies 字段中。例如:Webpack、babel 等。 -
peerDependencies:指定对等依赖的包,也就是依赖的一个包,必须是以另外一个包为前提的。例如:
element-plus
是依赖 Vue3 的,ant design
是依赖 react、react-dom
的。
可以看到,在element-plus
的package.json
配置文件的 peerDependencies 中指定了 Vue3。
package-lock.json
文件:
例如:下载了 A 依赖的 v1.0.0 版本, 同时 A 依赖又依赖 B 依赖的 v1.3.2 版本和 C 依赖的 v2.0.3 版本。
packag.json
中只单纯记录本项目的依赖, 而没有记录依赖的依赖;并且依赖之间的版本号也没有明确固定, 导致无法保证依赖环境一致,其他人下载的时候可能会出现以下情况:
- A 依赖的下载的版本为
1.最新版.最新版
, 导致项目出现 bug。 - A 依赖所依赖的 B 依赖和 C 依赖下载了别的版本, 导致 A 依赖出现 bug,进而导致项目出现 bug。
package-lock.json
的出现解决了上述问题。
package-lock.json
文件是 npm 自动生成和维护的。主要作用是:锁定安装时的包的版本号及包依赖包的版本号,以保证所有人在使用 npm install
时下载的依赖包都是一致的;而且会记录包缓存所在位置的标识符,用来查找缓存。
package-lock.json
文件中的常见字段:
-
name:包的名称。
-
version:包的版本。
-
lockfileVersion:lock 文件的版本。
-
requires:是否使用 requires 来跟踪包的依赖关系。
-
dependencies:依赖的包。
依赖的包的常见字段有:
- version:实际安装的版本。
- resolved:在 registry 远程仓库中的位置。
- requires/dependencies:当前包的依赖。
requires 和 dependencies 这两个字段作用是一样的。
- integrity:通过 sha512 算法生成的一个标识符,解析后会生成该包所在缓存的位置。
安装包时会先去缓存中查找,找不到的话才会去 registry 远程仓库中去下载。
下载包时会优先下载在缓存中,integrity 的值也会被更新。
npx:
在某个目录的终端下运行某个命令,会先在当前目录下查找是否有该程序,找到的话就用它运行;如果找不到的话,会去环境变量中查找。
webpack 是例外。webpack 会在当前目录及子目录下查找是否有该程序,都找不到的话,才去环境变量中查找。
例如:通过 npm install yarn -g
全局安装最新版的 yarn,在 npm-demo
目录下通过 npm install yarn@1.0.0
局部安装 1.0.0
版本的 yarn。在某个任意目录的终端下运行 yarn -v
,会输出 1.22.10
;在 npm-demo
目录的终端下运行 yarn -v
,也会输出 1.22.10
。这是因为,在 npm-demo
目录下通过 npm install yarn@1.0.0
局部安装的 1.0.0
版本的 yarn,实际安装的目录是 node_modules/.bin/yarn
,因此在 npm-demo
目录下找不到 yarn,会去环境变量中查找,找到的就是最新版的 yarn。而如果想要找到 1.0.0
版本的 yarn ,需要运行 ./node_modules/.bin/yarn -v
,这个写法繁琐易错。
npx 的出现就是为了解决这个问题。npx 是 npm5.2.0 版本自带的一个命令。npx 会在当前目录下的 ./node_modules/.bin
里去查找是否有可执行的命令,没有找到的话再从全局里查找是否有安装对应的模块,全局也没有的话就会自动下载对应的模块。
因此,运行 npx yarn -v
,就相当于是在运行 ./node_modules/.bin/yarn -v
。
node_modules/.bin
文件夹下存放的是当前项目环境下的可执行文件。