在前端开发工作中,为了避免重复的工作,我们通常会借助一些任务运行器去完成常见的前端任务,例如文件合并,脚本压缩,生成sprite图。世面上有很多这样的工具,比较成熟的有 gruntgulpwebpackshellant。使用这些工具可以大大的提高我们的日常产出,让我们把开发的重心放在项目本身的业务上,而不必在常见任务上浪费过多的时间。我们不去讨论这些工具之间的优势和差异,一千个读者就有一千个哈姆雷特。在工作中,我使用过的前端任务工具包括但不限于 gruntgulp,他们的确给我带来了很多的帮助,当我发现 npm scripts 命令就能很好的完成这些任务时,我不得不跟他们告别。相较于 gruntgulpnpm scripts 具有更大的优势,使用 npm scripts 执行构建自动化是一种更简单的方式。

基于npm scripts的前端构建工具

问题

  • 对插件作者的依赖
  • 令人沮丧的调试
  • 过时的文档

为何会忽略掉 npm scripts

  • 认为 npm scripts 需要强大的命令行技巧
  • 认为 npm scripts 不够强大
  • 认为 Gulp 的流对于快速构建来说是不可或缺的
  • 认为 npm scripts 无法实现跨平台运行

npm scripts

npm 会在项目的 package.json 文件中寻找 scripts 区域,其中包括 npm testnpm start等命令。事实上,npm testnpm startnpm run testnpm run start 的简写,你可以使用 npm run 来运行 scripts 里的任何条目。
使用 npm run 的方便之处在于,npm 会自动把 node_modules/.bin 加入 $PATH,当脚本内容结束,则子shell关闭,回到父shell中,这样你可以直接运行依赖和开发依赖程序,不需要全局安装了,只要 npm 上的包提供命令行接口,你就可以直接使用它们。

常见任务

package.json 模板

{
  "name": "npm-scripts-boilerplate",
  "version": "1.0.0",
  "scripts": {
    ...
  },
  "devDependencies": {
    ...
  }
}

我们的构建脚本命令放在 scripts 对象里,对于想使用的工具依赖库都放在 devDependencies对象里。

项目结构

编译 SCSS

scss 编译为 css,使用 node-sass.

安装 node-sass

命令行输入:
npm install --save-dev node-sass 或者 npm install -D node-sass

命令行脚本

安装完成后,我们可以使用 node-sass 工具来构建我的任务: node-sass --output-style compressed -o dist/css src/sass
上面的命令行功能比较容易理解,就是 src/sass 下的 *scss 文件编译成 css 文件,并输出到 dist/css 目录下,文件内容的输出风格为 compressed,输出风格可以任意选择,可以使用 node-sass help 查看帮助。

写入 package.jsonscripts 对象里

把上面的代码放到 package.json 文件里,package.json的内容变成:

package.json

"scripts": {
  "scss": "node-sass --output-style compressed -o dist/css src/sass"
}

运行任务

npm run scss

使用 PostCSS 自动补全 CSS 浏览器厂商前缀

用到的库 postcss-cliautoprefixer

安装 postcss-cli, autoprefixer

npm install -D postcss-cli autoprefixer

写入 package.json 的 scripts 对象里

package.json

"scripts": {
  ...
  "autoprefixer": "postcss -u autoprefixer -r dist/css/*"
}

可以通过设置 autoprefixer 的相关参数来改变 autoprefixer 默认浏览器支持。

校验 javascript

eslint" class="reference-link">安装 eslint

npm i -D eslint 或者使用 npm install --save-dev eslint,前者是后者的简写方式。

运行命令,初始化一些 hint 的基本规则

eslint --init

写入 package.jsonscripts 对象里

package.json

"scripts": {
  ...
  "lint": "eslint src/js"
}

运行任务

npm run lint

压缩/混淆 javascript

依赖库 uglify-js

安装

npm i -D uglify-js

写入 package.jsonscripts 对象里

package.json

"scripts": {
  ...
  "uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js"
}

运行任务

npm run uglify

压缩图片

依赖库 imagemin-cli

安装

npm i -D imagemin-cli

写入 package.jsonscripts 对象里

package.json

"scripts": {
  ...
  "imagemin": "imagemin src/images dist/images -p",
}

运行任务

npm run imagemin

开启http静态服务器

依赖库 BrowserSync

安装

npm i -D browser-sync

写入 package.jsonscripts 对象里

package.json

"scripts": {
  ...
  "serve": "browser-sync start --server --files 'dist/css/*.css, dist/js/*.js'"
}

监听css和javascript的改变

依赖库: onchange

安装

npm i -D onchange

写入 package.jsonscripts 对象里

package.json

"scripts": {
  ...
  "watch:css": "onchange 'src/scss/*.scss' -- npm run build:css",
  "watch:js": "onchange 'src/js/*.js' -- npm run build:js",
}

使用 npm scripts 钩子创建任务

pre-post- 脚本命令,npm run 为每条命令提供了 pre-post- 两个钩子(hook)。以 npm run install 为例,如果我们的 scripts 字段定义了 postinstall

package.json

"scripts": {
  ...
  "postinstall": "npm run watch:all"
}

执行 npm run install 时,任务 postinstall 也会立即执行,在团队里,这是一种非常好的协作方式,当有人克隆我们的代码后,执行npm install,我们的 watch:all 任务也会跟着执行,它会自动的开启一个服务器并打开默认的浏览器,同时也会监听文件的修改。

使用内部变量

scripts 字段可以使用一些内部变量,主要是 package.json 的各种字段。内部变量的主要特征是 $npm_package_key

比如,package.json 的内容是

	
{
  "name":"mobile-scaffold",
  "version":"1.0.0"
}

那么变量 $npm_package_name 的值是mobile-scaffold,变量 npm_package_version 的值是 1.0.0

{
  "version": "1.0.0",
  "scripts": {
    ...
    "bundle": "mkdir -p build/$npm_package_version/"
  }
}

运行 npm run bundle 以后,将会生成 build/1.0.0/ 子目录。

config 字段也可以用于设置内部字段。

{
  "name": "mobile-scaffold",
  "config": {
    "port": "3000"
  },
  "scripts": {
    ...
    "serve": "http-server -p $npm_package_config_port"
  }
}

上面代码中,变量 npm_package_config_port对应的就是 3000

使 npm run 命令可以接收参数

在一些任务里,我们需要根据不同的情形来传递参数,最常见的例子就是提交 git commit -m需要填写一些信息,这时,npm run 能接收参数就显得非常重要了。
package.json 的内容是:

{
  "name": "mobile-scaffold",
  "scripts": {
    ...
    "preci": "git add -A",
    "ci": "git commit -m",
    "postci": "git push origin master"
  }
}

运行 npm run ci -- "add git command task",这条命令执行后,相继发生:

  1. preci 任务执行
  2. ci 任务执行
  3. postci 任务执行

痛点及解决之道

显然,使用 npm scripts 也存在着一些问题: JSON 规范并不支持注释,因此无法在 package.json 中添加注释。不过有一些办法可以突破这个限制:

  • 编写小巧、命名良好、单一目的的脚本
  • 分离文档与脚本(比如说放在README.md中)
  • 调用单独的.js文件

相关链接

标签: 基于npm scripts的前端构建工具, npm scripts前端构建, npm前端构建工具

添加新评论