• 将源代码编译成在线上环境运行的过程
  • 优势:
    • 编码阶段可以使用最新语法,提高开发效率
    • 例如使用sass编写css,使用NPM scripts定义命令
  • 常用的自动化构建工具
    • Grunt:项目大的时候构建速度慢,基于磁盘读写
    • Gulp:基于内存实现,默认同时执行多个任务
    • FIS

Grunt

  • yarn add grunt
  • 创建gruntfile.js
  1. // gruntfile.js 是grunt的入口
  2. // 用于定义一些需要grunt 自动执行的任务
  3. module.exports = grunt => {
  4. // 默认任务
  5. //grunt.registerTask('default', () => {
  6. //
  7. //})
  8. grunt.registerTask('default',[ 'foo', 'bar'])
  9. grunt.registerTask('foo', () => {
  10. })
  11. grunt.registerTask('bar', () => {
  12. })
  13. // 异步操作
  14. grunt.registerTask('async-task', function() {
  15. const done = this.async()
  16. setTimeout(()=>{
  17. done()
  18. },1000)
  19. })
  20. }

Grunt标记任务失败

  1. module.exports = grunt => {
  2. grunt.registerTask('bar', () => {
  3. return false
  4. })
  5. grunt.registerTask('async-task', function() {
  6. const done = this.async()
  7. setTimeout(()=>{
  8. done(false)
  9. },1000)
  10. })
  11. }
  12. //-- force 强制后面任务执行

Grunt配置选项方法

  1. module.exports = grunt => {
  2. grunt.initConfig({
  3. foo: {
  4. bar: 123
  5. }
  6. })
  7. grunt.registerTask("foo",() => {
  8. console.log(grunt.config('foo.bar'))
  9. })
  10. }

Grunt多目标任务

  1. module.exports = grunt => {
  2. grunt.initConfig({
  3. build: {
  4. options:{
  5. foo: 'bar'
  6. },
  7. css: {
  8. options: {
  9. foo: 'baz' // 会覆盖上面的值
  10. }
  11. },
  12. js: ''
  13. }
  14. })
  15. // 多目标模式,可以让任务根据配置形成多个子任务
  16. grunt.registerMultiTask('build', function () {
  17. console.log(this.options())
  18. console.log(`target: ${this.target}, data: ${this.data}`)
  19. })
  20. }

Grunt插件的使用

  1. // 封装了通用的构建任务
  2. // grunt-contrib-clean 清除文件
  3. module.exports = grunt => {
  4. grunt.initConfig({
  5. clean:{
  6. temp: 'temp/**' // "temp/*.txt"
  7. }
  8. })
  9. grunt.loadNpmTasks('grunt-contrib-clean')
  10. }

Grunt常用插件

  • grunt-sass

    1. // yarn add grunt-sass sass
    2. const sass = require('sass')
    3. module.exports = grunt => {
    4. grunt.initConfig({
    5. sass:{
    6. options: {
    7. sourceMap: true,
    8. implementation: sass
    9. }
    10. main:{
    11. files: {
    12. "dist/css/main.css": 'src/scss/main.scss'
    13. }
    14. }
    15. }
    16. })
    17. grunt.loadNpmTasks('grunt-sass')
    18. }
  • grunt-babel

  • load-grunt-tasks

    1. // yarn add grunt-babel @babel/core @babel/preset-env --dev
    2. // yarn add load-grunt-tasks --dev
    3. const loadGruntTasks = require('load-grunt-tasks')
    4. module.exports = grunt => {
    5. grunt.initConfig({
    6. babel:{
    7. options: {
    8. presets: ['@babel/preset-env'],
    9. sourceMap: true
    10. }
    11. main:{
    12. files: {
    13. "dist/js/app.js": 'src/js/app.js'
    14. }
    15. }
    16. }
    17. })
    18. loadGruntTasks(grunt) // 自动加载所有的grunt插件中的任务
    19. }
  • grunt-contrib-watch

    1. module.exports = grunt => {
    2. grunt.initConfig({
    3. watch:{
    4. options: {
    5. presets: ['@babel/preset-env'],
    6. sourceMap: true
    7. }
    8. js: {
    9. files: ['src/js/*.js'],
    10. tasks: ['babel']
    11. },
    12. css: {
    13. files: ['src/scss/*.scss'],
    14. tasks: ['sass']
    15. }
    16. }
    17. })
    18. loadGruntTasks(grunt) // 自动加载所有的grunt插件中的任务
    19. grunt.registerTask('default',['sass','babel','watch'])
    20. }

