Web应用的构建系统
---

> 构建系统(build system)是用来从源代码生成用户可以使用的目标的自动化工具。目标可以包括库、可执行文件、或者生成的脚本等等。

常用的构建工具包括GNU Make、GNU autotools、CMake、Apache Ant（主要用于JAVA）。此外，所有的集成开发环境（IDE）比如Qt Creator、Microsoft Visual Studio和Eclipse都对他们支持的语言添加了自己的构建系统配置工具。通常IDE中的构建系统只是基于控制台的构建系统（比如Autotool和CMake）的前端。

对比于Web应用开发来说，构建系统应该还包括应用打包(如Java中的Jar包，或者用于部署的RPM包、源代码分析、测试覆盖率分析等等。

###Web应用的构建过程

在刚创建项目的时候，我们都会有一个完整的构建思路。如下图便是这样的一个例子：

![构建过程](chapters/chapter3/build-web-project.png)

这是一个后台语言用的是Java，前台语言用的是JavaScript项目的构建流程。

**Compile**。对于那些不是用浏览器的前端项目来说，如ES6、CoffeeScript，他们还需要将代码编译成浏览器使用的JavaScript版本。对于Java语言来说，他需要一个编译的过程，在这个编译的过程中，会检查一些语法问题。

**Check Style**。通常我们会在我们的项目里定义一些代码规范，如JavaScript中的使用两个空格的缩进，Java的Checkstyle中一个函数不能超过30行的限制。

**单元测试**。作为测试中最基础也是最快的测试，这个测试将集中于测试单个函数的是不是正确的。

**功能测试**。功能测试的意义在于，保证一个功能依赖的几个函数组合在一起也是可以工作的。

**Mock Server**。当我们的代码依赖于第三方服务的时候，我们就需要一个Mock Server来保证我们的功能代码可以独立地测试。

**集成测试**。这一步将集成前台、后台，并且运行起最后将上线的应用。接着依据于用户所需要的功能来编写相应的测试，来保证一个个的功能是可以工作的。

**打包**。对于部署来说，直接安装一个RPM包，或者DEB包是最方便的事。在这个包里会包含应用程序所需的所有二进制文件、数据和配置文件等等。

**上传包**。在完成打包后，我们就可以上传这个软件包了。

**部署**。最后，我们就可以在我们的线上环境中安装这个软件包。

###Web应用的构建实战

下面就让我们来构建一个简单的Web应用，来实践一下这个过程。在这里，我们要使用到的一个工具是Gulp，当然对于Grunt也是类似的。

####Gulp入门指南

> Gulp.js 是一个自动化构建工具，开发者可以使用它在项目开发过程中自动执行常见任务。Gulp.js 是基于 Node.js 构建的，利用 Node.js 流的威力，你可以快速构建项目并减少频繁的 IO 操作。Gulp.js 源文件和你用来定义任务的 Gulp 文件都是通过 JavaScript（或者 CoffeeScript ）源码来实现的。

1. 全局安装 gulp：

```bash
$ npm install --global gulp
```

2. 作为项目的开发依赖（devDependencies）安装：

```bash
$ npm install --save-dev gulp
```

3. 在项目根目录下创建一个名为 gulpfile.js 的文件：

```javascript
var gulp = require('gulp');

gulp.task('default', function() {
  // 将你的默认的任务代码放在这
});
```

4. 运行 gulp：

```bash
$ gulp
```

默认的名为 default 的任务（task）将会被运行，在这里，这个任务并未做任何事情。接下来，我们就可以打造我们的应用的构建系统了。

####代码质量检测工具

当C还是一门新型的编程语言时，还存在一些未被原始编译器捕获的常见错误，所以程序员们开发了一个被称作lint的配套项目用来扫描源文件，查找问题。

对应于不同的语言都会有不同的lint工具，在JavaScript中就有JSLint。JavaScript是一门年轻、语法灵活多变且对格式要求相对松散的语言，因此这样的工具对于这门语言来说比较重要。

2011年，一个叫Anton Kovalyov的前端程序员借助开源社区的力量弄出来了JSHint，其思想基本上和JSLint是一致的，但是其有一下几项优势： 

 - 可配置规则，每个团队可以自己定义自己想要的代码规范。
 - 对社区非常友好，社区支持度高。
 - 可定制的结果报表。

下面就让我们来安装这个软件吧：

**安装及使用**

```bash
npm install jshint gulp-jshint --save-dev
```

示例代码:

```javascript
var jshint = require('gulp-jshint');
var gulp   = require('gulp');
 
gulp.task('lint', function() {
  return gulp.src('./lib/*.js')
    .pipe(jshint())
    .pipe(jshint.reporter('YOUR_REPORTER_HERE'));
});
```

####自动化测试工具

一般来说，自动测试应该从两部分考虑：

 - 单元测试
 - 功能测试

Mocha是一个可以运行在Node.js和浏览器环境里的测试框架，

```
var gulp = require('gulp');
var mocha = require('gulp-mocha');
 
gulp.task('default', function () {
	return gulp.src('test.js', {read: false})
		// gulp-mocha needs filepaths so you can't have any plugins before it 
		.pipe(mocha({reporter: 'nyan'}));
});
```

####编译

对于静态型语言来说，编译是一个很重要的步骤。不过，对于动态语言来说也存在这样的工具。

**动态语言的编译**

可以说这类型的语言，是以我们常见的JavaScript为代表。

1. CoffeeScript是一套JavaScript的转译语言，并且它增强了JavaScript的简洁性与可读性。

2. Webpack是一款模块加载器兼打包工具，它能把各种资源，例如JS（含JSX）、coffee、样式（含less/sass）、图片等都作为模块来使用和处理。

3. Babel是一个转换编译器，它能将ES6转换成可以在浏览器中运行的代码。

####打包

在GNU/Linux系统的软件包里通过包含了已压缩的软件文件集以及该软件的内容信息。常见的软件包有

1. DEB。Debian软件包格式，文件扩展名为.deb
2. RPM（原Red Hat Package Manager，现在是一个递归缩写）。该软件包分为二进制包（Binary）、源代码包（Source）和Delta包三种。二进制包可以直接安装在计算机中，而源代码包将会由RPM自动编译、安装。源代码包经常以src.rpm作为后缀名。
3. 压缩文档tar.gz。通常是该软件的源码，故而在安装的过程中需要编译、安装，并且在编译时需要自己手动安装所需要依赖的软件。在软件仓库没有最新版本的软件时，tar.gz往往是最好的选择。

由于这里的打包过程比较繁琐，就不介绍了。有兴趣的读者可以自己了解一下。

####上传及发布包

上传包之前我们需要创建一个相应的文件服务器，又或者是相应的软件源。并且对于我们的产品环境的服务器来说，我们还需要指定好这个软件源才能安装这个包。

以Ubuntu为例，Ubuntu里的许多应用程序软件包，是放在网络里的服务器上，这些服务器网站，就称作“源”，从源里可以很方便地获取软件包。

因而在这一步中，我们所需要做的事便是将我们打包完的软件上传到相应的服务器上。
