Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

你真的了解npm-scripts吗? #43

Open
dolymood opened this issue Apr 15, 2019 · 4 comments
Open

你真的了解npm-scripts吗? #43

dolymood opened this issue Apr 15, 2019 · 4 comments

Comments

@dolymood
Copy link
Member

作者:tank0317

我们都很熟悉的,通过 npm run script-name 可以执行 package.json 中 scripts 对象配置的脚本。但是,你或许不知道下面这些知识。

下文中 npm-scirpt 指 package.json scripts 中配置的脚本命令。name-scirpt 指代某一个名字为 name 的脚本命令。

生命周期脚本/自定义脚本

当我们使用命令 npm start 时,npm 会尝试执行 package.json scripts 中配置的 start 脚本命令。start-script 的默认配置为 "start": "node server.js"。所以如果项目根目录下有 server.js 文件,那么通过 npm start 会直接运行 server.js 中的代码。

除了 start-script ,当使用 npm start 命令时,npm 同样会尝试在 package.json scripts 中查找是否配置了 prestart,poststart 脚本命令。如果都配置了,npm 会按照以下顺序执行脚本。

  • npm run prestart
  • npm run start
  • npm run poststart

类似的,npm test, npm restart, npm stop 都会按照以上的方式执行 scripts 中配置的对应脚本。同时 npm 会通过 npm_lifecycle_event 环境变量标识当前处于哪一阶段(所谓的生命周期)。比如,在 prestart-script 脚本执行阶段 npm_lifecycle_event 的值为 "prestart",start-script 阶段,值为 "start",即 package.json scripts 对象配置的脚本名字。

以上是 npm 内置命令对应的脚本执行逻辑,对于我们平时最熟悉的自定义脚本,以上逻辑同样适用。比如我们配置了 "build": "webpack --mode=production",同时配置了 prebuild 以及 postbuild 脚本,当使用 npm run build 时,同样会依次执行 prebuild-script、build-script、postbuild-script。

任意脚本

我们配置的脚本命令,如 "start": "node server.js"node server.js 会当做一行代码传递给系统的 SHELL 去解释执行。实际使用的 SHELL 可能会根据系统平台而不同,类 UNIX 系统里,如 macOS 或 linux 中指代的是 /bin/sh, 在 windows 中使用的是 cmd.exe。

既然是交给 SHELL 去解释执行的,说明配置的脚本可以是任意能够在 SHELL 中运行的命令,而不仅仅是 node 脚本或者 js 程序。即如果你的系统里安装了 python(或者说系统变量 PATH 里能找到 python 命令),你也可以将 scripts 配置为 "myscript": "python xxx.py"

环境变量

上面提到了在使用 npm run script-name 命令时,npm 会设置一个环境变量 npm_lifecycle_event。实际上 npm 还会设置很多环境变量,通过内置命令 npm run env 可以查看 npm 为脚本运行时设置的所有环境变量。 其中 package.json 中设置的所有字段,都会被设置为 npm_package_ 开头的环境变量。如果你的 packge.json 设置如下

{
  "name": "npm-demo",
  "version": "1.0.0",
  "script": {
    "build": "webpack --mode=production"
  },
  "files": ["src"]
}

则可以得到 npm_package_name、npm_package_version、npm_package_script_build、npm_package_files_0 等变量。注意上面 package.json 中对象和数组中每个字段都会有对应的环境变量。

不止 package.json,npm 相关的所有配置也会有 npm_config_ 开头的环境变量。

另外,需要注意的是,即使在子目录下使用 npm run 命令,脚本也会在项目的根目录下运行。如果你想要区分在哪里使用的 npm run 命令,可以使用 INIT_CWD 环境变量,该变量保存了 npm run 命令运行时目录的绝对路径。

如何使用这些环境变量?如果你的脚本是 shell 脚本,可以直接通过对应的环境变量名获取变量值,如果是 node 脚本,可以通过 nodejs 中的全局变量 process.env 获取,比如获取项目版本号可以使用 process.env.npm_package_version

PATH

上面提到了 npm-script 执行前会设置一些环境变量,其中很重要的一个环境变量是 PATH。npm 会将项目 node_modules/.bin 的绝对路径添加到环境变量 PATH 中。因此我们可以在 npm-script 中使用项目本地安装的一些命令行工具。如上面设置的 build 脚本: "build": "webpack --mode=production"

只要我们本地安装了 webpack,就可以在项目的 node_modules/.bin 路径下看到 webpack 可执行文件。又因为 node_modules/.bin 路径已经添加到 PATH 中,所以脚本运行时能够在 PATH 中找到 webpack 命令,从而顺利执行。

最后,为什么 webpack 安装后,能够在 node_modules/.bin 路径下找到对应的可执行文件?可以查看 https://docs.npmjs.com/files/package.json.html#bin

Reference

https://docs.npmjs.com/cli/run-script.html

https://docs.npmjs.com/misc/scripts.html

https://docs.npmjs.com/files/package.json.html

@hucheng91
Copy link

今天才真屌 package.json里变量都会打到环境变量里,学习里,之前一直都是 fs.readFileSync('package.json').toString('utf8')

@simplefeel
Copy link

process.env.npm_package_version这种方式获取项目版本号的方式学习到了~

@LFdeWeb
Copy link

LFdeWeb commented Dec 3, 2019

process.env.npm_package_version这种方式获取项目版本号的方式学习到了~

没懂获取这版本号干什么呢

@kkkkkcnm
Copy link

process.env.npm_package_version这种方式获取项目版本号的方式学习到了~

没懂获取这版本号干什么呢

如果你npm包升级,会有版本号比对

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants