什么是 npm script
npm script
其实我们每天都在使用,就是我们package.json
文件scripts
属性里面的语句。比如我们常用的npm run dev、npm run serve、npm start
等等都是npm script
。
运行单个命令
首先我们在package.json
文件新建一个test script
,内容是输出hello randy
然后我们运行npm run test
,控制台可以看到
至此我们的第一个npm script
就运行成功啦。
运行多个命令
在实际开发过程中可能会碰到多个命令一起启动的情况。比如我们前后端一起启动。
运行多个命令就会涉及到串行和并行问题了,下面笔者分开讲解。
串行
串行实现方式也比较简单,只需要用 &&
符号把多条 npm script
按先后顺序串起来即可。
"scripts": {
"frotend": "echo \"前端服务启动啦\"",
"server": "echo \"后端服务启动啦\"",
"all1": "npm run frotend && npm run server",
},
运行结果如下
需要注意的是,串行执行的时候如果前序命令失败,后续全部命令都会终止。
并行
有时为了提高效率,我们希望多个命令并行执行,只需要用 &
符号把多条 npm script
按先后顺序串起来即可。
"scripts": {
"frotend": "echo \"前端服务启动啦\"",
"server": "echo \"后端服务启动啦\"",
"all2": "npm run frotend & npm run server",
},
运行结果如下
其实除了使用&& 和 &
,我们还有更优雅的方式,可以使用npm-run-all或concurrently。
更好的方式1 npm-run-all
首先我们来安装
npm i npm-run-all -D
然后添加我们的npm-run-all
命令
"scripts": {
"frotend": "echo \"前端服务启动啦\"",
"server": "echo \"后端服务启动啦\"",
"all3": "npm-run-all frotend server",
},
运行结果如下
上面是串行执行的,当然我们也可以并行执行,只需要加上--parallel
"scripts": {
"frotend": "echo \"前端服务启动啦\"",
"server": "echo \"后端服务启动啦\"",
"all4": "npm-run-all --parallel frotend server",
},
运行结果如下
npm-run-all还有很多用法,这里只是一个入门,感兴趣的同学可以查看文档自行学习。
更好的方式2 concurrently
首先我们来安装
npm i concurrently -D
然后添加我们的concurrently
命令
"scripts": {
"frotend": "echo \"前端服务启动啦\"",
"server": "echo \"后端服务启动啦\"",
"all5": "concurrently \"npm run frotend\" \"npm run server\""
},
运行结果如下
concurrently还有很多用法,这里只是一个入门,感兴趣的同学可以查看文档自行学习。
给 npm script 传递参数
eslint
我们都知道,是前端开发代码检测的一个重要工具。我们经常配置两条script
,一条用来检测错误,一条用来进行简单错误的修复。
"lint": "eslint js/*.js",
"lint:fix": "eslint js/*.js --fix"
笔者js
文件夹下有这样一个js
文件,它是空格问题。
我们运行npm run lint
,可以看到如下错误
空格这种简单问题eslint
是可以自动修复的,我们运行npm run lint:fix
可以看到,空格问题被自动修复了
其实学习完npm script
传递参数后,我们一条命令就可以搞定了。
npm script
使用--
传递参数。
我们在package.json
里面只需要配置一条命令
"lint": "eslint js/*.js",
需要修复的时候我们通过传递参数的方式进行处理。
可以看到,空格问题也被自动修复了,其实它运行的就是eslint js/*.js --fix
通过参数的方法可以大大减少我们script
的数量,让script
灵活度更高,特别是某些需要传递各种参数的script
。
npm script 日志
在运行 npm script
出现问题时你需要有能力去调试它,我们可以通过看日志来分析问题。日志级别是可以通过参数控制的。
默认日志输出级别
即不加任何日志控制参数得到的输出,可能是你最常用的,能看到执行的命令、命令执行的结果。
比如笔者上面的例子
显示更少日志
如果需要显示更少日志,我们只需要在运行script
的时候传递--loglevel silent
或者 --silent
或者更简单的 -s
来控制。
比如笔者上面的例子
就只会输出结果,非常简单。
显示更多日志
如果需要显示更多日志,我们只需要在运行script
的时候传递--loglevel verbose
或者 --verbose
或者更简单的 -d
来控制。
比如笔者上面的例子
可以看到,输出了非常多的信息。
npm script 钩子
为了方便开发者自定义,npm script
的设计者为命令的执行增加了类似生命周期的机制,具体来说就是 pre
和 post
钩子脚本。这种特性在某些操作前需要做检查、某些操作后需要做清理的情况下非常有用。
举例来说,运行 npm run test
的时候,分 3 个阶段:
- 检查 scripts 对象中是否存在 pretest 命令,如果有,先执行该命令;
- 检查是否有 test 命令,有的话运行 test 命令,没有的话报错;
- 检查是否存在 posttest 命令,如果有,执行 posttest 命令;
还是上面代码检查的例子,我们创建三条命令
"lint": "eslint js/*.js",
"prelint": "eslint js/*.js --fix",
"postlint": "echo \"eslint执行完毕\""
我们在每次lint
前,自动进行代码修复,执行完lint
后输出eslint
执行完毕。我们来看下效果
我们只执行了npm run lint
,但是它执行了npm run prelint、npm run lint、npm run postlint
三条命令。
npm script 变量
npm script
可以使用预定义变量和自定义变量。
预定义变量
预定义变量其实就是解析整个package.json
文件获取各个字段和值。
通过运行 npm run env
就能拿到完整的变量列表,这个列表非常长,这里我使用 npm run env | grep npm_package | sort
拿到部分排序后的预定义变量:
笔者的文件如下
变量的使用方法遵循 shell
里面的语法,直接在 npm script
给想要引用的变量前面加上 $
符号即可。
"var1": "echo $npm_package_author_name"
执行npm run var1
,运行结果如下
自定义变量
除了预定义变量外,我们还可以在 package.json
中添加自定义变量,并且在 npm script
中使用这些变量。
自定义变量需要配置在package.json
里面config
字段里。
{
"config": { "say": "hello randy" },
}
使用跟预定义变量一样,在变量前面加上 $
符号即可。
"var2": "echo $npm_package_config_say"
执行npm run var2
,运行结果如下
注意Linux、Mac
下直接可以用$npm_package_name
,而Windows
下必须使用%npm_package_name%
。
npm script 跨平台兼容
前面说到Linux、Mac
和Windows
引用变量的方式是不同的。
可能有部分同学处理过 npm script
跨平台兼容的问题,比如粗暴的为两种平台各写一份 npm script
,像下面这样:
{
"name": "test",
"scripts": {
"bash-script": "echo Hello $npm_package_name",
"win-script": "echo Hello %npm_package_name%"
}
}
那有没有什么更好的办法来实现呢?
cross-var
cross-var就是用来解决跨平台变量使用问题的。
首先我们安装 cross-var
npm i cross-var -D
然后修改我们的命令
"var3": "cross-var echo %npm_package_config_say%",
"var4": "cross-var echo $npm_package_config_say"
我们来看下运行结果
笔者是mac
,可以看到,使用windows
的方式引用变量也是能正常运行的。这就是cross-var
的魅力。
有写小伙伴可能会说啦,变量平时使用的不多,环境变量倒使用的不少,那有什么跨平台使用环境变量的方式吗?
cross-env
cross-env是用来解决跨平台环境变量问题的。
首先我们安装 cross-env
npm i cross-env -D
然后我们在设置环境变量的时候,加上cross-env
就可以了。
"env1": "cross-env NODE_ENV=staging"
这样环境变量也可以跨平台使用了。
npm script 命令列表
对于一个新项目,如果想要知道它有哪些script
我们一般都会找到package.json
文件,然后查看它scripts
字段。其实还有更简单的方法,直接在项目目录下执行npm run
就能列出 scripts
对象中定义的所有命令。
这样是不是很爽呢。
运行 npm run xxx 的时候发生了什么
npm run xxx
的时候,首先会去项目的package.json
文件里找 scripts
里找对应的xxx
,然后执行 xxx
的命令,例如启动vue
项目 npm run serve
的时候,实际上就是执行了vue-cli-service serve
这条命令。
为什么不直接执行vue-cli-service serve
而要执行npm run serve
呢?
因为 直接执行vue-cli-service serve
,会报错,因为操作系统中没有存在vue-cli-service
这一条指令。
那既然vue-cli-service
这条指令不存在操作系统中,为什么执行npm run serve
的时候,也就是相当于执行了vue-cli-service serve
,为什么这样它就能成功,而且不报指令不存在的错误呢?
这就需要了解npm run xxx
是怎么查找命令的啦。
- 运行
npm run xxx
的时候,npm
会先在当前目录的node_modules/.bin
查找要执行的程序,如果找到则运行。 - 没有找到则从全局的
node_modules/.bin
中查找,npm i -g xxx
就是安装到到全局目录。 - 如果全局目录还是没找到,那么就从
path
环境变量中查找有没有其他同名的可执行程序。如果再没有找到就会报错了。
因为我们在安装依赖的时候,是通过npm i xxx
来执行的,例如 npm i @vue/cli-service
,npm
在安装这个依赖的时候,就会在node_modules/.bin/
目录中创建好vue-cli-service
为名的几个可执行文件了。
所以当使用 npm run serve
执行 vue-cli-service serve
时,npm
会到 ./node_modules/.bin
中找到 vue-cli-service
文件作为脚本来执行,则相当于执行了 ./node_modules/.bin/vue-cli-service serve
。
有时我们可以全局安装,例如npm i -g @vue/cli-service
,这样他会在全局的node_modules/.bin
中创建可以执行程序,所以我们在电脑的任何目录下都能运行对应的命令。
好了,感谢小伙伴们的耐心观看,关于npm script
今天就讲到这里。
后记
感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!