主题
npm run命令执行过程
1. npm依赖的种类有那些?
在开发中,项目发package.json文件中,常见的或常用的就是开发依赖devDependencies和生产依赖dependencies,分别通过--save-dev 和 --save来进行安装,除了这两种依赖之外,其他还有一些不常用的依赖,例如 同等依赖,打包依赖,可选依赖,等
devDependencies:开发依赖 仅在开发阶段会使用的依赖,打包时候不会被打包,例如一些loader;dependencies:生产依赖 仅在生产环境下需要的依赖,可通过npm install --production来下载所有的生产依赖,例如nuxt上线后,仅仅只需要生产依赖。peerDependencies:同等依赖 可有可无,主要作用是用来在安装时候进行提示用的。例如:bootstrap依赖于jquery,那么,可以在peerDependencies内放入jquery,用户在安装bootstrap的时候,就知道需要安装jquery了;optionalDependencies:可选依赖 可有可无,也是做提示用的。bundledDependencies:捆绑依赖(npm压缩) 主要作用是在npm pack压缩项目时候,指定需要将那些node_modules中的依赖一起压缩,若没有指定任何依赖,则打包后的压缩包内不包含node_modules,bundledDependencies:['dayjs'],其值为数组
使用npm pack 打包tgz时会将捆绑依赖一同打包

npm pack打的压缩包,可以直接解压使用
注意:npm i 在安装依赖的时候只会下载开发依赖和生产依赖,其他的三个依赖不会自动下载
2. .bin目录是干什么的?
在安装好依赖后,node_modules目录下会多出一个.bin目录,这个目录不属于任何的依赖包,也不是依赖项,里面存放的是一些可执行脚本文件,.bin目录的意义意味着你安装的一些模块可以在命令行中执行。
但是,要区分是全局安装还是项目安装,
- 若是全局安装,会在全局的
node_modules目录下的.bin中新增脚本, - 若是项目安装,是在项目的
node_modules下的.bin中新增脚本文件
全局安装的可以直接在命令行执行,项目安装的必须得npm run xxx,且需要配置scripts脚本
为什么呢?
对于全局依赖,由于npm已经在环境变量里面了,所以npm下面的目录可以全局执行(另一篇文章有详细介绍) 对于项目依赖,下面有介绍

3. npm run xxx 时候做了什么?
我们知道,安装到项目的命令依赖不能直接在命令行执行,得通过npm run xxx才能执行,且必须在scripts内先配置相应的脚本启动命令,这是为何呢?
上面说过,项目的node_modules的.bin目录下存放着一堆脚本文件,我们在执行npm run xxx命令的时候,其实就是执行项目的node_modules目录下的.bin中某个xxx脚本,那只需要搞清楚,npm run的时候是咋能找到.bin中的脚本这个问题,就知道npm run xxx的原理了。
3.1 npm run env
首先,我们要知道npm run env这个命令的作用,可以将全局现有的环境变量打印出来,且这个命令不属于某个项目内配置的scripts脚本。


可以看到,运行了npm run xxx命令时,做的事情就是设置环境变量,并且很重要的一点,就是将当前所在目录(global-module)的node_modules下的.bin目录也加入到系统path环境变量下面,这就是为何在npm run xxx命令的时候,.bin目录下面的xxx命令都可以能被找到并执行的原因。
但是,这个这仅仅在npm run时候才生效,当执行完npm run命令后,就会自动从环境变量中删除刚刚添加进去的node_modules下面的.bin这个环境变量,可以直接在命令行运行path来验证,path能打印出当前计算机内的paht内的环境变量;

可以看到,系统内是没有node_modules/.bin这个环境变量了,再执行.bin下面的xxx脚本,就会报xxx不是内部或外部命令,也不是可运行的程序或批处理文件。
npm run去执行一个脚本,若这个脚本对应的包在项目内安装了,就如上面所说,会根据零时环境变量,先找项目的node_modules下的.bin目录内的脚本,若是项目内没有安装,但是全局安装了,那么就会在环境变量中找到全局的node_modules下的`对应包来执行。
3.2 pre 与 post 命令
npm的scripts脚本中, 除了自定义脚本名称外, 还提供了两个前置(pre)与后置(post)钩子命令, 把这俩命令拼接到自定义命令前面, 就可以实现前置或后置钩子指令了,例如:
json
"scripts":{
"predev":"node ./predev.js",
"dev": "vite",
"postdev": "node ./postdev.js",
}这样运行 npm run dev 指令的时候,终端会自动先运行 npm run predev ,再运行 npm run dev ,最后运行 npm run postdev,通过这种方式,我们就可以在自定义脚本运行前,执行一些前置或者后置操作, 比如先对包管理器进行判断, 然后强制开发者使用哪种包管理器。
4. npx xxx
npx命令是npm v5.2之后引入的新命令,npx可以帮我们直接执行node_modules/.bin文件夹下的文件
npx 运行脚本核心原理和 npm 类似,但是npx有一点不一样,就是在执行npx脚本时候,若包不存在,就会先下载,然后通npm一样运行下载的包,等脚本执行完毕又自动删除刚刚下载的包。
- 执行脚本
shell
npx webpack省去了配置scripts脚本
npx避免了安装全局模块 全局安装的模块会带来很多问题,例如:多个用户全局安装的模块版本不同
shell
npx create-react-app react-project我们可以直接使用 npx 来执行模块,它会先进行安装,安装执行后会将下载过的模块删除~,这样可以一直使用最新版本啦~
5. scripts配置
在package.json中可以定义自己的脚本通过npm run来执行
json
"scripts": {
"hello": "echo hello",
"build": "webpack"
}我们可以使用 npm run hello执行脚本,也可以使用 npm run build执行node_modules/.bin目录下的webpack文件
npm run命令执行时,会把./node_modules/.bin/目录添加到执行环境的PATH变量中,因此如果某个命令行包未全局安装,而只安装在了当前项目的node_modules中,通过npm run一样可以调用该命令。- 执行
npm脚本时要传入参数,需要在命令后加--标明, 如npm run hello -- --port 3000可以将--port参数传给hello命令` npm提供了pre和post两种钩子机制,可以定义某个脚本前后的执行脚本,没有定义默认会忽略
json
"scripts": {
"prehello":"echo prehello",
"hello": "echo hello",
"posthello":"echo posthello"
}可以通过打印全局env和 在项目下执行npm run env来对比PATH属性,不难发现在执行npm run 的时候确实会将 ./node_modules/.bin/ 目录添加到PATH中
6. 协议
这张图就说明了为什么MIT许可是最大的了

