造轮子:基于Gulp搭建一套前端自动化工程模板
前端这几年的发展可以说非常迅速,如今的Web前端,已经不同于早期的 Div + Css 模式了,简单的掌握 Div + Css 并不能胜任日益复杂的前端业务需求。正因如此,前端开发的工程化,流程化和自动化逐渐变成必然的需求。
简述
在前端工程化方面,可以选择的辅助工具非常多,常见和常用的有 Babel、webpack、grunt、browserify、gulp等。这些工具各有侧重点,babel主要用来将ES6及以上的高级语法特性转换成目前浏览器可以识别的ES5语言;webpack是一个模块化打包工具,可以将前端零碎的页面和组件打包在一起进行发布;grunt是早期前端自动化工具,可以在后台为开发人家提供自动转码等效率服务;browserify也是一个前端打包工具,主要用来将Js代码打包成可以在浏览器上运行的脚本;gulp与grunt类似,但是更精简,生态好于grunt。
本系列的文章主要想介绍一下基于gulp的流程化工程的搭建。
webpack 与 gulp
webpack
和 gulp
是目前比较流行的两种前端自动化和打包工具,webpack 像大哥,gulp 像小弟,虽然工程上使用webpack 更多一些,但 gulp 也有其自己的优势。
webpack 更加完善,大而全,对用户来说可以不用编写过多的脚本,只需要完成在 webpack.config.js
的配置即可,一定程度上 webpack 更像一个黑箱,他能做许多事情,但你却不知道为什么以及怎么做的。
gulp相比而言则更觉小而美,用户需要自己完成对构建过程的搭建,基于gulp提供的流的概念,用户可以自行组织和管理各个流模块,俗话说条条大路通罗马,在gulp上,完成工程自动化的方式也可谓多种多样,而这些,都可以让用户自己掌控。所以相比webpack的黑箱,gulp的可编辑性更好,用户可以自己构建,进而掌握构建过程中的任何细节。
但是,webpack 毕竟是大哥,大哥的地位是很难撼动的。webpack 目前在前端工程化中广泛应用,尤其是 webpack + vue 和 webpack + react,这种捆绑就类似于 WindowsXP + IE6 一样,即便你不想使用 IE6,但也得使用Windows,这是无奈的一面,但另一面,webpack并不能类比于IE6,webpack并不是前端噩梦,而是让前端在某种程度上脱离噩梦,webpack + vue 和 webpack + react 更像是强强联合,在这一点上,webpack模块化的处理哲学便体现的淋漓尽致。以 vue 举例,vue可以方便的构建单页面web应用(SPA),并将页面中用到的模块进行组件化,组件化的概念与webpack模块化的概念非常类似,所以在构建单页面Web应用上,webpack更强大和实用。
相比webpack的模块化,gulp在这方面就略显逊色。gulp突出的不是模块化,而是流程化,重点体现在 “流” 上。以编译 Less 文件为例,gulp的流可以先将 less 文件读取,然后交由 less 插件编译成 css 文本,然后在交给 minicss 插件将css文本压缩,最后可以将压缩后的 css 文本交给 gulp 输出到指定位置,变成 xx.min.css。以同样的方式,也可以对 typescript 和 js 文件进行类似的 流 操作。
拿一段 gulp 处理 less 的任务代码举例:
const {task, src, dest} = require("gulp");
/* 其他插件或模块引入省略
const less ...
const autoprefixer ...
const minifycss ...
const rename ...
*/
task("build:css", () => {
return src("less/*.less") // 读取less目录下的所有 .less 文件
.pipe(less()) // 通过less将less转码成css
.pipe(autoprefixer()) // 通过autoprefixer为css中的属性添加浏览器前缀
.pipe(minifycss()) // 通过minifycss将处理完的css压缩
.pipe(rename({ extname: ".min.css" })) // 修改压缩后的文件后缀,统一改为 xx.min.css
.pipe(dest("build/style")) // 将处理完的文件输出到 build/style 目录下
});
可以看出,在这个环节,每一个pipe管道都会将上一个节点的 流 传递进来,所以用户可以在对应的节点做一些自定义的任务,然后再将处理完成的 流 传递给下一个节点即可。对于开发人员,这样的方式更清晰,用户可以直观清晰的掌握数据在每个节点的流动情况,从某种程度上来说,这样的task重写了webpack的部分轮子。
这篇博文主要讲解造轮子的过程,所以通过gulp,来重造部分webpack的轮子,以便对构建过程有一个清晰的了解。
基于gulp的轮子
一个web页面离不开 html、css 和 js,所以轮子的构造也从这三点来讲,不过目前暂时先弱化 html 的部分,主要看看 css 和 js 部分的构建流程。我准备使用 less 来预写 css ,使用 typescript 来预写 js,使用 less/scss 和 typescript 来重构前端页面也是目前非常流程的方案。
基于以上,我需要借助 gulp 来流程化构建的过程包括:
- 从 less 到 css 的转码和发布;
- less转码到css;
- 浏览器前缀的处理;
- css文件的压缩和合并;
- 从 typescript 到 js 的转码;
- typescript转码到js;
- ES6及以上语法降维到ES5;
- 浏览器运行支持;
- 本地调试,浏览器自动刷新;
- 监听工程文件变动;
- 自动刷新浏览器,重载页面;
- 以js文件为例的单元测试;
- 测试js模块文件是否符合预期;
- 基于jest的单元测试;
- 项目文件的发布
- 从开发环境转变为生产环境;
- 发布生产环境下的项目代码;
以上四点将是最基础的构建部分,我将使用gulp来依次处理这些部分,这将是一系列文章,正好也通过整个手动构建来加深对前端工程化的理解。
必备模块/插件
基于gulp来构建整个工程项目离不开外部优秀的插件和模块,以此项目为例,包含但不限于的插件和模块有:
- babel
- browser-sync
- browserify
- gulp
- gulp-autoprefixer
- gulp-cache
- gulp-concat
- gulp-less
- gulp-minify-css
- gulp-rename
- gulp-uglify
- gulp-rev
- gulp-pxtorem
- gulp-filter
- gulp-sourcemaps
- jest
- typescript
- tsify
- vinyl-buffer
- vinyl-source-stream
- …
每一个外部的模块或者插件,都将为整个项目的构建添砖加瓦。
目录结构
下面简要列举出目录的结构:
+-- __tests__
+-- build
| +-- js
| +-- css
| +-- index.html
+-- dist
+-- node_modules
+-- src
| +-- js
| +-- less
| +-- index.html
+-- .babelrc
+-- gulpfile.js
+-- jest.config.js
+-- package.json
其中:
__tests__
单元测试的测试脚本目录;buil
开发过程中文件编辑输出目录;dist
生产环境文件输出目录;src
项目源码目录;.babelrc
babel 的配置文件;gulpfile.js
gulp 的任务配置文件;jest.config.js
jest 测试工具的配置脚本文件;
约定开发阶段可以使用以下脚本启动项目:
npm run dev
开发完成后,约定使用下面的脚本用于输出到dist目录:
npm run dist
下一篇文章将基于该目录结构,使用gulp构建less自动转码的任务。