node_modules/.bin和依赖命令原理

6,314 阅读4分钟

npm run的原理

其实npm run的原理非常简单,每次执行npm run就会新建一个shell,在这个shell,在这个shell里面执行脚本,因此,这个脚本得要求不仅是node脚本,只要在shell中可以执行就可以。

在scripts模块内可以使用运行我们自己写的脚本,例如

scripts:{

"test":"node ../test.js"

}

使用npm run test来执行脚本,

除了在外壳存在的路径之外,比较特别的是,npm run新建的这个 Shell,会将当前目录的node_modules/.bin子目录加入PATH变量,执行结束后,再将PATH变量恢复原样,因此我们还可以直接执行本地安装依赖自带的命令,npm run提供了node_modules/.bin 的 PATH 提供给脚本,本地安装的依赖的任何二进制文件都可以不带node_modules/.bin 前缀来使用。

node_modules/.bin文件下的可执行文件又是从何而来呢?

首先我们知道,npm是随同NodeJS一起安装的包管理工具,用于 Node.js 包的发布、传播、依赖控制,npm 的背后,是基于 couchdb 的一个数据库,详细记录了每个包的信息,包括作者、版本、依赖、授权信息等。它的一个很重要的作用就是:将开发者从繁琐的包管理工作(版本、依赖等)中解放出来,更加专注于功能的开发。

npm 的 package.json 记录了下载包的具体表述,node_modules文档就是存放这些安装包的地方。

在node_modules文件下我们可以看到每个被上传包都有的packsge.json文件,其内保存着许多配置参数,其中有一个参数是bin,例如lint-staged

在安装时,npm 会将文件符号链接到 prefix/bin 以进行全局安装或/node_modules/.bin/ 本地安装。

当安装完之后,我们可以在node_modules/.bin下发现一个名为lint-staged的文件,如图:

#!/usr/bin/env/ node 是什么??上传包脚本第一行是这行代码的原因?

指定执行脚本的解释器。

#!叫做Shebang,常出现在类Unix系统的脚本中第一行,作为前两个字符,用于指明执行这个脚本文件的解释器。如果#!之后的解释程序是一个可执行文件,那么执行这个脚本时,它就会把文件名及其参数一起作为参数传给那个解释程序去执行。如果#!指定的解释程序不存在,那么会报错,如果没有权限则使用shell执行。/usr/bin/env 用来告诉用户到path目录下去寻找node,#!/usr/bin/env node 可以让系统动态的去查找node,以解决不同机器不同用户设置不一致问题。 下面是两个参考的内容,想知道具体细节可以阅读一下:
具体细节1
具体细节2 我们自己在项目内写的脚本需要在scripts中使用node xxx来实现调用,npm run实现临时shell的创建,在环境变量内寻找node来执行。

npm 脚本的退出码!!! 因为脚本在shell中运行,所以必须要遵守 Shell 脚本规则。如果退出码不是0,npm 就认为这个脚本执行失败,如图:

在开发中运行命令案例:

在husky配合lint-staged实现约束代码规范中我们可以发现可以这样实现:

{
    "husky": {

    "hooks": {

        "pre-commit": "lint-staged"

        }

    },

    "lint-staged": { "*.js": "eslint --fix" }

}

其中利用git的钩子函数(可能用词不准确)来实现lint-staged命令的调用,来实现约束。

由上面可知,上传包的人员用bin配置来指定脚本文件,使用npm下载的使用者下载依赖时,npm自动会根据package.json下的bin建立链接,生成可直接省略/node_modules/.bin/直接调用的脚本文件供使用者使用。

npm的执行顺序

(这段来自阮一峰老师的npm介绍)
如果 npm 脚本里面需要执行多个任务,那么需要明确它们的执行顺序。
如果是并行执行(即同时的平行执行),可以使用&符号。
$ npm run script1.js & npm run script2.js
如果是继发执行(即只有前一个任务成功,才执行下一个任务),可以使用&&符号。
$ npm run script1.js && npm run script2.js
这两个符号是 Bash 的功能。