谈谈前端自动构建工具 Gulp

类似 Gulp 这样的工具可以说是前端利器,基本前端开发都离不开他,类似的解决方案还有 Grunt 和 Webpack 等,不过我用 Gulp 比较多一些,所以我只能谈谈 Gulp 了。

Gulp 上面优秀的插件特别多,我使用的有这些:

import gulp from 'gulp'
import babel from 'gulp-babel'
import uglify from 'gulp-uglify'
import ngAnnotate from 'gulp-ng-annotate'
import concat from 'gulp-concat'
import cleanCSS from 'gulp-clean-css'
import imagemin from 'gulp-imagemin'
import minifyHtml from 'gulp-minify-html'
import ngTemplate from 'gulp-ng-template'
import plumber from 'gulp-plumber'
import sass from 'gulp-sass'
import usemin from 'gulp-usemin'
import runSequence from 'gulp-run-sequence'
import eslint from 'gulp-eslint'
  • gulp-uglify
    对 JavaScript 进行压缩的插件,可以有效减少 JavaScript 的文件大小。
  • gulp-ng-annotate
    对 Angular 的代码进行转换,因为使用上面的 gulp-uglify 对 Angular 的代码进行压缩时会破坏 Angular 文件的依赖注入功能,导致无法正常工作,这个基本上是 Angular 开发必备的了。
  • gulp-concat
    文件合并,前端合并文件以减少请求是非常重要的优化技巧。
  • gulp-clean-css
    字如其名,对css 进行合并压缩。
  • gulp-imagemin
    对图片进行压缩。
  • gulp-minify-html
    对html文件进行压缩。
  • gulp-ng-template
    这个也是 Angular 里面比较响当当的一个插件了,他的作用是将 Angular 模板存到 templateCache ,可以提升模板加载速度。
  • gulp-plumber
    这个貌似也是 Gulp 必不可少的插件之一了,可以避免 Gulp 出错导致整个进程崩掉。
  • gulp-sass
    编译 sass 代码为 css,非常方便。
  • gulp-run-sequence
    可以让 Gulp 的任务顺序执行,有些时候我们希望 Gulp 执行了一些任务完成之后才来执行下一个任务,这时候这个插件就派上用场了。
  • gulp-usemin
    这个是用来从工作环境到生产环境进行部署的工具。
  • gulp-eslint
    eslint 代码检查。

上面的这些插件都是我在一个项目中使用到的,通过这些工具实现了前端的自动化开发,我在项目中有开发环境和生产环境之分。

在 Gulp 中,我有一段在开发环境下执行的任务

gulp.task('default', ['css', 'js', 'angular', 'img', 'templates:dist', 'sass', 'fonts'])

这段代码帮我做了

  • css:进行 css 文件(这些文件是第三方 css 文件如 bootstrap)的合并。
  • javascript:进行 JavaScript 文件的合并,这是将所有我写的 Angular 文件进行合并,但不进行压缩以方便我调试。
  • angular:将项目所有的 JavaScript 依赖如 Angular, ui-router, jQuery 等文件进行压缩合并。
  • img:将图片进行压缩和迁移,这些图片压缩后放入生产环境对应的文件夹中。
  • templates:dist:对 Angular 的视图进行合并,使用了上述的 gulp-ng-template 插件,合并后为一个新的 JavaScript 文件。
  • sass:将我写的 scss 代码进行编译。
  • fonts:移动相应的字体文件到生产环境中。

开发环境下我们需要自动构建,也需要便于调试,所以我用上面这样的方式来处理,并且开启了 watch 监视变化,在有更改发生时自动构建。当我处理完全部工作后需要 push 到服务器上面时,会执行 gulp product 即下面的 task。

gulp.task('product', function(cb){
  runSequence('together', 'move', cb)
});

gulp.task('together', function(cb){
    gulp.src('index.html')
        .pipe(plumber())
        .pipe(usemin({
            cssProduct: ['concat'],
            jsProduct: [ngAnnotate(),'concat',uglify()]
        }))
        .pipe(gulp.dest('backend/app/'))
        .on('end',cb);
});

gulp.task('move', function(){
    return gulp.src('backend/app/index.html')
                .pipe(gulp.dest('backend/app/templates/'));
});

这里使用了上述说的 ng-run-sequence 插件,这里会在执行完 together 的任务后才开始执行 move 的任务。这里主要使用的插件是 gulp-usemin,我用它来做了这些事情,为了方便说明,我贴下代码。需要先说明的是,我在项目中一共有3个 index.html 文件。

<!DOCTYPE html>
<html lang="zh-CN" ng-app="index">
<head>
    <!-- build:cssProduct /static/css/app.min.css -->
    <link rel="stylesheet" href="src/css/app.min.css">
    <link rel="stylesheet" href="src/css/bookist.css">
    <!-- endbuild -->
<body>
    ...
    <!-- build:jsProduct /static/js/app.min.js -->
    <script src="src/js/dependence.min.js"></script>
    <script src="src/js/app.js"></script>
    <script src="src/js/templates.js"></script>
    <!-- endbuild -->
    <!-- build:remove -->
    <!--
        这段注释会被移除
    -->
    <!-- endbuild-->
</body>
</head>

省去了没有用的代码,这里需要你对 ng-usemin 有一定的了解。这个 index.html 是我在开发环境下使用的,使用了我开发环境的 task 生成文件,我在上面有补充说明了。

所以,在部署生产环境时执行这段 task 的意义是,将开发环境下的代码再做进一步的合并和压缩。ng-usemin 这个插件会帮我们处理这个 index.html 文件,最后会在我们指定的目录下部署好这些东西。但是因为后端处理 index.html 的路径原因,我还要对 index.html 做一次移动,所以有了第三个 index.html。

最终生成的 index 和相应的资源位置如下

<!DOCTYPE html>
<html lang="zh-CN" ng-app="index">
<head>
    <link rel="stylesheet" href="/static/css/app.min.css"/>
</head>
<body>
    <script src="/static/js/app.min.js"></script>
</body>
</html>