为什么要自动化

你好,切图仔!

现在的前端早已不是简单的静态页面开发,一些大型的 Web App 动辄几千行甚至上万行代码,所以如何构建本地开发环境尤为重要。本篇文章将以 gulp 为例,从编译、文件合并、文件压缩、单元测试等几个角度从零开始搭建一个简单的前端开发环境。

Github 地址:gulp-demo

最佳实践

抛开项目类型,一个项目 Js 文件和目录结构应该有以下几个特点:

  • 一个文件只包含一个对象
  • 相关的文件用目录分组
  • 保持第三方代码的独立
  • 确定创建文位置
  • 保持测试代码的完整性

以 jQuery 项目的目录结构为例



build:用来放置最终构建后的文件(不应该被提交)
src:用来放置所有的源文件,包括用例进行文件分组的子目录
test:用来放置测试文件,包含一些同源代码目录对应的子目录或文件
external:用来存放一些外部拓展文件
Gruntfile.js:grunt 配置文件,用来配置或定义任务并加载 Grunt 插件
package.json:描述了一个 NPM 包的所有相关信息
.eslintrc:Eslint 配置文件

从零开始

创建一个 Gulp 项目

假设你已经安装了 Node,通过npm init初始化一个package.json文件 ,然后新建一个gulpfile.js文件,执行npm install grunt --save-dev安装 Gulp。

1
2
3
4
//gulpfile.js
var gulp = require('gulp');

gulp.task('default', function() {});

运行 gulp

1
$ gulp

使用命令gulp会使默认是的名为 default 的任务(task)将会被运行,此示例未做任何事情。

ESLint

在团队开发中,编程风格(style guideline)和编码规范(code convention)的一致性是及其重要的,即时是缩进统一,也会给后期维护节省大量的时间成本。所以使用像 ESLint 这样的工具是很有必要的,不仅可以找出代码中潜在的错误,而且能针对你的代码给出编程风格上的警告。

安装 gulp-eslint

1
$ npm i --save-dev gulp-eslint

gulpfile添加 lint 任务

1
2
3
4
5
6
gulp.task('lint', function() {
return gulp
.src(['**/*.js', '!node_modules/**'])
.pipe(eslint())
.pipe(eslint.formatEach('compact', process.stderr));
});

使用 gulp-concat 和 gulp-uglify 合并压缩

如果恰当的组织 javaScript 文件,那么每个文件就只包含一个对象,但是会带来一个问题,就是会增加网络请求数。所以应该将文件合并,合并之后进行压缩工作,尽可能的缩小文件大小。

安装 gulp-concat 和 gulp-uglify

1
$ npm i --save-dev gulp-concat gulp-uglify

添加 javaScript 任务到gulpfile.js

1
2
3
4
5
6
7
8
9
gulp.task('javascript', ['lint'], function() {
return gulp
.src('src/**/*.js')
.pipe(sourcemaps.init())
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist'));
});

然后修改gulp.task(..)

1
gulp.task('default', ['lint', 'javascript'], function() {});

合并和压缩任务添加结束之后我们可以在src文件夹里尝试一下,添加add.jsmultiply.js

1
2
3
4
5
6
//add.js
var add = function(x, y) {
return x + y;
};

module.exports = add;
1
2
3
4
5
6
//multiply.js
var multiply = function(x, y) {
return x * y;
};

module.exports = multiply;

执行gulp,控制台会输出如下内容,项目目录会生成dist文件夹,里面存放压缩并合并后的all.js文件

