在阅读完上一节1-1前端的发展后你一定会感叹前端技术发展之快,各种可以提高开发效率的新思想和框架被发明。但是这些东西都有一个共同点:源代码无法直接运行,必须通过转换后才可以正常运行。
构建就是做这件事情,把源代码转换成发布到线上的可执行 JavaScrip、CSS、HTML 代码,包括如下内容。
构建其实是工程化、自动化思想在前端开发中的体现,把一系列流程用代码去实现,让代码自动化地执行这一系列复杂的流程。 构建给前端开发注入了更大的活力,解放了我们的生产力。
历史上先后出现一系列构建工具,它们各有其优缺点。由于前端工程师很熟悉 JavaScript ,Node.js 又可以胜任所有构建需求,所以大多数构建工具都是用 Node.js 开发的。下面来一一介绍它们。
Npm Script 是一个任务执行者。Npm 是在安装 Node.js 时附带的包管理器,Npm Script 则是 Npm 内置的一个功能,允许在 package.json
文件里面使用 scripts
字段定义任务:
{
"scripts": {
"dev": "node dev.js",
"pub": "node build.js"
}
}
里面的 scripts
字段是一个对象,每个属性对应一段 Shell 脚本,以上代码定义了两个任务 dev
和 pub
。
其底层实现原理是通过调用 Shell 去运行脚本命令,例如执行 npm run pub
命令等同于执行命令 node build.js
。
Npm Script的优点是内置,无须安装其他依赖。其缺点是功能太简单,虽然提供了 pre
和 post
两个钩子,但不能方便地管理多个任务之间的依赖。
Grunt 和 Npm Script 类似,也是一个任务执行者。Grunt 有大量现成的插件封装了常见的任务,也能管理任务之间的依赖关系,自动化执行依赖的任务,每个任务的具体执行代码和依赖关系写在配置文件 Gruntfile.js
里,例如:
module.exports = function(grunt) {
// 所有插件的配置信息
grunt.initConfig({
// uglify 插件的配置信息
uglify: {
app_task: {
files: {
'build/app.min.js': ['lib/index.js', 'lib/test.js']
}
}
},
// watch 插件的配置信息
watch: {
another: {
files: ['lib/*.js'],
}
}
});
// 告诉 grunt 我们将使用这些插件
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
// 告诉grunt当我们在终端中启动 grunt 时需要执行哪些任务
grunt.registerTask('dev', ['uglify','watch']);
};
在项目根目录下执行命令 grunt dev
就会启动 JavaScript 文件压缩和自动刷新功能。
Grunt的优点是:
Grunt的缺点是集成度不高,要写很多配置后才可以用,无法做到开箱即用。
Grunt 相当于进化版的 Npm Script,它的诞生其实是为了弥补 Npm Script 的不足。
Gulp 是一个基于流的自动化构建工具。 除了可以管理和执行任务,还支持监听文件、读写文件。Gulp 被设计得非常简单,只通过下面5种个方法就可以胜任几乎所有构建场景:
gulp.task
注册一个任务;gulp.run
执行任务;gulp.watch
监听文件变化;gulp.src
读取文件;gulp.dest
写文件。Gulp 的最大特点是引入了流的概念,同时提供了一系列常用的插件去处理流,流可以在插件之间传递,大致使用如下:
// 引入 Gulp
var gulp = require('gulp');
// 引入插件
var jshint = require('gulp-jshint');
var sass = require('gulp-sass');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
// 编译 SCSS 任务
gulp.task('sass', function() {
// 读取文件通过管道喂给插件
gulp.src('./scss/*.scss')
// SCSS 插件把 scss 文件编译成 CSS 文件
.pipe(sass())
// 输出文件
.pipe(gulp.dest('./css'));
});
// 合并压缩 JS
gulp.task('scripts', function() {
gulp.src('./js/*.js')
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
// 监听文件变化
gulp.task('watch', function(){
// 当 scss 文件被编辑时执行 SCSS 任务
gulp.watch('./scss/*.scss', ['sass']);
gulp.watch('./js/*.js', ['scripts']);
});
Gulp 的优点是好用又不失灵活,既可以单独完成构建也可以和其它工具搭配使用。其缺点是和 Grunt 类似,集成度不高,要写很多配置后才可以用,无法做到开箱即用。
可以将Gulp 看作 Grunt 的加强版。相对于 Grunt,Gulp增加了监听文件、读写文件、流式处理的功能。
Fis3 是一个来自百度的优秀国产构建工具。相对于 Grunt、Gulp 这些只提供基本功能的工具,Fis3 集成了 Web 开发中的常用构建功能,如下所述。
fis.match
读文件,release
配置文件输出路径。useHash
配置输出文件时给文件 URL 加上 md5 戳来优化浏览器缓存。parser
配置文件解析器做文件转换,例如把 ES6 编译成 ES5。optimizer
配置代码压缩方法。spriter
配置合并 CSS 里导入的图片到一个文件来减少 HTTP 请求数。大致使用如下:
// 加 md5
fis.match('*.{js,css,png}', {
useHash: true
});
// fis3-parser-typescript 插件把 TypeScript 文件转换成 JavaScript 文件
fis.match('*.ts', {
parser: fis.plugin('typescript')
});
// 对 CSS 进行雪碧图合并
fis.match('*.css', {
// 给匹配到的文件分配属性 `useSprite`
useSprite: true
});
// 压缩 JavaScript
fis.match('*.js', {
optimizer: fis.plugin('uglify-js')
});
// 压缩 CSS
fis.match('*.css', {
optimizer: fis.plugin('clean-css')
});
// 压缩图片
fis.match('*.png', {
optimizer: fis.plugin('png-compressor')
});
可以看出 Fis3 很强大,内置了许多功能,无须做太多配置就能完成大量工作。
Fis3的优点是集成了各种 Web 开发所需的构建功能,配置简单开箱即用。其缺点是目前官方已经不再更新和维护,不支持最新版本的 Node.js。
Fis3 是一种专注于 Web 开发的完整解决方案,如果将 Grunt、Gulp 比作汽车的发动机,则可以将Fis3 比作一辆完整的汽车。
Webpack 是一个打包模块化 JavaScript 的工具,在 Webpack 里一切文件皆模块,通过 Loader 转换文件,通过 Plugin 注入钩子,最后输出由多个模块组合成的文件。Webpack 专注于构建模块化项目。 大致使用如下:
module.exports = {
// 所有模块的入口,Webpack 从入口开始递归解析出所有依赖的模块
entry: './app.js',
output: {
// 把入口所依赖的所有模块打包成一个文件 bundle.js 输出
filename: 'bundle.js'
}
}
Webpack的优点是:
Webpack的缺点是只能用于采用模块化开发的项目。
Rollup 是一个和 Webpack 很类似但专注于 ES6 的模块打包工具。 Rollup 的亮点在于能针对 ES6 源码进行 Tree Shaking 去除那些已被定义但没被使用的代码,和 Scope Hoisting 减小输出文件大小提升运行性能。 然而 Rollup 的这些亮点随后就被 Webpack 模仿和实现。 由于 Rollup 的使用和 Webpack 差不多,这里就不详细介绍如何使用了,而是详细说明它们的差别:
Rollup 在用于打包 JavaScript 库时比 Webpack 更加有优势,因为其打包出来的代码更小更快。 但功能不够完善,很多场景都找不到现成的解决方案。
上面介绍的构建工具是按照它们诞生的时间排序的,它们是时代的产物,侧面反映出 Web 开发的发展趋势如下:
这些构建工具都有各自的定位和专注点,它们之间既可以单独地完成任务,也可以相互搭配起来弥补各自的不足。 在了解这些常见的构建工具后,你需要根据自己的需求去判断应该如何选择和搭配它们才能更好地完成自己的需求。
经过多年的发展, Webpack 已经成为构建工具中的首选,这是有原因的:
下面开始跨入 Webpack 的大门吧!