用脚步丈量人生宽度

基于npm scripts的前端构建工具

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

基于npm scripts的前端构建工具

问题

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

为何会忽略掉 npm scripts

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

npm scripts

npm 会在项目的 package.json 文件中寻找 scripts 区域,其中包括 npm test 和 npm start等命令。事实上,npm test 和 npm start 是 npm run test和 npm 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.json 的 scripts 对象里

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

package.json

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

运行任务

npm run scss

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

用到的库 postcss-cli,autoprefixer

安装 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.json 的 scripts 对象里

package.json

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

运行任务

npm run lint

压缩/混淆 javascript

依赖库 uglify-js

安装

npm i -D uglify-js

写入 package.json 的 scripts 对象里

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.json 的 scripts 对象里

package.json

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

运行任务

npm run imagemin

开启http静态服务器

依赖库 BrowserSync

安装

npm i -D browser-sync

写入 package.json 的 scripts 对象里

package.json

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

监听css和javascript的改变

依赖库: onchange

安装

npm i -D onchange

写入 package.json 的 scripts 对象里

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文件

相关链接

评论

暂未收到

写下评论

支持 Markdown 语法