已经在我的项目中使用 npm scripts 有六个月。在之前,我一直使用 Gulp , Grunt ,它们帮了我很多,让我的任务完成得更加高效,也自动帮我处理很多繁琐的任务。 然而,我开始感觉到我好想是在跟工具战斗而不是关乎自己的代码。
Grunt, Gulp, Broccoli,, Brunch 等等工具都要求你的任务符合它们定出的规则,每个工具都要你花时间去了解。并且一旦代码复杂性提高了,你需要花更多精力去处理这些工具。
这些构建工具依靠的插件外面包裹了一层命令行工具,在核心工具外面多了一层抽象,这也意味着可能存在隐患。
下面三个问题我遇到过好多次
- 如果这个工具下没有你想要的插件,那你就太不幸了(除非你自己写一个)
- 你尝试使用的插件包裹着你想用的另一个工具的老版本,那么会导致特性和文档对不上号。
- 错误不是一直都能被很好处理,如果一个插件出错了,它可能不会把错误抛出,这会导致你很痛苦,因为不知道如何 Debug 。
但是,记住
我想说:如果你对当前使用的构建工具非常满意,并且你要的它都能给你,咁你keep住就嘚啦。 只是因为 npm scripts 越来越重要,而不是说你必须跳船。把注意力集中于编写程序而不是用在学习工具。如果你也觉得你是在和工具战斗,那么我建议你尝试使用 npm scripts
如果你真的想开始使用 npm scripts,那么请继续看下去!你会看到很多例子,并且我建好了 npm-build-boilerplate 给你作为出发点。开始吧!
编写 npm scripts
我们都花了大把时间在 package.json
文件上,我们的依赖和 scripts 都在这,这是我 boilerplate 项目的精简版 package.json
{ "name": "npm-build-boilerplate", "version": "1.0.0", "scripts": { ... }, "devDependencies": { ... } }
|
我们的 scripts 都会写在 scripts 下面,而devDependencies 下存放的是我们项目的依赖。
开始之前,想看看这个项目的结构:
项目结构
SCSS => CSS
我是 SCSS 的狂热爱好者,所以我迫不及待地想跟你介绍。我使用 node-sass 来帮我做这项任务,
npm install --save-dev node-sass
|
使用上面的命令安装好 node-sass, 那么它会出现在你的 package.json 中的 devDependencies里面,这样对于其他想跑你代码的人就方便多了。安装完成之后,我们来使用它:
node-sass --output-style compressed -o dist/css src/scss
|
这行命令干了这样的事: node-sass 同学 (你是学计算机的吧?) 去把 src/scss
下的所有 SCSS 文件都编成 CSS 然后放在 dist/css
下面,对了,帮我压缩一下(compressed)
但是大领导通常都懒得说这么长的话,它跟 scripts 说 Just do IT
:
"scripts": { "scss": "node-sass --output-style compressed -o dist/css src/scss" }
|
然后大领导就只需要喊口号即可:
这样,大领导(你)就完成了编译 Sass 的任务(just kidding)。
接下的的部分,任何时候你都可以像上面那样创建 npm scripts
只需要替换把 scss 替换成你的命令即可。
正如你所见,很多命令行工具都需要一大把选项供你选择。比如这里是 node-sass options下面是多个选项的配置:
"scripts": { "scss": "node-sass --output-style nested --indent-type tab --indent-width 4 -o dist/css src/scss" }
|
Autoprefix CSS with PostCSS
现在我们使用 Autoprefixer & PostCSS 来自动添加前缀,我们可以同时安装多个模块:
npm install --save-dev postcss-cli autoprefixer
|
我们安装了两个模块,因为 PostCSS 默认什么都不做,他依赖于像Autoprefixer 这类插件。
现在我们都把两个工具添加到 devDependencies 中,在 scripts 对象中再添加一个任务:
"scripts": { ... "autoprefixer": "postcss -u autoprefixer -r dist/css/*" }
|
这个任务说,postcss 你用 autoprefixer 帮我把 dist/css/*
下的所有 css 文件给处理一下,那具体要适应什么浏览器你也要告诉 Autoprefix:
"autoprefixer": "postcss -u autoprefixer --autoprefixer.browsers '> 5%, ie 9' -r dist/css/*"
|
同样的,postcss-cli, autoprefixer也有很多可选项
Linting JavaScript
保持良好的编程风格和规范是错误最小化和开发效率的保障,Linting
帮助我们自动地检查,我们可以使用 eslint
再一次,我们安装 package,这一次使用快捷方式:
同下面的方式一样
npm install --save-dev eslint
|
安装完,我们使用 eslint 设置一些执行我们代码的基本规则,执行下面代码进入指引:
我建议你选择”Answer questions about your style” 并且回答它问的问题,这会生成一个新的文件在你的项目根部。
再次丰富 scripts 对象:
"scripts": {
...
"lint": "eslint src/js"
}
|
这13个字符的命令会查找在 src/js 下的所有js文件,并根据配置重新执行一遍。另外你会被这些配置逼疯的。
Uglifying JavaScript files
接下来是合并压缩 JavaScript文件,我们选择 uglify-js 来做:
然后再次配置 package.json :
"scripts": { ... "uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js" }
|
值得一提的是 npm scripts 本质上是命令行的别名,这意味着你可以在 scripts 中使用标准命令行代码,这里用到了 mkdir 和 &&
前半部分,mkdir -p dist/js
的意思是如果(-p)不存在这样的目录结构,则创建一个新的执行成功之后(&&) 再执行后半部分 uglifyjs src/js/*.js -m -o dist/js/app.js"
这部分是告诉 uglifyjs 使用 “mangle” (-m) 命令,应用在 src/js
的所有js 上,并产出到 dist/js/app.js
。
让我们再丰富下 uglify , 创建一个 compress 版本的 dist/js/app.js
(使用 -c )
"scripts": { ... "uglify": "mkdir -p dist/js && uglifyjs src/js/*.js -m -o dist/js/app.js && uglifyjs src/js/*.js -m -c -o dist/js/app.min.js" }
|
Compressing Images
接下来看看压缩图片。根据 httparchive.org , 前1000 个热门网站的页面大小是 1.9mb ,而其中图片就占了 1.1mb ,所以页面提速的首要因素是压缩图片体积。
安装 imagemin-cli
Imagemin 几乎可以压缩所有类型的图片,包括 GIF,JPG,SVG。你可以传递一个文件夹路径,然后它会处理其中的所有图片:
"scripts": { ... "imagemin": "imagemin src/images dist/images -p", }
|
这个任务是压缩所有在 src/images
下的图片,并把结果输出到 dist/images
。-p 的意思是 尽量创建 “progressive” 的图片。
SVG Sprites
近几年 SVG 越来越受欢迎,因为它几乎兼容所有设备,可以用 CSS 调整,视觉效果良好。然而很多 SVG 编辑器会残留多余和不必要的代码。我们使用 svgo 来移除。
你可以把压缩 SVG 和拼接精灵图放在一块,拼接精灵图我们使用svg-sprite-generator
npm i -D svgo svg-sprite-generator
|
现在你应该很熟悉这种模式了吧。
"scripts": { ... "icons": "svgo -f src/images/icons && mkdir -p dist/images && svg-sprite-generate -d src/images/icons -o dist/images/icons.svg" }
|
icons 这个任务做了三件事,传递了一个文件夹路径(-f)给 svgo, 然后如果没有(-p)dist/images
这个文件夹则创建一个,接着就拼接精灵图,结果保存到(-d)src/images/icons
, 产出(-o)叫做 dist/images/icons.svg
Serve and Automatically Inject Changes with BrowserSync
最后一个问题是 BrowserSync,他可以帮我们做的是:开启一个本地服务器,自动更新文件,自动在浏览器中同步点击,滚动效果。
"scripts": { ... "serve": "browser-sync start --server --files 'dist/css/*.css, dist/js/*.js'" }
|
这个任务打开一个本地服务(—server),以当前路径作为根目录,—files 参数告诉 Browsersync 监听 dist
下的所有css 和 js文件,一有更新,马上自动刷新页面。
Grouping tasks
有了上面的代码,我们现在能够:
- 编译 SCSS 并且自动添加前缀
- 检查并压缩 JavaScript
- 压缩图片
- 将一个 SVG 文件夹转成一张 SVG 精灵图
- 创建一个本地服务器,并实时自动刷新浏览器
Combining CSS tasks
我们可以把 CSS 相关的任务合并在一起:
"scripts": { ... "build:css": "npm run scss && npm run autoprefixer" }
|
当你执行 npm run build:css ,它会在执行 scss 任务成功之后在执行 autoprefixer 。
其他任务也类似,我们也可以这样做
"scripts": { ... "build:js": "npm run lint && npm run uglify", "build:images": "npm run imagemin && npm run icons", "build:all": "npm run build:css && npm run build:js && npm run build:images" }
|
Watching for changes
我们现在还需要监听文件的变动,并自动执行相应的任务,我推荐使用 onchange,安装:
添加任务:
"scripts": { ... "watch:css": "onchange 'src/scss/*.scss' -- npm run build:css", "watch:js": "onchange 'src/js/*.js' -- npm run build:js", }
|
任务是给 onchange 传递一个需要监听的文件路径,我们需要 onchange 自动执行的命令则放在 — 后面。
Let’s add one more watch command to finish off our npm scripts build process.
安装多一个 package, parallelshell
再一次,添加新的任务到 scripts 对象上:
"scripts": { ... "watch:all": "parallelshell 'npm run serve' 'npm run watch:css' 'npm run watch:js'" }
|
parallelshell 允许我们同时执行多个任务,为什么不使用 && 呢?
因为 && 的执行顺序必须是前面的执行完了才轮到后面的任务,但是 watch 类型的任务永远不会完成啊~
现在 watch:all 任务开启服务器,并监听代码,一旦有变动,马上刷新浏览器 perfect!
Other useful tasks
npm 有很多其他任务。我们再写一个总的启动任务:
"scripts": { ... "postinstall": "npm run watch:all" }
|
npm install 之后就执行一下 postinstall 吧,这在团队开发中是很好的体验,克隆你代码的人执行 npm install 然后 马上 watch: all
Wrap Up
噢,我们做到了(终于翻译完了,好长的文章。。。),希望看完这篇文章你能学会使用 npm scripts
对了,我把代码都放在 npm-build-boilerplate 上了,欢迎交流。
译者的废话
最近看到关于 npm scripts 的字眼比较多,然后就找了篇文章翻译。
本文根据@Damon Bauer的文章所译,整篇译文带有我们自己的理解和意思,如果有译得不好的地方或者不对之处,还请大家指点。英文出处:Why npm Scripts?
如需转载,请注明出处: http://w3ctrain.com/2016/02/27/why-npm-scripts/ ,欢迎加入前端Q群( 467969149 )