• gulp + angularjs


    示例项目介绍

    文中使用的例子是一个基于 Angular.js 实现的网页版 Todo App,在 Github 中下载angular-quickstart。项目代码结构如下

    清单 5. 项目目录结构
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    |--bower_components
    |--build
    |--node_modules
    |--static_pages
    |--js
       |--controllers
       |--services
       |--app.js          // app 启动配置
    |--style
       |--main.css
    |--view
       |--note.html
    |--gulpfile.js      // gulp 配置
    |--bower.json           // bower 配置
    |--package.json         // node module 配置
    |--index.html           // app 启动文件

    架构上使用如下 libs

    • Angular:JavaScript 架构
    • Bootstrap:样式控件库
    • bower:管理项目依赖包
    • npm:管理项目运行的依赖工具
    • gulp:自动化构建工具

    设计 build process

    因为项目中使用到的 source code 有 JavaScript,,CSS,HTML 以及依赖 bower 导入的依赖包,所以我们将构建分成以下几个 task:

    1. jshint:编译 JavaScript
    2. clean:清空 build 目录
    3. template:合并并打包所有 HTML 模板文件生成 template.js
    4. js:压缩、混淆 JavaScript,并生成 sourcemap
    5. deployCSS:合并压缩 CSS
    6. devIndex:组织 develop 时的 index.html
    7. deployIndex:组织 deploy 时的 index.html,区别于第 6 个 task,这个 index.html 中 link 的将是压缩过的 CSS 和 JavaScript

    接下来,我们分条介绍上面的 task。

    设定全局变量 paths,记录 source code 的路径

    清单 6. 项目 paths
    1
    2
    3
    4
    5
    6
    7
    var paths = {
     js: ['./js/app.js', 'js/**/*.js'],
     css: ['./style/**/*.css'],
     templates: './js/templates.js',
     buildjs: ['./build/**/*.js'],
     buildcss: ['./build/**/*.css']
    };

    task 1: jshint

    这个 task 主要用来编译 JavaScript 代码。依赖插件 glup-jshint,需要在配置之前将这个插件安装好,之后如下配置:

    清单 7. jshint
    1
    2
    3
    4
    5
    6
    var jshint = require('gulp-jshint');
    gulp.task('jshint', function() {
     gulp.src(paths.js)
     .pipe(jshint())
     .pipe(jshint.reporter('default'));
    });

    task 2: clean

    我们可以看到项目目录中有个 build 文件夹,这个目录是用来存放所有 build 之后的 CSS/JS/HTML 文件。所以 clean 的任务是在每次 build 之前清理上一次 build 的 outputs,也就是清空 build 文件夹。依赖 del 模块:

    清单 8. clean
    1
    2
    3
    4
    5
    var del = require('del');
    gulp.task('clean', function() {
     // You can use multiple globbing patterns as you would with `gulp.src`
     return del(['./build', paths.templates]);
    });

    task 3: template

    开发过程中一般按照功能模块将页面分成不同的 HTML 片段模板,每个片段对应一个相应 controller,客户端浏览器访问网页时会分别请求下载 HTML 文件。当业务逻辑较为复杂时,项目中将会存在很多的 HTML 小文件,此时下载的请求数目也会很大,影响 performance。我们的想法是使用插件 gulp-angular-templatecache,将这些 HTML 模版片段合并成一个文件。这个插件会将所有模板文件合并成一个 template.js, 并将其作为项目中的一个 module 而存在。

    清单 9. template
    1
    2
    3
    4
    5
    6
    var templateCache = require('gulp-angular-templatecache');
    gulp.task('template', function () {
     return gulp.src('./view/**/*.html')
     .pipe(templateCache({module: 'myApp'}))
     .pipe(gulp.dest('./js'))
    });

    task 4: js

    JavaScript 的 build 分成两种情况:

    1. DEV 模式:在开发环境中,为了方便 debug,JavaScript 通常不做压缩和混淆;
    2. PROD 模式:上生产环境时,JavaScript 必须并合压缩、混淆并成一个文件,同时需要去除所有的 log 输出语句。

    JavaScript 混淆使用了插件 gulp-uglify;合并压缩使用了插件 gulp-concat,以及 gulp-sourcemaps;

    去除 log 语句使用了插件 gulp-strip-debug。

    清单 10. gulp 任务 js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    gulp.task('js', function() {
     if (deployEnvironment == Environment.DEV) { // DEV
     return gulp.src(paths.js)
     .pipe(concat('all.js'))
     .pipe(gulp.dest('./build'));
     } else { // PROD
     return gulp.src(paths.js)
     .pipe(sourcemaps.init())
     .pipe(stripDebug())
     .pipe(uglify())
     .pipe(concat('all.min.js'))
     .pipe(sourcemaps.write())
     .pipe(gulp.dest('./build'));
     }
    });

    task 5: css

    文中示例的样式表使用的是原生的 CSS 文件,所以使用 cssmin 完成了所有 CSS 文件的合并及压缩。

    清单 11. gulp 任务 css
    1
    2
    3
    4
    5
    6
    7
    var cssmin = require('gulp-cssmin');
    gulp.task('deployCSS', function() {
     return gulp.src(paths.css)
     .pipe(cssmin())
     .pipe(concat('all.css'))
     .pipe(gulp.dest('./build'));
    });

    task 6: devIndex

    这个 task 主要是管理开发使用的 index.html 文件中对静态资源的引用。因为我们使用了 bower 来管理项目的依赖包,比如 jQuery 和 Angular,我们使用下面这种方式来导入项目:

    清单 12. 引用静态资源
    1
    2
    <script src="bower_components/jquery/dist/jquery.js"></script>
    <script src="bower_components/angular/angular.js"></script>

    可以看出,当我们需要引用的静态资源变得很多时,这个 list 也将会变得很长很不好管理。这时可以使用插件 gulp-inject。

    1. 使用 bower 命令安装项目依赖包时添加--save-dev 参数,使配置写入 bower.json 文件。比如安装 angular 使用如下命令:

    清单 13. 安装本地 angular 模块
    1
    $ bower install –-save-dev angular

    安装成功以后 bower.json 文件的 dependencies 中会自动生成 angular 的依赖关系。

    清单 14.bower.json
    1
    2
    3
    "dependencies": {
     "angular": "^1.5.7"
    },

    2. 在 index.html 中使用 inject 标签管理需要插入依赖包的位置。整理 index.html 成如下格式:

    清单 15. 为 gulp-inject 准备的 index.html 模板
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!DOCTYPE html>
    <html lang="en" data-ng-app="myApp">
    <head>
    <meta charset="utf-8">
     <title>Angular UI Router</title>
     <!-- bower:css -->
     <!-- endinject -->
     
     <!-- inject:css -->
     <!-- endinject -->
    </head>
    <body>
     <a ui-sref="note">go note</a>
     <div ui-view></div>
     <!-- bower:js -->
     <!-- endinject -->
     
     <!-- inject:js -->
     <!-- endinject -->
    </body>
    </html>

    3. 配置 inject 的 task

    清单 16.gulp 任务 inject
    1
    2
    3
    4
    5
    6
    7
    8
    gulp.task('devIndex', ['clean', 'jshint'], function () {
     // It's not necessary to read the files (will speed up things), we're only after their paths:
     return gulp.src('./index.html')
     .pipe(inject(gulp.src(paths.js, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(paths.css, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(bowerFiles(), {read: false}), {name: 'bower', relative: true}))
     .pipe(gulp.dest('./'));
    });

    4. 执行命令 gulp devIndex,我们可以得到注入以后的 index.html 如下:

    清单 17.Inject 后生成的 index.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <!DOCTYPE html>
    <html lang="en" data-ng-app="myApp">
    <head>
    <meta charset="utf-8">
     <title>Angular UI Router</title>
     <!-- bower:css -->
     <link rel="stylesheet" href="bower_components/normalize-css/normalize.css">
     <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
     <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap-theme.css">
     <!-- endinject -->
     
     <!-- inject:css -->
     <link rel="stylesheet" href="style/main.css">
     <!-- endinject -->
    </head>
    <body>
     <a ui-sref="note">go note</a>
     <div ui-view></div>
     
     <!-- bower:js -->
     <script src="bower_components/angular/angular.js"></script>
     <!-- endinject -->
     
     <!-- inject:js -->
     <script src="js/app.js"></script>
     <script src="js/controllers/note.js"></script>
     <script src="js/services/note.js"></script>
     <!-- endinject -->
    </body>
    </html>

    task 7: deployIndex

    deployIndex 主要是用来组织部署到测试或者生产环境时需要的 index.html。和 devIndex 的区别在于页面中引用的是合并压缩混淆后的静态资源,也就是项目目录 build 中的文件。此处同样也是使用的 gulp-inject,我们直接看一下 task。

    清单 18. gulp 任务 deployIndex
    1
    2
    3
    4
    5
    6
    7
    8
    gulp.task('deployIndex', ['clean', 'jshint', 'template', 'deployJS', 'deployCSS'], function () {
     // It's not necessary to read the files (will speed up things), we're only after their paths:
     return gulp.src('./index.html')
     .pipe(inject(gulp.src(paths.buildjs, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(paths.buildcss, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(bowerFiles(), {read: false}), {name: 'bower', relative: true}))
     .pipe(gulp.dest('./'));
    });

    上面这段代码在配置 deployIndex 时使用了三个参数,其中第二个参数表示当前 task 所依赖的 task list。

    示例项目介绍

    文中使用的例子是一个基于 Angular.js 实现的网页版 Todo App,在 Github 中下载angular-quickstart。项目代码结构如下

    清单 5. 项目目录结构
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    |--bower_components
    |--build
    |--node_modules
    |--static_pages
    |--js
       |--controllers
       |--services
       |--app.js          // app 启动配置
    |--style
       |--main.css
    |--view
       |--note.html
    |--gulpfile.js      // gulp 配置
    |--bower.json           // bower 配置
    |--package.json         // node module 配置
    |--index.html           // app 启动文件

    架构上使用如下 libs

    • Angular:JavaScript 架构
    • Bootstrap:样式控件库
    • bower:管理项目依赖包
    • npm:管理项目运行的依赖工具
    • gulp:自动化构建工具

    设计 build process

    因为项目中使用到的 source code 有 JavaScript,,CSS,HTML 以及依赖 bower 导入的依赖包,所以我们将构建分成以下几个 task:

    1. jshint:编译 JavaScript
    2. clean:清空 build 目录
    3. template:合并并打包所有 HTML 模板文件生成 template.js
    4. js:压缩、混淆 JavaScript,并生成 sourcemap
    5. deployCSS:合并压缩 CSS
    6. devIndex:组织 develop 时的 index.html
    7. deployIndex:组织 deploy 时的 index.html,区别于第 6 个 task,这个 index.html 中 link 的将是压缩过的 CSS 和 JavaScript

    接下来,我们分条介绍上面的 task。

    设定全局变量 paths,记录 source code 的路径

    清单 6. 项目 paths
    1
    2
    3
    4
    5
    6
    7
    var paths = {
     js: ['./js/app.js', 'js/**/*.js'],
     css: ['./style/**/*.css'],
     templates: './js/templates.js',
     buildjs: ['./build/**/*.js'],
     buildcss: ['./build/**/*.css']
    };

    task 1: jshint

    这个 task 主要用来编译 JavaScript 代码。依赖插件 glup-jshint,需要在配置之前将这个插件安装好,之后如下配置:

    清单 7. jshint
    1
    2
    3
    4
    5
    6
    var jshint = require('gulp-jshint');
    gulp.task('jshint', function() {
     gulp.src(paths.js)
     .pipe(jshint())
     .pipe(jshint.reporter('default'));
    });

    task 2: clean

    我们可以看到项目目录中有个 build 文件夹,这个目录是用来存放所有 build 之后的 CSS/JS/HTML 文件。所以 clean 的任务是在每次 build 之前清理上一次 build 的 outputs,也就是清空 build 文件夹。依赖 del 模块:

    清单 8. clean
    1
    2
    3
    4
    5
    var del = require('del');
    gulp.task('clean', function() {
     // You can use multiple globbing patterns as you would with `gulp.src`
     return del(['./build', paths.templates]);
    });

    task 3: template

    开发过程中一般按照功能模块将页面分成不同的 HTML 片段模板,每个片段对应一个相应 controller,客户端浏览器访问网页时会分别请求下载 HTML 文件。当业务逻辑较为复杂时,项目中将会存在很多的 HTML 小文件,此时下载的请求数目也会很大,影响 performance。我们的想法是使用插件 gulp-angular-templatecache,将这些 HTML 模版片段合并成一个文件。这个插件会将所有模板文件合并成一个 template.js, 并将其作为项目中的一个 module 而存在。

    清单 9. template
    1
    2
    3
    4
    5
    6
    var templateCache = require('gulp-angular-templatecache');
    gulp.task('template', function () {
     return gulp.src('./view/**/*.html')
     .pipe(templateCache({module: 'myApp'}))
     .pipe(gulp.dest('./js'))
    });

    task 4: js

    JavaScript 的 build 分成两种情况:

    1. DEV 模式:在开发环境中,为了方便 debug,JavaScript 通常不做压缩和混淆;
    2. PROD 模式:上生产环境时,JavaScript 必须并合压缩、混淆并成一个文件,同时需要去除所有的 log 输出语句。

    JavaScript 混淆使用了插件 gulp-uglify;合并压缩使用了插件 gulp-concat,以及 gulp-sourcemaps;

    去除 log 语句使用了插件 gulp-strip-debug。

    清单 10. gulp 任务 js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    gulp.task('js', function() {
     if (deployEnvironment == Environment.DEV) { // DEV
     return gulp.src(paths.js)
     .pipe(concat('all.js'))
     .pipe(gulp.dest('./build'));
     } else { // PROD
     return gulp.src(paths.js)
     .pipe(sourcemaps.init())
     .pipe(stripDebug())
     .pipe(uglify())
     .pipe(concat('all.min.js'))
     .pipe(sourcemaps.write())
     .pipe(gulp.dest('./build'));
     }
    });

    task 5: css

    文中示例的样式表使用的是原生的 CSS 文件,所以使用 cssmin 完成了所有 CSS 文件的合并及压缩。

    清单 11. gulp 任务 css
    1
    2
    3
    4
    5
    6
    7
    var cssmin = require('gulp-cssmin');
    gulp.task('deployCSS', function() {
     return gulp.src(paths.css)
     .pipe(cssmin())
     .pipe(concat('all.css'))
     .pipe(gulp.dest('./build'));
    });

    task 6: devIndex

    这个 task 主要是管理开发使用的 index.html 文件中对静态资源的引用。因为我们使用了 bower 来管理项目的依赖包,比如 jQuery 和 Angular,我们使用下面这种方式来导入项目:

    清单 12. 引用静态资源
    1
    2
    <script src="bower_components/jquery/dist/jquery.js"></script>
    <script src="bower_components/angular/angular.js"></script>

    可以看出,当我们需要引用的静态资源变得很多时,这个 list 也将会变得很长很不好管理。这时可以使用插件 gulp-inject。

    1. 使用 bower 命令安装项目依赖包时添加--save-dev 参数,使配置写入 bower.json 文件。比如安装 angular 使用如下命令:

    清单 13. 安装本地 angular 模块
    1
    $ bower install –-save-dev angular

    安装成功以后 bower.json 文件的 dependencies 中会自动生成 angular 的依赖关系。

    清单 14.bower.json
    1
    2
    3
    "dependencies": {
     "angular": "^1.5.7"
    },

    2. 在 index.html 中使用 inject 标签管理需要插入依赖包的位置。整理 index.html 成如下格式:

    清单 15. 为 gulp-inject 准备的 index.html 模板
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!DOCTYPE html>
    <html lang="en" data-ng-app="myApp">
    <head>
    <meta charset="utf-8">
     <title>Angular UI Router</title>
     <!-- bower:css -->
     <!-- endinject -->
     
     <!-- inject:css -->
     <!-- endinject -->
    </head>
    <body>
     <a ui-sref="note">go note</a>
     <div ui-view></div>
     <!-- bower:js -->
     <!-- endinject -->
     
     <!-- inject:js -->
     <!-- endinject -->
    </body>
    </html>

    3. 配置 inject 的 task

    清单 16.gulp 任务 inject
    1
    2
    3
    4
    5
    6
    7
    8
    gulp.task('devIndex', ['clean', 'jshint'], function () {
     // It's not necessary to read the files (will speed up things), we're only after their paths:
     return gulp.src('./index.html')
     .pipe(inject(gulp.src(paths.js, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(paths.css, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(bowerFiles(), {read: false}), {name: 'bower', relative: true}))
     .pipe(gulp.dest('./'));
    });

    4. 执行命令 gulp devIndex,我们可以得到注入以后的 index.html 如下:

    清单 17.Inject 后生成的 index.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <!DOCTYPE html>
    <html lang="en" data-ng-app="myApp">
    <head>
    <meta charset="utf-8">
     <title>Angular UI Router</title>
     <!-- bower:css -->
     <link rel="stylesheet" href="bower_components/normalize-css/normalize.css">
     <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
     <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap-theme.css">
     <!-- endinject -->
     
     <!-- inject:css -->
     <link rel="stylesheet" href="style/main.css">
     <!-- endinject -->
    </head>
    <body>
     <a ui-sref="note">go note</a>
     <div ui-view></div>
     
     <!-- bower:js -->
     <script src="bower_components/angular/angular.js"></script>
     <!-- endinject -->
     
     <!-- inject:js -->
     <script src="js/app.js"></script>
     <script src="js/controllers/note.js"></script>
     <script src="js/services/note.js"></script>
     <!-- endinject -->
    </body>
    </html>

    task 7: deployIndex

    deployIndex 主要是用来组织部署到测试或者生产环境时需要的 index.html。和 devIndex 的区别在于页面中引用的是合并压缩混淆后的静态资源,也就是项目目录 build 中的文件。此处同样也是使用的 gulp-inject,我们直接看一下 task。

    清单 18. gulp 任务 deployIndex
    1
    2
    3
    4
    5
    6
    7
    8
    gulp.task('deployIndex', ['clean', 'jshint', 'template', 'deployJS', 'deployCSS'], function () {
     // It's not necessary to read the files (will speed up things), we're only after their paths:
     return gulp.src('./index.html')
     .pipe(inject(gulp.src(paths.buildjs, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(paths.buildcss, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(bowerFiles(), {read: false}), {name: 'bower', relative: true}))
     .pipe(gulp.dest('./'));
    });

    上面这段代码在配置 deployIndex 时使用了三个参数,其中第二个参数表示当前 task 所依赖的 task list。

    调用 gulp deployIndex,生成的 index.html 和上一个 task 类似,不过 CSS 和 JS 的引用会修改如下:

    清单 19. Inject 之后生成的 index.html
    1
    2
    3
    4
    5
    6
    <!-- inject:css -->
    <link rel="stylesheet" href="build/all.css">
    <!-- endinject -->
    <!-- inject:js -->
    <script src="build/all.min.js"></script>
    <!-- endinject -->

    结束语

    随着"前后端分离"架构的日渐普及,前台的自动化构建将越来越被重视。本文着重介绍了 gulp 的使用方式,以及 Web 前台开发过程中涉及的一些自动化构建切入点,希望读者可以通过本文了解 Web 前台的自动化构建相关知识。

    调用 gulp deployIndex,生成的 index.html 和上一个 task 类似,不过 CSS 和 JS 的引用会修改如下:

    清单 19. Inject 之后生成的 index.html
    1
    2
    3
    4
    5
    6
    <!-- inject:css -->
    <link rel="stylesheet" href="build/all.css">
    <!-- endinject -->
    <!-- inject:js -->
    <script src="build/all.min.js"></script>
    <!-- endinject -->

    结束语

    随着"前后端分离"架构的日渐普及,前台的自动化构建将越来越被重视。本文着重介绍了 gulp 的使用方式,以及 Web 前台开发过程中涉及的一些自动化构建切入点,希望读者可以通过本文了解 Web 前台的自动化构建相关知识。

    示例项目介绍

    文中使用的例子是一个基于 Angular.js 实现的网页版 Todo App,在 Github 中下载angular-quickstart。项目代码结构如下

    清单 5. 项目目录结构
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    |--bower_components
    |--build
    |--node_modules
    |--static_pages
    |--js
       |--controllers
       |--services
       |--app.js          // app 启动配置
    |--style
       |--main.css
    |--view
       |--note.html
    |--gulpfile.js      // gulp 配置
    |--bower.json           // bower 配置
    |--package.json         // node module 配置
    |--index.html           // app 启动文件

    架构上使用如下 libs

    • Angular:JavaScript 架构
    • Bootstrap:样式控件库
    • bower:管理项目依赖包
    • npm:管理项目运行的依赖工具
    • gulp:自动化构建工具

    设计 build process

    因为项目中使用到的 source code 有 JavaScript,,CSS,HTML 以及依赖 bower 导入的依赖包,所以我们将构建分成以下几个 task:

    1. jshint:编译 JavaScript
    2. clean:清空 build 目录
    3. template:合并并打包所有 HTML 模板文件生成 template.js
    4. js:压缩、混淆 JavaScript,并生成 sourcemap
    5. deployCSS:合并压缩 CSS
    6. devIndex:组织 develop 时的 index.html
    7. deployIndex:组织 deploy 时的 index.html,区别于第 6 个 task,这个 index.html 中 link 的将是压缩过的 CSS 和 JavaScript

    接下来,我们分条介绍上面的 task。

    设定全局变量 paths,记录 source code 的路径

    清单 6. 项目 paths
    1
    2
    3
    4
    5
    6
    7
    var paths = {
     js: ['./js/app.js', 'js/**/*.js'],
     css: ['./style/**/*.css'],
     templates: './js/templates.js',
     buildjs: ['./build/**/*.js'],
     buildcss: ['./build/**/*.css']
    };

    task 1: jshint

    这个 task 主要用来编译 JavaScript 代码。依赖插件 glup-jshint,需要在配置之前将这个插件安装好,之后如下配置:

    清单 7. jshint
    1
    2
    3
    4
    5
    6
    var jshint = require('gulp-jshint');
    gulp.task('jshint', function() {
     gulp.src(paths.js)
     .pipe(jshint())
     .pipe(jshint.reporter('default'));
    });

    task 2: clean

    我们可以看到项目目录中有个 build 文件夹,这个目录是用来存放所有 build 之后的 CSS/JS/HTML 文件。所以 clean 的任务是在每次 build 之前清理上一次 build 的 outputs,也就是清空 build 文件夹。依赖 del 模块:

    清单 8. clean
    1
    2
    3
    4
    5
    var del = require('del');
    gulp.task('clean', function() {
     // You can use multiple globbing patterns as you would with `gulp.src`
     return del(['./build', paths.templates]);
    });

    task 3: template

    开发过程中一般按照功能模块将页面分成不同的 HTML 片段模板,每个片段对应一个相应 controller,客户端浏览器访问网页时会分别请求下载 HTML 文件。当业务逻辑较为复杂时,项目中将会存在很多的 HTML 小文件,此时下载的请求数目也会很大,影响 performance。我们的想法是使用插件 gulp-angular-templatecache,将这些 HTML 模版片段合并成一个文件。这个插件会将所有模板文件合并成一个 template.js, 并将其作为项目中的一个 module 而存在。

    清单 9. template
    1
    2
    3
    4
    5
    6
    var templateCache = require('gulp-angular-templatecache');
    gulp.task('template', function () {
     return gulp.src('./view/**/*.html')
     .pipe(templateCache({module: 'myApp'}))
     .pipe(gulp.dest('./js'))
    });

    task 4: js

    JavaScript 的 build 分成两种情况:

    1. DEV 模式:在开发环境中,为了方便 debug,JavaScript 通常不做压缩和混淆;
    2. PROD 模式:上生产环境时,JavaScript 必须并合压缩、混淆并成一个文件,同时需要去除所有的 log 输出语句。

    JavaScript 混淆使用了插件 gulp-uglify;合并压缩使用了插件 gulp-concat,以及 gulp-sourcemaps;

    去除 log 语句使用了插件 gulp-strip-debug。

    清单 10. gulp 任务 js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    gulp.task('js', function() {
     if (deployEnvironment == Environment.DEV) { // DEV
     return gulp.src(paths.js)
     .pipe(concat('all.js'))
     .pipe(gulp.dest('./build'));
     } else { // PROD
     return gulp.src(paths.js)
     .pipe(sourcemaps.init())
     .pipe(stripDebug())
     .pipe(uglify())
     .pipe(concat('all.min.js'))
     .pipe(sourcemaps.write())
     .pipe(gulp.dest('./build'));
     }
    });

    task 5: css

    文中示例的样式表使用的是原生的 CSS 文件,所以使用 cssmin 完成了所有 CSS 文件的合并及压缩。

    清单 11. gulp 任务 css
    1
    2
    3
    4
    5
    6
    7
    var cssmin = require('gulp-cssmin');
    gulp.task('deployCSS', function() {
     return gulp.src(paths.css)
     .pipe(cssmin())
     .pipe(concat('all.css'))
     .pipe(gulp.dest('./build'));
    });

    task 6: devIndex

    这个 task 主要是管理开发使用的 index.html 文件中对静态资源的引用。因为我们使用了 bower 来管理项目的依赖包,比如 jQuery 和 Angular,我们使用下面这种方式来导入项目:

    清单 12. 引用静态资源
    1
    2
    <script src="bower_components/jquery/dist/jquery.js"></script>
    <script src="bower_components/angular/angular.js"></script>

    可以看出,当我们需要引用的静态资源变得很多时,这个 list 也将会变得很长很不好管理。这时可以使用插件 gulp-inject。

    1. 使用 bower 命令安装项目依赖包时添加--save-dev 参数,使配置写入 bower.json 文件。比如安装 angular 使用如下命令:

    清单 13. 安装本地 angular 模块
    1
    $ bower install –-save-dev angular

    安装成功以后 bower.json 文件的 dependencies 中会自动生成 angular 的依赖关系。

    清单 14.bower.json
    1
    2
    3
    "dependencies": {
     "angular": "^1.5.7"
    },

    2. 在 index.html 中使用 inject 标签管理需要插入依赖包的位置。整理 index.html 成如下格式:

    清单 15. 为 gulp-inject 准备的 index.html 模板
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <!DOCTYPE html>
    <html lang="en" data-ng-app="myApp">
    <head>
    <meta charset="utf-8">
     <title>Angular UI Router</title>
     <!-- bower:css -->
     <!-- endinject -->
     
     <!-- inject:css -->
     <!-- endinject -->
    </head>
    <body>
     <a ui-sref="note">go note</a>
     <div ui-view></div>
     <!-- bower:js -->
     <!-- endinject -->
     
     <!-- inject:js -->
     <!-- endinject -->
    </body>
    </html>

    3. 配置 inject 的 task

    清单 16.gulp 任务 inject
    1
    2
    3
    4
    5
    6
    7
    8
    gulp.task('devIndex', ['clean', 'jshint'], function () {
     // It's not necessary to read the files (will speed up things), we're only after their paths:
     return gulp.src('./index.html')
     .pipe(inject(gulp.src(paths.js, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(paths.css, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(bowerFiles(), {read: false}), {name: 'bower', relative: true}))
     .pipe(gulp.dest('./'));
    });

    4. 执行命令 gulp devIndex,我们可以得到注入以后的 index.html 如下:

    清单 17.Inject 后生成的 index.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <!DOCTYPE html>
    <html lang="en" data-ng-app="myApp">
    <head>
    <meta charset="utf-8">
     <title>Angular UI Router</title>
     <!-- bower:css -->
     <link rel="stylesheet" href="bower_components/normalize-css/normalize.css">
     <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
     <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap-theme.css">
     <!-- endinject -->
     
     <!-- inject:css -->
     <link rel="stylesheet" href="style/main.css">
     <!-- endinject -->
    </head>
    <body>
     <a ui-sref="note">go note</a>
     <div ui-view></div>
     
     <!-- bower:js -->
     <script src="bower_components/angular/angular.js"></script>
     <!-- endinject -->
     
     <!-- inject:js -->
     <script src="js/app.js"></script>
     <script src="js/controllers/note.js"></script>
     <script src="js/services/note.js"></script>
     <!-- endinject -->
    </body>
    </html>

    task 7: deployIndex

    deployIndex 主要是用来组织部署到测试或者生产环境时需要的 index.html。和 devIndex 的区别在于页面中引用的是合并压缩混淆后的静态资源,也就是项目目录 build 中的文件。此处同样也是使用的 gulp-inject,我们直接看一下 task。

    清单 18. gulp 任务 deployIndex
    1
    2
    3
    4
    5
    6
    7
    8
    gulp.task('deployIndex', ['clean', 'jshint', 'template', 'deployJS', 'deployCSS'], function () {
     // It's not necessary to read the files (will speed up things), we're only after their paths:
     return gulp.src('./index.html')
     .pipe(inject(gulp.src(paths.buildjs, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(paths.buildcss, {read: false}), {relative: true}))
     .pipe(inject(gulp.src(bowerFiles(), {read: false}), {name: 'bower', relative: true}))
     .pipe(gulp.dest('./'));
    });

    上面这段代码在配置 deployIndex 时使用了三个参数,其中第二个参数表示当前 task 所依赖的 task list。

    调用 gulp deployIndex,生成的 index.html 和上一个 task 类似,不过 CSS 和 JS 的引用会修改如下:

    清单 19. Inject 之后生成的 index.html
    1
    2
    3
    4
    5
    6
    <!-- inject:css -->
    <link rel="stylesheet" href="build/all.css">
    <!-- endinject -->
    <!-- inject:js -->
    <script src="build/all.min.js"></script>
    <!-- endinject -->

    结束语

    随着"前后端分离"架构的日渐普及,前台的自动化构建将越来越被重视。本文着重介绍了 gulp 的使用方式,以及 Web 前台开发过程中涉及的一些自动化构建切入点,希望读者可以通过本文了解 Web 前台的自动化构建相关知识。

  • 相关阅读:
    每天一点点之css
    【Vue中的坑】Vue中的修改变量没有效果?
    每天一点点之vue框架开发
    每天一点点之laravel框架开发
    每天一点点之vue框架开发
    推荐几款好用的办公软件
    每天一点点之vue框架开发
    Unity3D调用摄像头,画面为翻转的问题
    正确显示竖屏预览和拍照的照片
    卡尔曼滤波简介+ 算法实现代码
  • 原文地址:https://www.cnblogs.com/zhengyan/p/8710519.html
Copyright © 2020-2023  润新知