Gulp

  • yarn init 初始化package.json
  • yarn add gulp —dev
  • 创建gulpfile.js 入口文件
  1. exports.foo = done => {
  2. conosle.log('foo task working')
  3. done() // 标识任务完成
  4. }
  5. // gulp foo
  6. export.default = done => {
  7. console.log('default task')
  8. done()
  9. }
  10. // 直接运行 gulp
  11. // gulp4.0之前需要先引入gulp
  12. const gulp = require('gulp')
  13. gulp.task('bar', done => {
  14. console.log("bar task")
  15. done()
  16. })

Gulp组合任务

  1. const { series, parallel } = require('gulp')
  2. const task1 = done => {
  3. setTimeout(() => {
  4. console.log('task1')
  5. done()
  6. }, 1000)
  7. }
  8. const task2 = done => {
  9. setTimeout(() => {
  10. console.log('task1')
  11. done()
  12. }, 1000)
  13. }
  14. const task3 = done => {
  15. setTimeout(() => {
  16. console.log('task1')
  17. done()
  18. }, 1000)
  19. }
  20. exports.foo = series(task1, task2, task3)// 按顺序进行
  21. exports.bar = parallel(task1, task2, task3) // 同时进行

Gulp中的异步任务

  1. // done
  2. exports.callback_error = done => {
  3. done(new Error('task failed'))
  4. }
  5. exports.promise = () => {
  6. return Promise.resolve()
  7. }
  8. exports.promise_error = () => {
  9. return Promise.reject()
  10. }
  11. const timeout = time => {
  12. return new Promise( resolve => {
  13. setTimeout(resolve, time)
  14. })
  15. }
  16. exports.async = async () => {
  17. await timeout(1000)
  18. }
  19. // 这种方式看node版本支不支持async await
  20. exports.stream = () => {
  21. const readStream = fs.createReadStream('package.json')
  22. const writeStream = fs.createWriteStream('temp.txt')
  23. readStream.pipe(writeStream)
  24. return readStream
  25. }
  26. // stream 中end事件触发结束任务
  27. exports.stream = done => {
  28. const readStream = fs.createReadStream('package.json')
  29. const writeStream = fs.createWriteStream('temp.txt')
  30. readStream.pipe(writeStream)
  31. readStream.on('end', () => {
  32. done()
  33. })
  34. }

Gulp构建过程核心工作原理

  1. const fs = require('fs')
  2. const { Transform } = require('stream')
  3. exporta.default = () => {
  4. const read = fs.createReadStream('normalize.css')
  5. const write = fs.createWriteStream('normalize.min.css')
  6. // 文件转换流
  7. const transform = new Transform({
  8. // 核心转换过程实现
  9. // chunk 读取流中读取到的内容(Buffer)
  10. const input = chunk.toString()
  11. const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
  12. callback(null, output)
  13. })
  14. read.pipe(transform).pipe(write)
  15. }
  16. // gulp是基于文件流的构建方式

Gulp文件操作API + 插件的使用

  1. const { src, dest } = require('gulp')
  2. const cleanCss = require('gulp-clean-css')
  3. const rename = require('gulp-rename')
  4. export.default = () => {
  5. return src('src/*.css')
  6. .pipe(cleanCss())
  7. .pipe(rename({ extname: '.min.css' }))
  8. .pipe(dest('dist'))
  9. }

