1.什么是构建工具
比如我们执行一些例如CoffeeScript/ES6 去代替 Javascript、JS或CSS压缩、用Less去写CSS、用Jade去写HTML、用Browserify去模块化、为非覆盖式部署的资源加MD5戳等,这些操作如果我们一遍遍手动执行,非常耗费时间和精力,所以前端构建工具,或者较前端自动化构建工具,就是用来让我们不再做机械重复的事情,解放我们的双手的。
以gulp为例,编写gulpfile.js
例如:
gulp = require('gulp')
coffee = require('gulp-coffee')
uglify = require('gulp-uglify')
rename = require('gulp-rename')
file = './src/js/a.coffee'
gulp.task('coffe',function(){
gulp.src(file)
.pipe(coffee()) //编译
.pipe(uglify()) //压缩
.pipe(rename({
extname:".min.js" //重命名
}))
.pipe(gulp.dest('./build/js'))
})
gulp.task('watch',function(
gulp.watch(file,['coffee'])
))
gulp.task('default',['coffee'])
这样,我只要执行一下 gulp watch,它就可以自动监视 a.coffee 的变化,每次修改 a.coffee 并保存后,它就会自动执行编译->压缩丑化->重命名这一系列动作了。
参考文章:https://www.zhihu.com/question/35595198
2.构建工具的发展
构建其实是工程化、自动化思想在前端开发中的体现,将一系列流程用代码去实现,让代码自动化地执行这一系列复杂的流程。
构建可以实现如下内容:
- 代码转换:将 TypeScript/es6 编译成JavaScript、将 SCSS 编译成 CSS等。
- 文件优化:压缩JavaScript、CSS、HTML 代码,压缩合并图片等。
- 代码分割:提取多个页面的公共代码,提取首屏不需要执行部分代码让其异步记在。
- 模块合并:在采用模块化的项目里会有很多个模块和文件,需要通过构建功能将模块分类合并成一个文件。
- 自动刷新:监听本地源代码变化,自动重新构建、刷新浏览器。
- 代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
- 自动发布:更新代码后,自动构建出线上发布代码并传输给发布系统。
构建工具发展:Npm Scripts、Grunt、Gulp、FIS 3、Webpack、Rollup、Parcel
Grunt:
Grunt 的优点是:
- 灵活,它只负责执行我们定义好的任务;
- 大量可复用插件封装好了常见的构建任务。
Grunt 的缺点是集成度不高,要写很多配置后才可以用,无法做到开箱即用。
Grunt 相当于进化版的 Npm scripts,它的诞生其实是为了弥补 Npm Scripts 的不足。
Gulp:
Gulp 是一个基于流的自动化构建工具。除了可以管理任务和执行任务,还支持监听文件、读写文件。Gulp 被设计的非常简单,只通过下面5个方法就可以支持几乎所有构建场景:
- 通过 gulp.task 注册一个任务;
- 通过 gulp.run 执行任务;
- 通过 gulp.watch 监听文件变化;
- 通过 gulp.src 读取文件;
- 通过 gulp.dest 写完文件。
// 引入 Gulp
var gulp = require("gulp");
// 引入插件
var jshint = require("gulp-jshint");
var sass = require("gulp-sass");
var concat = require("gulp-concat");
....
// 便宜SCSS任务
gulp.task('scss', function() {
// 读取文件,通过管道喂给插件
gulp.src('./scss/*.scss')
// SCSS 插件将 scss 文件编译成 css
.pipe(sass())
// 输出文件
.pipe(guilp.dest('./css'));
});
// 合并压缩 JavaScript 文件
gulp.task('scripts', function() {
gulp.src('./js/*.js')
.pipe(concat('all.js'))
.pipe(uglify())
.pipe(gulp.dest('./dest'));
});
// 监听文件变化
gulp.task('watch', function() {
// 当 SCSS 文件被编辑时执行 SCSS 任务
gulp.watch('./scss/*.scss', ['sass']);
gulp.watch('./js/*.js', ['scripts']);
});
Gulp 的优点:好用又不失灵活,既可以单独完成构建,也可以和其他工具搭配使用。
缺点:和Grunt 类似。集成度不高,要写很多配置后才可以用,无法做到开箱即用。
可以将Gulp 看做是 Grunt 的加强版。相对于 Grunt ,Gulp 增加了文件监听、读写文件、流式处理的功能。
FIS 3:
Fis3是一个来自百度的优秀国产构建工具。相对于 Grunt、Gulp 这些只提供了基本功能的工具。Fis3集成了开发者常用的构建功能,如下所述。
- 读写文件:通过 fis.match 读文件,release 配置文件输出路径。
- 资源定位:解析文件之间的依赖关系和文件位置。
- 文件指纹:在通过 useHash 配置输出文件时为文件 URL加上 md5 戳,来优化浏览器的缓存。
- 文件编译:通过 parser 配置文件解析器做文件转换,例如将 ES6 编译成 ES5。
- 压缩资源:通过 optimizer 配置代码压缩方法。
- 图片合并:通过 spriter 配置合并 CSS 里导入的图片到一个文件中,来减少 HTTP 请求数。
大致使用如下:
// 加 md5
fis.match('*.{js,css,png}', {
useHash: true
});
// 通过fis3-parse-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。
Webpack:
Webpack 是一个打包模块化的JavaScript的工具,在Webpack里一切文件皆模块,通过 loader 转换文件,通过Plugin 注入钩子,最后输出由多个模块组合成的文件。Webpack 专注于构建模块化项目。
其官网的首页图很形象的展示了 Webpack 的定义,如下图:
一切文件,如JavaScript、CSS、SCSS、图片、模板,对于Webpack 来说都是一个个模块,这样的好处是能清晰地描绘各个模块之间的依赖关系,以方便Webpack进行组合和打包,经过Webpack的处理,最终会输出浏览器能使用的静态资源。
Webpack具有很大的灵活性,能配置处理文件的方式,使用方法大致如下:
module.exports = {
// 所有模块的入口,webpack从入口开始递归解析出所有依赖的模块
entry: './app.js',
output: {
// 将入口所依赖的所有模块打包成一个文件 bundle.js 输出
filename: 'bundle.js'
}
}
Webpack的优点是:
- 专注于处理模块化的项目,能做到开箱即用、一步到位;
- 可通过 Plugin 扩展,完整好用又不失灵活性;
- 使用场景不局限于Web开发;
- 社区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展;
- 良好的开发体验;
Webpack的缺点是:只能用于采用模块化开发的项目。
Rollup:
Rollup 是一个和 Webpack 很类似但专注于ES6的模块打包工具。它的亮点在于,针对ES6源码进行 Tree Shaking,以去除那些已经被定义但没被使用的代码并进行 Scope Hoisting,以减少输出文件的大小和提升运行性能。然而 Rollup 的这些亮点随后就被 Webpack 模仿和实现了。
Parcel:
Parcel 是 最近新起的Web 应用打包工具,适用于经验不同的开发者。它利用多核处理提供了极快的速度,并且不需要任何配置。
Parcel的优点:
- 极速打包。Parcel 使用 worker 进程去启用多核编译。同时有文件系统缓存,即使在重启构建后也能快速再编译。
- 开箱即用。对 JS, CSS, HTML, 文件 及更多的支持,而且不需要插件。
- 自动转换。如若有需要,Babel, PostCSS, 和PostHTML甚至 node_modules 包会被用于自动转换代码。
-热模块替换。Parcel 无需配置,在开发环境的时候会自动在浏览器内随着你的代码更改而去更新模块。
友好的错误日志。当遇到错误时,Parcel 会输出 语法高亮的代码片段,帮助你定位问题。
缺点:
- 不支持SourceMap:在开发模式下,Parcel也不会输出SourceMap,目前只能去调试可读性极低的代码;
- 不支持剔除无效代码(TreeShaking):很多时候我们只用到了库中的一个函数,结果Parcel把整个库都打包了进来;
- 一些依赖会让Parcel出错:当你的项目依赖了一些Npm上的模块时,有些Npm模块会让Parcel运行错误;
- Parcel需要为零配置付出代价。零配置其实是把各种常见的场景做为默认值来实现的,
这虽然能节省很多工作量,快速上手,但这同时会带来一些问题:
- 不守规矩的node_module:有些依赖的库在发布到Npm上时可能不小心把.babelrcpostcss.config.js tsconfig.json这些配置文件也一起发布上去了,
- 不灵活的配置:零配置的Parcel关闭了很多配置项,在一些需要的配置的场景下无法改变。
Parcel使用场景受限。目前Parcel只能用来构建用于运行在浏览器中的网页,这也是他的出发点和专注点。在软件行业不可能存在即使用简单又可以适应各种场景的方案,就算所谓的人工智能也许能解决这个问题,但人工智能不能保证100%的正确性。
反观Webpack除了用于构建网页,还可以做:
- 打包发布到Npm上的库
- 构建Node.js应用(同构应用)
- 构建Electron应用
- 构建离线应用(ServiceWorkers)
Parcel与Webpack的对比:http://www.cnblogs.com/lxg0/p/8387670.html
3.为什么选择Webpack
上面介绍的构建工具是按照他们的诞生时间排序的,他们是时代的产物,侧面反映出 Web 开发的发展趋势,如下所述:
- 在 Npm Scripts 和 Grunt 时代,Web 开发要做的事情变多,流程复杂,自动化思想被引入,用于简化流程;
- 在 Gulp 时代,开始出现一些新语言用于提高开发效率,流程处理思想的出现是为了简化文件转换的流程,例如将ES6转换为ES5;
- 在Webpack时代,由于单页应用的流行,网页的功能和实现代码变的复杂、庞大,Web开发向模块化改进。
这些构建工具都有各自的定位和专注点,它们之间既可以单独完成任务,也可以互相搭配起来弥补各自的不足。在了解这些常见的构建工具后,我们需要根据自己的需求去判断应该如何进行选择和搭配它们才能更好的满足自己的需求。
经过多年的额发展,Webpack 已经成为构建工具中的首选,这是因为:
- 大多数团队在开发新项目时会采用紧跟时代的技术,这些技术几乎都会采用“模块化+新语言+新框架”,Webpack可以为这些新项目提供一站式的解决方案;
- Webpack有良好的生态和维护团队,能提供良好的开发体验并保证质量;
- Webpack 被全世界大量的Web开发者使用和验证,能找到各个层面所需要的教程和经验分享。
4.Gulp和Webpack的区别
常有人拿gulp与webpack来比较,知道这两个构建工具功能上有重叠的地方,可单用,也可一起用,但本质的区别就没有那么清晰。
Gulp强调的是前端开发的工作流程,我们可以通过配置一系列的task,定义task处理的事务(例如文件压缩合并、雪碧图、启动server、版本控制等),然后定义执行顺序,来让gulp执行这些task,从而构建项目的整个前端开发流程。 简单说就一个Task Runner,就是用来跑一个一个任务的。
Gulp 没发解决的是 js module 的问题,是你写代码时候如何组织代码结构的问题。
Webpack是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图片、js文件、css文件等)都看成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源。
相同点:文件合并与压缩(css,js),sass/less预编译,启动server,版本控制。
不同点,虽然都是前端自动化构建工具,但看他们的定位就知道不是对等的。
- gulp严格上讲,模块化不是他强调的东西,他旨在规范前端开发流程。
- webpack更是明显强调模块化开发,而那些文件压缩合并、预处理等功能,不过是他附带的功能。
参考文章:
https://juejin.im/entry/5ae5c8c9f265da0b9f400d8e
https://www.cnblogs.com/iovec/p/7921177.html
支付宝前端构建工具的发展和未来的选择:https://github.com/pigcan/blog/issues/4
5.为什么node出现之后,各种前端构建工具和手段才如雨后春笋般层出不穷
https://www.zhihu.com/question/35427358
6.browserify
服务器端NodeJS自带模块功能,可以使用require和module.exports构建项目
随着项目的增大,浏览器端任务越来越重,依赖关系越来越复杂,需要使用工具实现模块化。
Browserify通过require和module.exports来导入和导出。
Browserify的原理:部署时处理代码依赖,将模块打包为一个文件。
参考文章:
https://blog.youkuaiyun.com/real_bird/article/details/53560206?utm_source=copy