一、npm run serve时发生了什么?灵魂5问
1、npm run xxx 的时候,首先会去项目的 package.json 文件里找 scripts 里对应的 xxx,然后执行 xxx 的命令,例如启动vue项目 npm run serve 的时候,实际上就是执行了 package.json 文件里 scripts 下的 serve 对应的 vue-cli-service serve 这条命令
2、那为什么不直接执行 vue-cli-service serve
而要执行 npm run serve
呢?
因为直接执行vue-cli-service serve
,会报错,因为操作系统中没有存在vue-cli-service
这一条指令
3、那既然vue-cli-service
这条指令不存在操作系统中,为什么执行npm run serve
时,也就是相当于执行了vue-cli-service serve
,为什么这样它就能成功,而且不报指令不存在的错误呢?
我们重点关注下这个问题:为什么执行npm run serve
时可以成功,而且不报指令不存在的错误呢?
因为我们在安装依赖的时候,是通过 npm i xxx 来执行的,例如 npm i @vue/cli-service
,npm 在安装这个依赖的时候,就会在 node_modules/.bin/
目录中创建好 vue-cli-service
为名的几个可执行文件了。
.bin 目录,这个目录不是任何一个 npm 包目录下的文件,表示这是一个个软链接,打开文件可以看到文件顶部写着 #!/bin/sh
,表示这是一个脚本
#!/bin/sh basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')") case `uname` in *CYGWIN*|*MINGW*|*MSYS*) basedir=`cygpath -w "$basedir"`;; esac if [ -x "$basedir/node" ]; then exec "$basedir/node" "$basedir/../@vue/cli-service/bin/vue-cli-service.js" "$@" else exec node "$basedir/../@vue/cli-service/bin/vue-cli-service.js" "$@" fi
由此我们可以知道,当使用 npm run serve
执行 vue-cli-service serve
时,虽然没有安装 vue-cli-service
的全局命令,但是 npm 会到 ./node_modules/.bin
中找到 vue-cli-service
文件作为 脚本来执行,则相当于执行了 ./node_modules/.bin/vue-cli-service serve
(最后的 serve 作为参数传入)
4、.bin 目录下的文件表示软连接,那这个bin目录下的那些软连接文件是哪里来的呢?它又是怎么知道这条软连接是执行哪里的呢?
我们可以直接在新建的vue项目里面搜索vue-cli-service
可以看到,它存在项目的 package-lock.json 文件中,从 package-lock.json 中可知,当我们npm i 整个新建的vue项目的时候,npm 将 bin/vue-cli-service.js 作为 bin 声明了。
注意:bin字段不是在自己项目的package.json文件里面,而是在库的源代码中的package.json里面,用于在安装时创建软链指向bin中的地址
在 npm i 安装时写入到了项目的 package-lock.json 里
所以在 npm install 时,npm 读到该配置后,就将该文件软链接到 ./node_modules/.bin 目录下,而 npm 还会自动把node_modules/.bin加入$PATH,这样就可以直接作为命令运行依赖程序和开发依赖程序,不用全局安装了。
假如我们在安装包时,使用 npm install -g xxx
来安装,那么会将其中的 bin 文件加入到全局,比如 create-react-app 和 vue-cli ,在全局安装后,就可以直接使用如 vue-cli projectName 这样的命令来创建项目了。
也就是说,npm i 的时候,npm 就帮我们把这种软连接配置好了,其实这种软连接相当于一种映射,执行 npm run xxx 的时候,就会到 node_modules/bin 中找对应的映射文件,然后再找到相应的js文件来执行。
5、刚刚看到在node_modules/bin中有三个vue-cli-service文件,为什么会有三个文件呢?
如果我们在 cmd 里运行的时候,windows 一般是调用了 vue-cli-service.cmd
这个文件,这是 windows 下的批处理脚本。
所以当我们运行vue-cli-service serve
这条命令的时候,就相当于运行 node_modules/.bin/vue-cli-service.cmd serve
然后这个脚本会使用 node 去运行 vue-cli-service.js
这个 js 文件,由于 node 中可以使用一系列系统相关的 api ,所以在这个 js 中可以做很多事情,例如读取并分析运行这条命令的目录下的文件,根据模板生成文件等
# unix 系默认的可执行文件,必须输入完整文件名 vue-cli-service # windows cmd 中默认的可执行文件,当我们不添加后缀名时,自动根据 pathext 查找文件 vue-cli-service.cmd # Windows PowerShell 中可执行文件,可以跨平台 vue-cli-service.ps1
6、总结:
(1)运行 npm run xxx的时候,npm 会先在当前目录的 node_modules/.bin 查找要执行的程序,如果找到则运行;
(2)没有找到则从全局的 node_modules/.bin 中查找,npm i -g xxx就是安装到到全局目录;
(3)如果全局目录还是没找到,那么就从 path 环境变量中查找有没有其他同名的可执行程序。
二、当输入 npm run 后发生了什么
在前端开发的工作当中,使用 npm run dev
的命令启动本地开发环境,是再正常不过的事了。那么,当输入完类似 npm run xxx
的命令后,究竟是如何触发各种构建工具的构建命令以及启动 Node 服务等功能的呢?
首先我们知道,Node 作为 JavaScript 的运行时,可以把 .js
文件当做脚本来运行,像这种:node index.js
npm
来管理项目时,会在根目录下生成一个 package.json
文件,其中的 scripts
属性,就是用于配置 npm run xxx
命令的,比如我有如下配置:
// package.json { // ... "scripts": { "start": "node ./src/index.js", "build": "react-scripts build", }, // ... }
当执行 npm start
时,对于 npm
来说,相当于执行 npm run start
,则映射为 scripts
属性下的 start
命令,即
npm start # 相当于 npm run start # 相当于 node ./src/index.js
这个比较好理解,就是直接使用全局安装的 Node 命令来执行了 ./src
目录下的 index.js
文件而已。
如上面类似,执行 npm run build
即相当于执行 react-scripts build
命令。这个命令,是使用 create-react-app
搭建 React 项目时默认配置的。与 Node 不同,react-scripts
并没有全局安装,怎么就能直接执行呢?
这时我们不妨看一下,使用 create-react-app
搭建的项目(使用 vue-cli
搭建的项目也一样),在 npm install
后,其 node_modules
目录下面的样子:
如图可以看到有一个 .bin
目录,这个目录不是任何一个 npm
包。目录下的文件,右面都有一个小箭头(VS Code 上这样显示),表示这是一个软链接,打开文件可以看到文件顶部写着 #!/user/bin/env node
,表示这是一个通过使用 Node 执行的脚本。
npm run build
执行 react-scripts build
时,虽然没有安装 react-scripts
的全局命令,但是 npm
会到 ./node_modules/.bin
中找到 react-scripts.js
文件作为 Node 脚本来执行,则相当于执行了 ./node_modules/.bin/react-scripts build
(最后的 build
作为参数传入)。
npm run build # 相当于 ./node_modules/.bin/react-scripts build
前面说过,react-scripts
是一个软链接,那么它的指向是哪里,又是怎么来的呢?
我们可以在 node_modules
目录下,直接找到 react-scripts
包,查看其目录结构和 package.json
如下:
从 package.json
中可知,这个包将 ./bin/react-scripts.js
作为 bin
声明了。所以在 npm install
时,npm
读到该配置后,就将该文件软链接到 ./node_modules/.bin
目录下,而 npm
还会自动把node_modules/.bin加入$PATH,这样就可以直接作为命令运行依赖程序和开发依赖程序,不用全局安装了。
假如我们在安装包时,使用 npm install -g xxx
来安装,那么会将其中的 bin
文件加入到全局,比如 create-react-app
和 vue-cli
,在全局安装后,就可以直接使用如 vue-cli projectName
这样的命令来创建项目了。
第二节来源于:https://juejin.cn/post/6971723285138505765
还有这篇文章,可以学一下:https://juejin.cn/post/7025908145650139144
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。