Gulp案例

  1. // yarn add gulp --dev
  2. // 项目根目录新建gulpfile.js文件
  3. const { src, dest, parallel, series } = require('gulp')
  4. // 自动加载插件
  5. const loadPlugins = require('gulp-load-plugins')
  6. const plugins = loadPlugins()
  7. //const sass = require('gulp-sass')
  8. //const babel = require('gulp-babel') // 需要安装@babel/core @babel/preset-env
  9. //const swig = require('gulp-swig')
  10. //const imagemin = require('gulp-imagemin')
  11. //const del = require('del')
  12. const style = () => {
  13. return src('src/assets/styles/*.scss', { base: 'src' })// 保留原本目录结构
  14. .pipe(plugins.sass({ outputStyle: 'expanded' }))
  15. .pipe(dest('temp'))
  16. .pipe(fs.reload({ stream: true })) // 与bs配置中的files属性用途类似
  17. }
  18. const script = () => {
  19. return src('src/assets/scripts/*.js', { base: 'src' })
  20. .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
  21. .pipe(dest('temp'))
  22. }
  23. const page = () => {
  24. return src('src/**/*.html', { base: 'src' })
  25. .pipe(plugins.swig( { data, cache: false } )) // 将模板需要的数据导入
  26. .pipe(dest('temp'))
  27. }
  28. const image = () => {
  29. return src('src/assets/images/**', { base: 'src' })
  30. .pipe(plugins.imagemin())
  31. .pipe(dest('dist'))
  32. }
  33. const font = () => {
  34. return src('src/assets/fonts/**', { base: 'src' })
  35. .pipe(plugins.imagemin())
  36. .pipe(dest('dist'))
  37. }
  38. const extra = () => {
  39. return src('public/**', { base: 'public' })
  40. .pipe(dest('dist'))
  41. }
  42. const clean = () => {
  43. return del(['dist','temp'])
  44. }
  45. const compile = parallel(style, script, page, image, font)
  46. const build = series(clean, parallel(compile, extra))
  47. module.exports = {
  48. build
  49. }

Gulp配置开发热更新服务器

  1. // browsersync
  2. const { watch } = require('gulp')
  3. const browsersync = require("browser-sync")
  4. const bs = browsersync.create()
  5. const server = () => {
  6. // 监听src源代码的变化
  7. watch('src/assets/styles/*.scss', style)
  8. watch('src/assets/scripts/*.js', script)
  9. watch('src/*.html', page)
  10. //watch('src/assets/images/**', image)
  11. //watch('src/assets/fonts/**', font)
  12. //watch('public/**', extra)
  13. watch([
  14. 'src/assets/images/**',
  15. 'src/assets/fonts/**',
  16. 'public/**'
  17. ], bs.reload)
  18. bs.init({
  19. server: {
  20. notify: false,
  21. port: 8080,
  22. open: true,
  23. //files: 'temp/**', // 用来被监听的文件
  24. baseDir: ['temp','src','public'],
  25. routes: {
  26. '/node_modules': 'node_modules'
  27. }
  28. }
  29. })
  30. }
  31. module.exports = {
  32. server
  33. }

Gulp文件引用处理 useref

  1. // 将html中的build:css等构建注释的地方转换
  2. // yarn add gulp-useref --dev
  3. const useref = () => {
  4. return src('temp/*.html', { base: 'dist' })
  5. .pipe(plugins.useref({ searchPath: ['dist', '.'] }))
  6. // html js css 压缩 gulp-htmlmin gulp-uglify gulp-clean-css gulp-if
  7. .pipe(plugins.if(/\.js$/, plugins.uglify()))
  8. .pipe(plugins.if(/\.html$/, plugins.htmlmin({ collapseWhitespace: true, minifyCss: true, minifyJs: true }))) // style script 标签中代码压缩
  9. .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
  10. .pipe(dest('dist'))
  11. }
  12. const compile = parallel(style, script, page)
  13. const build = series(
  14. clean,
  15. parallel(
  16. series(compile, useref),
  17. image,
  18. font,
  19. extra
  20. )
  21. )
  22. const develop = series(compile, serve)
  23. module.exports = {
  24. clean,
  25. build,
  26. develop
  27. }
  • 可以将构建命令放到package.json的scripts中

封装自动化构建流

参考案例