1
2
3
4
5
6
7
8
$ gulp
[21:23:44] Using gulpfile gulpfile.js
[21:23:44] Starting 'lint'...
1 problem[21:23:45] Finished 'lint' after 657 ms
[21:23:45] Starting 'javascript'...
[21:23:45] Finished 'javascript' after 57 ms
[21:23:45] Starting 'default'...
[21:23:45] Finished 'default' after 29 μs
1
2
3
//all.js
var add=function(r,t){return r+t};module.exports=add;var multiply=function(r,t){return r*t};module.exports=multiply;
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImFkZC5qcyIsIm11bHRpcGx5LmpzIl0sIm5hbWVzIjpbImFkZCIsIngiLCJ5IiwibW9kdWxlIiwiZXhwb3J0cyIsIm11bHRpcGx5Il0sIm1hcHBpbmdzIjoiQUFBQSxJQUFBQSxJQUFBLFNBQUFDLEVBQUFDLEdBQ0EsT0FBQUQsRUFBQUMsR0FHQUMsT0FBQUMsUUFBQUosSUNKQSxJQUFBSyxTQUFBLFNBQUFKLEVBQUFDLEdBQ0EsT0FBQUQsRUFBQUMsR0FHQUMsT0FBQUMsUUFBQUMiLCJmaWxlIjoiYWxsLmpzIiwic291cmNlc0NvbnRlbnQiOlsidmFyIGFkZCA9IGZ1bmN0aW9uKHgsIHkpIHtcclxuXHRyZXR1cm4geCArIHk7XHJcbn07XHJcblxyXG5tb2R1bGUuZXhwb3J0cyA9IGFkZDtcclxuIiwidmFyIG11bHRpcGx5ID0gZnVuY3Rpb24oeCwgeSkge1xyXG5cdHJldHVybiB4ICogeTtcclxufTtcclxuXHJcbm1vZHVsZS5leHBvcnRzID0gbXVsdGlwbHk7XHJcbiJdfQ==

自动化测试

安装 gulp-mocha 和 chai ,前者是一款测试框架,就是运行测试的工具,在浏览器和 Node 环境都可以使用,添加测试,从而保证代码的质量。chai 是一款 js 断言库,就是判断源码的实际执行结果与预期结果是否一致。

1
$ npm i --save-dev gulp-mocha chai

add.jsmultiply.js添加测试脚本add.test.jsmultiply.test.js

1
2
3
4
5
6
7
8
9
//add.test.js
var add = require('../src/add.js');
var expect = require('chai').expect;

describe('加法函数的测试', function() {
it('1 加 1 应该等于 2', function() {
expect(add(1, 1)).to.be.equal(2);
});
});
1
2
3
4
5
6
7
8
9
//multiply.test.js
var multiply = require('../src/multiply.js');
var expect = require('chai').expect;

describe('乘法函数的测试', function() {
it('2 乘 2 应该等于 4', function() {
expect(multiply(2, 2)).to.be.equal(4);
});
});

describe块称为”测试套件”(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称(”加法函数的测试”),第二个参数是一个实际执行的函数。
it块称为”测试用例”(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称(”1 加 1 应该等于 2”),第二个参数是一个实际执行的函数。

添加 gulp 任务

1
2
3
4
5
6
7
gulp.task('test', function() {
return gulp.src('test/*.test.js', { read: false }).pipe(
mocha({
reporter: 'spec'
})
);
});

执行gulp test,如下输出

1
2
3
4
5
6
7
[21:37:31] Starting 'test'...
加法函数的测试
√ 1 加 1 应该等于 2
乘法函数的测试
√ 2 乘 2 应该等于 4
2 passing (6ms)
[21:37:32] Finished 'test' after 502 ms

表示测试通过

Webpack

Webpack 是一款优秀的前端模块打包器,它可以找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript 等),并将其转换和打包为合适的格式供浏览器使用。与 Gulp/Grunt 相比,Gulp/Grunt 是一种能够优化前端开发流程的工具,Webpack 是一种模块化的解决方案,同时 Webpack 在很多场景下可以替代 Gulp/Grunt 这类工具。所以 Webpack 是非常值得学习的。

总结

这篇文章是在读完 《编写可维护的 JavaScript》 这本书之后,做的总结性实践类文章。总之,如今的前端工程化完善,本文的例子只是很简单的内容,gulp的具体使用,复杂应用的测试等内容还有待深入。

Github 地址:gulp-demo

Reference:
Gulp 中文网
测试框架 Mocha 实例教程