前端开发工具库[第一期]-npm script

在自动构建工具grunt\webpack等红噪一时的背景下,为什么我想用npm script而不是grunt和gulp等其他工具?

前言

为什么我们需要自动构建工具?

在前端开发的时候,会遇到很多实际产品开发之外上的需求,比如开发者希望做到“所写即所得”,可以一边在编辑器里面修改和开发代码,浏览器可以同步更新而不需要我们手动去refresh页面; 比如我们希望可以压缩最后的成品代码, 图片资源的大小,让每次浏览器下载所需要的js代码的时间可以更短,或者考虑CDN; 比如我们希望我们写的scss可以适配任何类型的浏览器等等。

很多功能曾经是要开发者手动引入script文件的,但鉴于npm上活跃的开发者将很多需求的module开发并发布出来, 我们可以利用npm这个包管理器来配置使用这些方便的module,在能够达到同样功能的工具里面比如bower, grunt, gulp,我认为对于一个轻量的小项目, 个人项目来说, npm script是最方便的, 最容易上手的。没有最好的工具, 只有最合适的使用场景。

而今天的主题:在配置工具grunt\webpack等红噪一时的背景下,为什么我想用npm script而不是grunt和gulp等其他工具?

因为simplicity matters。没有必要在需要用的时候才去找那些数量有限的grunt, gulp plugins,而直接将node modules拿来用。对于个人开发和维护的小项目, 有没有必要花时间去研究Gruntfile.js怎么去配置, 或者说, 在配置上花的时间相对短期集中开发的时间来说值不值?不是说反对使用grunt, gulp和webpack等工具, 而是我们没有必要拿大炮去打蚊子, 我们想要agile development。 也正是simplicy, 所以才有RoR, meteor等全栈框架的出现来挑战java等较为臃肿的开发流程不是么?

下图是截止至今年1月为止的各平台的插件数量,仍在不断地增加中。

npm script

什么是npm script

其实npm script就是希望执行的command的alias, 类似与command line里面的make, 通过提前设置希望执行的命令, 我们可以通过npm run <alias>来执行我们预先设置的命令。 还有一些特别方便的commands比如:

  • npm home request, 可以直接跳转到那个module的介绍页面;
  • npm install request --save可以将我们使用的modules以“^”形式保存在package.json文件里面, 这意味着下一次用同一个package.json安装依赖模块时, 没有经过major version jump的模块可以下载到本地项目目录;
  • npm install --production可以安装生产环境的模块, 同NODE_ENV=production npm install

如何config你的npm script

而目前npm上有很多很棒的module可以直接处理项目, 下面列出来的是我平时自己经常使用的module:

比如: browserfy将文件的各种文件和浏览器同步; postcss和autofixer可以将css文件添加适配各种浏览器的前缀同时进行压缩; js-lint用来检查js文件的各种格式细节; uglify用来压缩js文件的大小; imagemin用来压缩各种图片文件的大小, 在各种大型网站中, 图片的大小占据了大部分。

node-sass

下面是一些具体使用的例子:比如我们想将sass compile成css。

1
npm install --save-dev node-sass

node-sass这个module装在developing环境之后,可以直接node-sass --output-style compressed -o dist/css src/scss来将”src/scss“这个文件夹下面的sass文件compile出来并保存在”dist/css“文件夹下面; 或者一个更便捷的做法,是使用npm script:

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

然后在console里run npm run scss就可以执行这个相同命令了。和makefile的原理和使用习惯可以类比, 只不过使用场景和平台不同。

autoprefixer

同理对上文提到的autoprefixer这个module, npm install --save-dev postcss-cli autoprefixer来安装, 然后配置script:

1
2
3
4
"scripts": {
...
"autoprefixer": "postcss -u autoprefixer -r dist/css/*"
}

那么npm run autoprefixer这个效果就相当于postcss -u autoprefixer --autoprefixer.browsers '> 5%, ie 9' -r dist/css/*

eslint

类似地还有eslint这个对js文件进行syntax testing的常用module:npm install --save-dev eslint或者使用shortcut:npm i -D eslint, 然后配置package.json的script部分:

1
2
3
4
"scripts": {
...
"lint": "eslint src/js"
}

项目源代码示例

一个实战项目的源代码使用在这里和大家分享:

考虑到开发和生产环境的不同,还需要配置不同的环境,这个项目在开发上有浏览器同步更新,语法检查,压缩源文件, 监听端口, s3同步备份的自动化优势, 还引入了前端的jade框架代替html, stylus框架代替css,mocha的testing框架和karma驱动。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
"name": "npm-scripts-example",
"version": "1.0.0",
"description": "An example of how to use npm scripts",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"browserify": "^6.3.2",
"hashmark": "^2.0.0",
"http-server": "^0.7.3",
"jade": "^1.7.0",
"jshint": "^2.5.10",
"karma": "^0.12.28",
"karma-browserify": "^1.0.0",
"karma-cli": "^0.0.4",
"karma-mocha": "^0.1.10",
"karma-phantomjs-launcher": "^0.1.4",
"live-reload": "^0.2.0",
"minifyify": "^6.0.0",
"mocha": "^2.0.1",
"nodemon": "^1.2.1",
"opener": "^1.4.0",
"parallelshell": "^1.0.0",
"rimraf": "^2.2.8",
"s3-cli": "^0.11.1",
"stylus": "^0.49.3"
},
"scripts": {
"clean": "rimraf dist/*",

"prebuild": "npm run clean -s",
"build": "npm run build:scripts -s && npm run build:styles -s && npm run build:markup -s",
"build:scripts": "browserify -d assets/scripts/main.js -p [minifyify --compressPath . --map main.js.map --output dist/main.js.map] | hashmark -n dist/main.js -s -l 8 -m assets.json 'dist/{name}{hash}{ext}'",
"build:styles": "stylus assets/styles/main.styl -m -o dist/ && hashmark -s -l 8 -m assets.json dist/main.css 'dist/{name}{hash}{ext}'",
"build:markup": "jade assets/markup/index.jade --obj assets.json -o dist",

"test": "karma start --singleRun",

"watch": "parallelshell \"npm run watch:test -s\" \"npm run watch:build -s\"",
"watch:test": "karma start",
"watch:build": "nodemon -q -w assets/ --ext '.' --exec 'npm run build'",

"open:prod": "opener http://example.com",
"open:stage": "opener http://staging.example.internal",
"open:dev": "opener http://localhost:9090",

"deploy:prod": "s3-cli sync ./dist/ s3://example-com/prod-site/",
"deploy:stage": "s3-cli sync ./dist/ s3://example-com/stage-site/",

"serve": "http-server -p 9090 dist/",
"live-reload": "live-reload --port 9091 dist/",

"dev": "npm run open:dev -s && parallelshell \"npm run live-reload -s\" \"npm run serve -s\" \"npm run watch -s\""
}
}

很多时候就是因为准备的工具效率高, 开发者也因此得以集中精力于产品逻辑, 在更短的时间内开发出更好更稳定的产品。

后记小结

npm script不是没有缺点的,就像我一再强调的,没有最好的工具, 只有最合适的使用场景, 在个人小项目适合的npm script,在大项目, 动辄几十万的前端项目的构建和测试下, npm script会显得特别臃肿和难以维护。 而目前大热的grunt\gulp\webpack也迎来了他们的舞台。下一期,集中介绍grunt和webpack,公司里使用的也是grunt,为什么它会在众多工具中脱颖而出。

参考链接

一起加油!