npm run 命令解析与node_modules .bin下的文件解析

npm run 命令解析

在vue和react项目中,我们常常用到npm run dev命令来起本地服务,那么npm run dev到底做了什么?

package.json文件中的字段script的每一个属性都是一个自定义的脚本命令,npm run 其实执行了package.json中的script脚本

下面的例子,我们以vue-cli3脚手架搭建的项目为例说明,所以当我们输入命令npm run serve命令,底层相当执行vue-cli-service serve --port 8055命令

// package.json
"scripts": {
    "serve": "vue-cli-service serve --port 8055",
    "build": "vue-cli-service build",
    "build:test": "vue-cli-service build --mode test",
    "build:beta": "vue-cli-service build --mode beta",
    "lint": "vue-cli-service lint",
    "inspect-old": "vue-cli-service inspect --mode production > webpack.inspect.js",
    "inspect": "vue inspect --mode production",
    "inspectwebpack": "vue inspect --mode production > output.js"
}
知识点总结

npm run如果不加任何参数,直接运行,会列出package.json里面所有可以执行的脚本命令(script字段里面的内容)。

npm start可以运行是为了方便开发者使用,npm start会执行scripts里的start字段。 如果没有start字段则执行node server.js。

This runs an arbitrary command specified in the package's "start" property of its "scripts" object. If no "start" property is specified on the "scripts" object, it will run node server.js.

执行原理

使用npm run script执行脚本的时候都会创建一个shell,然后在shell中执行指定的脚本。

这个shell会将当前项目的可执行依赖目录(即node_modules/.bin)添加到环境变量path中,当执行之后再恢复原样。就是说脚本命令中的依赖名会直接找到node_modules/.bin下面的对应脚本,而不需要加上路径,所以scripts字段里面调用命令时不用加上路径,这就避免了全局安装NPM模块

执行顺序
'&' 并行执行顺序,同时执行
"dev":"node test.js & webpack"

'&&'继发顺序,执行前面之后才可以执行后面
"dev":"node test.js && webpack"
顺序钩子
"predev":"node test_one.js",
"dev":"node test_two.js",
"postdev":"node test_three.js"

当执行 npm run dev 的时候默认就会执行

npm run predev && npm run dev && npm run postdev
四个可以简写的脚本执行命令

npm start === npm run start

npm stop === npm run stop

npm test === npm run test

npm restart === npm run stop && npm run restart && npm run start

使用package.json内部变量

通过npm_package_前缀,npm脚本可以拿到npm的内部变量

// package.json
{
  "name":"zhy",
  "test":"node test.js"
}

test.js:
console.log(process.env.npm_package_name) //zhy

node_modules/.bin文件夹内容解析

下面是vue-cli3搭建的项目node_modules/.bin文件夹下面的文件名

eslint
eslint.cmd
lessc
lessc.cmd
uuid
uuid.cmd
vue-cli-service
vue-cli-service.cmd

对于一个npm包,有两个可执行文件,没有后缀名的是是对应unix系的shell脚本,.cmd文件对应的是windows bat脚本,内容都是用node执行一个js文件

// vue-cli-service.cmd文件内容
// windows bat脚本
@IF EXIST "%~dp0
ode.exe" (
  "%~dp0
ode.exe"  "%~dp0..\_@vue_cli-service@3.12.1@@vuecli-serviceinvue-cli-service.js" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0..\_@vue_cli-service@3.12.1@@vuecli-serviceinvue-cli-service.js" %*
)

这里是windows的cmd中的语法
~dp0指执行脚本的当前目录,这句话的意思是如果当前目录下有node.exe,就用node.exe执行... ...webpack.js文件 %*是指执行bat时命令中输入的后续参数
否则 @SETLOCAL设置本次批处理命令中的环境变量
PATHEXT是windows下的文件扩展名环境变量 后面的语法是从PATHEXT中删除.JS 然后执行 node ... ... webpack.js 命令,
去除掉扩展名的作用是为了防止执行到node.js文件
比如当前文件夹下有一个node.js文件, 如果直接执行node命令可能会默认用vscode打开这个.js文件

// vue-cli-service文件内容
// unix系的shell脚本
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\,/,g')")

case `uname` in
    *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac

if [ -x "$basedir/node" ]; then
  "$basedir/node"  "$basedir/../_@vue_cli-service@3.12.1@@vue/cli-service/bin/vue-cli-service.js" "$@"
  ret=$?
else 
  node  "$basedir/../_@vue_cli-service@3.12.1@@vue/cli-service/bin/vue-cli-service.js" "$@"
  ret=$?
fi
exit $ret
原文地址:https://www.cnblogs.com/HYZhou2018/p/12195670.html