npm 不仅是 JavaScript 的包管理工具,它还可以用于你代码库相关的配置工具,如 Linters(代码检查工具)、transpilers(代码转译工具)、testing(测试工具)和servers(本地服务器)等。这些都可以根据软件包的说明进行配置并运行。基本用法也很简单。
你可以在
主对象中的
- package.json
属性中指定 scripts ,然后使用
- scripts
运行 scripts。
- npm run
例如:
- {
- ...
- "scripts": {
- "build": "webpack --progress",
- "test": "karma start",
- "server": "webpack-dev-server"
- }
- ...
- }
然而,在执行你的配置时,有些细节可能会很有用。
假设你想要运行 Karma ,默认情况下,你无需此功能即可监听所有文件是否已经更改。
为此,它们提供了一个可以与 script 一起使用的
标志。
- --single-run
实现这一点的最简单方法是在我们的 scripts 中添加一个新条目。
例如:
- "test:single-run": "karma start --single-run"
但是,如果我们要修改我们的默认 test 选项,我们必须在两个地方进行修改
和
- test
。
- test:single-run
或者我们可以直接从命令行中使用我们的标志来解决这个问题。
为了实现这一点,在我们的命令的末尾使用
,这会告诉 npm ,在此之后的任何东西都应该直接附加到命令中。
- --
- $ npm run test----single - run
如果你想在一个 script 运行多个命令,假设说 CSS linter(检查),JS linter 和 html linter ,最好一次新运行它们来加快运行速度。(愚人码头注:并行)
但是,如果你的命令存在相互依赖的话,比如说在运行 test 之前需要先运行 transpiler ,你会想要一个接一个地运行的执行流程,不是同时运行。(愚人码头注:串行)
因为 npm scripts 在内部实际产生的是一个
进程,所以我们可以使用
- shell
语法来实现我们所需要的功能。 具体来说,使用
- shell
(和
- ;
,下一节会详细说明) 来串联运行,使用
- &&
来并行运行。
- &
使用此语法的示例如下所示:
并行:
- "lint": "eslint & csslint & htmllint"
串行:
- "build": "babel; jest"
(我知道,Jest 测试运行器有一个内置的功能来预编译你的代码,这只是一个例子)。
它会工作很好,但是这种方法有一个相当大的问题。
语法会创建一个子进程,这会导致无法判断原始的
- &
进程是否已经完成。这可能是有问题的,特别是长时间运行 scripts 时。
- npm
为了使事情更加一致,我们可以使用一个名为
的包。它提供了额外的命令,更具体地说就是,用
- npm-run-all
来运行串联任务, 用
- run-s
来运行并行任务,它将正确处理所有的子进程。
- run-p
并行:
- "lint": "run-p eslint csslint htmllint"
串行:
- "build": "run-s babel jest"
在我们前面的例子中,在运行测试命令之前,我们运行转译器。
但是,如果一开始就发现了转译失败,那么运行测试的意义是什么?
语法会让下一个命令等待,直到上一个命令完成后。也就是说上一个命令完成后,再运行下一个命令,不管上一个命令的退出代码是什么,下一个命令始终会执行。
- ;
而我们想要的是,如果任何一个串联命令失败,则停止后续的所有命令执行。
要改成这样,我们只需使用
代替
- &&
即可:
- ;
- "build": "babel && jest"
现在,如果
以除了
- babel
以外的代码退出,这意味着该进程会被中止,
- 0
将永远不会运行。
- jest
当然,我们可以按照我们想要的方式链调用这个语法:
- "build": "eslint && babel && jest && deploy"
npm 中的每条 script 在引擎内部都会运行三个单独的 script 。一个
scripts,一个 scripts 本身和一个
- pre
scripts。 这两个额外运行的 scripts ,正如他们的名字所描述的那样,就是在该 scripts 运行前和该 scripts 运行后运行的脚本。
- post
例如,在部署期间,它们可用来做一些设置和清理。
这两个 scripts 使用与之前
名称相同的
- scripts
和
- pre[scriptname]
来表示。
- post[scriptname]
假设我们要构建我们的项目,这将是一个非常简单的例子,只是为了展示这个概念。
我们会做的是这样的:
目录,如果这个目录已经存在,那么从中删除所有内容
- dist
目录
- tmp
目录
- tmp
目录
- dist
目录
- tmp
- "prebuild": "mkdir dist tmp; rm -rf dist/*",
- "build": "browserify main.js -o tmp/bundle.js && uglifyjs -o dist/bundle.min.js -- tmp/bundle.js",
- "postbuild": "rm -rf tmp"
请注意,你应该使用的
包进行跨平台兼容性,因为上面的代码无法在 Windows 上运行。
- rimraf
现在,每当运行
时,它会触发所有命令,并且保证他们以正确的顺序被执行。
- npm run build
npm 中的命名约定使用冒号对整组特定任务进行分组。在上面的代码示例之一中,我们使用
语法并行运行所有代码检查任务。
- &
我经常想做的是将这些任务分成较小的块,并使用 script 本身的
命令将其作为命令组运行。
- npm run
我们以前的例子看起来像这样:
- "lint": "eslint & csslint & htmllint"
我们可以做的是将他们分隔成单独的任务(例如,如果我们需要添加一些 flags 标志来配置它们),并将它们组合在一起。
我们所能做的是将每一个单独的(例如,我们需要添加一些标记来配置它们)并将它们组合在一起。
- "lint": "npm run lint:js & npm run lint:css & npm run lint:html",
- "lint:js": "eslint --some-flag",
- "lint:css": "csslint --that-will-change",
- "lint:html": "htmllint --how-things-work"
在这个更改之后,它将以同样的方式工作,但是现在我们可以同时运行它们,或者在需要的时候也可以分别单独运行。
为了使其更加清洁,我们可以再次使用
,并将我们的主要
- npm-run-all
命令更改为
- lint
,然后它将匹配
- npm-run-all lint:*
分组中的所有 scripts 。
- lint:
我最近刚学到的一件事是,npm 本身为我们提供了一种 baked-in 方式,即在终端中添加命令完成。更好的是它还将包含你所有的自定义 scripts !
根据你的环境(
或
- bash
) ,你只需将
- zsh
命令的结果直接传递给
- npm completion
或
- ~/.bashrc
。记住要使用
- ~/.zshrc
重载这个文件!
- source ~/.bashrc
- $ npm completion >> ~/.bashrc
- $ npm completion >> ~/.zshrc
由于实用了
语法,npm 能够识别如上所述的常规退出代码,我们可以编写非常简单的 node scripts,这将为我们做一些初步检查。
- &&
例如,确保用户指定了所有必需的
环境变量,或者在尝试运行命令名时不包含任何拼写错误。
- ENV
我最近使用的是这个 node.js 脚本验证我已经设置了
,并且开发人员正在使用其中一个预定义的 env-specific(环境指定) scripts。
- NODE_ENV
我的 scripts 看起来像这样:
- "build": "node ./scripts/env-check.js && rimraf dist && webpack --bail --progress --profile --display-error-details",
- "build:development": "NODE_ENV=development npm run build",
- "build:staging": "NODE_ENV=staging npm run build",
- "build:production": "NODE_ENV=production npm run build",
内容:
- env-check.js
- const task = process.env.npm_lifecycle_event
- const packageJSON = require('../package.json')
- const availableEnvironments = Object.keys(packageJSON.scripts)
- .filter(key => key.startsWith(task))
- .map(key => key.split(':')[1])
- .filter(key => key)
- if (!process.env.NODE_ENV) {
- console.error(`[ Error ] NODE_ENV is required. Use ${task}:${availableEnvironments.join('/')} scripts instead.`)
- process.exit(1)
- }
- if (!availableEnvironments.includes(env)) {
- console.error(`[ Error ] ${env} is not valid NODE_ENV. Use ${task}:${availableEnvironments.join('/')} scripts instead.`)
- process.exit(1)
- }
- process.exit(0)
现在,每当开发人员输入
时,该提示将显示:
- npm run build
- [Error] NODE_ENV is required.Use build: development / staging / production scripts instead.
上面的代码有个缺点是,没有使用
script,这似乎是一个完美的地方来做这个检查:
- pre
- "prebuild": "node ./scripts/env-check.js && rimraf dist",
- "build": "webpack --bail --progress --profile --display-error-details",
要解决这个问题,我们必须更新
变量,因为
- task
不会返回
- process.env.npm_lifecycle_event
名称,而是返回
- build
。
- prebuild
- const task = process.env.npm_lifecycle_event.startsWith('pre') ? process.env.npm_lifecycle_event.slice(3) : process.env.npm_lifecycle_event
现在,我们可以在任何
script 中放置
- pre
,它将为我们执行这些所有的初步检查。
- node ./scripts/env-check.js
我个人使用它来构建,服务和部署脚本,但它肯定可以在更多的地方有效地使用。
来源: http://www.css88.com/archives/8029