前端工程化实战-开发脚手架及封装自动化构建工作流> 工程化的定义和主要解决的问题- 02-01-03自动化构建

1.自动化构建基本介绍

自动化构建是前端工程化中重要组成部分,
就是把开发阶段源代码自动转化成生产环境当中可以运行的代码或者程序

  • 自动化构建工作流

2.自动化构建体验

NPM Scripts
在package.json中增加一个scripts对象,如:在这里插入代码片

{
  "scripts": {
    "build": "sass scss/main.scss css/style.css"
  }
}

scripts可以自动发现node_modules里面的命令,所以不需要写完整的路径,直接写命令的名称就可以。然后可以通过npm或yarn运行scripts下面的命令名称,npm用run启动,yarn可以省略run,如:npm run buildyarn build
NPM Scripts是实现自动化构建工作流的最简方式
安装browser-sync

{
  "scripts": {
    "build": "sass scss/main.scss css/style.css",
    "preserve": "yarn build",
    "serve": "browser-sync ."
  }
}

preserve是一个钩子,保证在执行serve之前,会先执行build,使样式先处理,然后再执行serve
通过–watch可以监听sass文件的变化自动编译,但是此时sass命令在工作时,命令行会阻塞,去等待文件的变化,导致了后面的serve无法去工作,此时就需要同时去执行多个任务,要安装npm-run-all这个模块

{
  "scripts": {
    "build": "sass scss/main.scss css/style.css --watch",
    "serve": "browser-sync .",
    "start": "run-p build serve"
  }
}

运行npm run start命令,build和serve就会被同时执行

3.常用的自动化构建工具

  • Grunt:磁盘读写
  • Gulp:在内存中完成,可同时执行多个任务
  • FIS:百度支持,微内核

4.Grunt的使用

官网
Grunt是最早的前端构建系统,它的插件生态非常完善,它的插件可以帮你完成任何你想做的事情。由于Grunt工作过程是基于临时文件去实现的,所以会比较慢

使用详情

  1. 初始化项目yarn init --yes
  2. 安装grunt:yarn add grunt
  3. 编写gruntfile.js文件,下面举例grunt任务的几种用法:
  4. 执行命令:yarn grunt build

1.基本使用

// Grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的对象类型的形参
// grunt 对象中提供一些创建任务时会用到的 API

module.exports = grunt => {
  grunt.registerTask('foo', 'a sample task', () => {
    console.log('hello grunt')
  })

  grunt.registerTask('bar', () => {
    console.log('other task')
  })

  // // default 是默认任务名称
  // // 通过 grunt 执行时可以省略
  // grunt.registerTask('default', () => {
  //   console.log('default task')
  // })

  // 第二个参数可以指定此任务的映射任务,
  // 这样执行 default 就相当于执行对应的任务
  // 这里映射的任务会按顺序依次执行,不会同步执行
  grunt.registerTask('default', ['foo', 'bar'])

  // 也可以在任务函数中执行其他任务
  grunt.registerTask('run-other', () => {
    // foo 和 bar 会在当前任务执行完成过后自动依次执行
    grunt.task.run('foo', 'bar')
    console.log('current task runing~')
  })

  // 默认 grunt 采用同步模式编码
  // 如果需要异步可以使用 this.async() 方法创建回调函数
  // grunt.registerTask('async-task', () => {
  //   setTimeout(() => {
  //     console.log('async task working~')
  //   }, 1000)
  // })

  // 由于函数体中需要使用 this,所以这里不能使用箭头函数
  grunt.registerTask('async-task', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async task working~')
      done()
    }, 1000)
  })
}

2.标记任务失败

- 在任务中return false
- 命令中添加 --force
- 异步任务中给done添加实参
module.exports = grunt => {
  // 任务函数执行过程中如果返回 false
  // 则意味着此任务执行失败
  grunt.registerTask('bad', () => {
    console.log('bad working~')
    return false
  })

  grunt.registerTask('foo', () => {
    console.log('foo working~')
  })

  grunt.registerTask('bar', () => {
    console.log('bar working~')
  })

  // 如果一个任务列表中的某个任务执行失败
  // 则后续任务默认不会运行
  // 除非 grunt 运行时指定 --force 参数强制执行
  grunt.registerTask('default', ['foo', 'bad', 'bar'])

  // 异步函数中标记当前任务执行失败的方式是为回调函数指定一个 false 的实参
  grunt.registerTask('bad-async', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async task working~')
      done(false)
    }, 1000)
  })
}

3.Grunt的配置方法

module.exports = grunt => {
  // grunt.initConfig() 用于为任务添加一些配置选项
  grunt.initConfig({
    // 键一般对应任务的名称
    // 值可以是任意类型的数据
    foo: {
      bar: 'baz'
    }
  })

  grunt.registerTask('foo', () => {
    // 任务中可以使用 grunt.config() 获取配置
    console.log(grunt.config('foo'))
    // 如果属性值是对象的话,config 中可以使用点的方式定位对象中属性的值
    console.log(grunt.config('foo.bar'))
  })
}

4.多目标任务(相当于子任务)

module.exports = grunt => {
  // 多目标模式,可以让任务根据配置形成多个子任务

  // grunt.initConfig({
  //   build: {
  //     foo: 100,
  //     bar: '456'
  //   }
  // })

  // grunt.registerMultiTask('build', function () {
  //   console.log(`task: build, target: ${this.target}, data: ${this.data}`)
  // })

  grunt.initConfig({
    build: {
      options: {
        msg: 'task options'
      },
      foo: {
        options: {
          msg: 'foo target options'
        }
      },
      bar: '456'
    }
  })

  grunt.registerMultiTask('build', function () {
    console.log(this.options())
  })
}

5.grunt插件使用

插件机制是grunt的核心,因为很多构建任务都是通用的,社区当中也就出现了很多通用的插件,这些插件中封装了很多通用的任务,一般情况下我们的构建过程都是由通用的构建任务组成的。先去npm中安装 需要的插件,再去gruntfile中使用grunt.loadNpmTasks方法载入这个插件,最后根据插件的文档完成相关的配置选项
使用clean插件,可清除文件
- 安装 yarn add grunt-contrib-clean

module.exports = grunt => {
// 多目标任务需要通过initConfig配置目标
  grunt.initConfig({
    clean: {
      temp: 'temp/**' // ** 表示temp下的子目录以及子目录下的文件
    }
  })
  grunt.loadNpmTasks('grunt-contrib-clean')
}
执行:yarn grunt clean ,就会删除temp文件夹

6.Grunt常用插件总结

- grunt-sass
- grunt-babel
- grunt-watch

1. grunt-sass

可查看
官网
github网址

const sass = require('sass')
module.exports = grunt => {
  grunt.initConfig({
    sass: {
      options: {
        sourceMap:true,
        implementation: sass
      },
      main: {
        files: {
          'dist/css/main.css': 'src/scss/main.scss'
        }
      }
    }
  })

  grunt.loadNpmTasks('grunt-sass')
}

2. grunt-babel(将ES6语法转化为ES5)

yarn add grunt-babel @babel/core @babel/preset-env --dev
const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
  grunt.initConfig({
    sass: {
      options: {
        sourceMap:true,
        implementation: sass
      },
      main: {
        files: {
          'dist/css/main.css': 'src/scss/main.scss'
        }
      }
    },
    babel: {
      options: {
        sourceMap: true,
        presets: ['@babel/preset-env']
      },
      main: {
        files: {
          'dist/js/app.js': 'src/js/app.js'
        }
      }
    }
  })

  // grunt.loadNpmTasks('grunt-sass')
  loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
}

3.grunt-contrib-watch(监视文件改变)

const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
  grunt.initConfig({
    sass: {
      options: {
        sourceMap: true,
        implementation: sass, // implementation指定在grunt-sass中使用哪个模块对sass进行编译,我们使用npm中的sass
      },
      main: {
        files: {
          'dist/css/main.css': 'src/scss/main.scss'
        }
      }
    },
    babel: {
      options: {
        presets: ['@babel/preset-env'],
        sourceMap: true
      },
      main: {
        files: {
          'dist/js/app.js': 'src/js/app.js'
        }
      }
    },
    watch: {
      js: {
        files: ['src/js/*.js'],
        tasks: ['babel']
      },
      css: {
        files: ['src/scss/*.scss'],
        tasks: ['sass']
      }
    }
  })

  // grunt.loadNpmTasks('grunt-sass')
  loadGruntTasks(grunt) // 自动加载所有的grunt插件中的任务

  grunt.registerTask('default', ['sass', 'babel', 'watch'])
}

package.json安装对应的依赖

{
  "name": "grunt-demo",
  "version": "0.1.0",
  "main": "index.js",
  "author": "zce <w@zce.me> (https://zce.me)",
  "license": "MIT",
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "grunt": "^1.0.4",
    "grunt-babel": "^8.0.0",
    "grunt-contrib-watch": "^1.1.0",
    "grunt-sass": "^3.1.0",
    "load-grunt-tasks": "^5.1.0",
    "sass": "^1.22.10"
  }
}

5.Gulp

英文官网
中文网址
Gulp是目前世界上最流行的前端构建系统,其核心特点就是高效、易用。它很好的解决了Grunt中读写磁盘慢的问题,Gulp是基于内存操作的。Gulp支持同时执行多个任务,效率自然大大提高,而且它的使用方式相对于Grunt更加易懂,而且Gulp的生态也非常完善

1.gulp的使用

  • 初始化项目yarn init --yes
  • 安装:yarn add gulp
  • 创建gulpfile.js
// gulp的入口文件
exports.foo = done => {
  console.log('foo task working...')
  done() // 使用done()标识任务完成
}

exports.default = done => {
  console.log('default task working...')
  done()
}
  • 执行命令:yarn gulp foo执行foo任务, 或者yarn gulp执行默认任务default
    结果:
    在这里插入图片描述
    gulp4.0之前的任务写法:
const gulp = require('gulp')

gulp.task('bar', done => {
  console.log('bar working...')
  done()
})

执行命令yarn gulp bar可以运行bar任务,gulp4.0之后也保留了这个API,但是不推荐使用了

2.组合任务(串行,并行)

const { series, parallel } = require('gulp')

const task1 = done => {
  setTimeout(() => {
    console.log('task1 working~')
    done()
  }, 1000)
}

const task2 = done => {
  setTimeout(() => {
    console.log('task2 working~')
    done()
  }, 1000)  
}

const task3 = done => {
  setTimeout(() => {
    console.log('task3 working~')
    done()
  }, 1000)  
}

// 让多个任务按照顺序依次执行
exports.foo = series(task1, task2, task3)

// 让多个任务同时执行
exports.bar = parallel(task1, task2, task3)

yarn gulp foo 输出

yarn run v1.22.10
$ D:\CODE\study\02-01-study-materials\02-01-study-materials\code\02-01-03-08-gulp-compose-tasks\node_modules\.bin\gulp foo
[16:10:34] Using gulpfile D:\CODE\study\02-01-study-materials\02-01-study-materials\code\02-01-03-08-gulp-compose-tasks\gulpfile.js
[16:10:34] Starting 'foo'...
[16:10:34] Starting 'task1'...
task1 working~
[16:10:35] Finished 'task1' after 1 s
[16:10:35] Starting 'task2'...
task2 working~
[16:10:36] Finished 'task2' after 1 s
[16:10:36] Starting 'task3'...
task3 working~
[16:10:37] Finished 'task3' after 1 s
[16:10:37] Finished 'foo' after 3.01 s
Done in 3.94s.

yarn gulp gar 输出

yarn run v1.22.10
$ D:\CODE\study\02-01-study-materials\02-01-study-materials\code\02-01-03-08-gulp-compose-tasks\node_modules\.bin\gulp bar
[16:10:43] Using gulpfile D:\CODE\study\02-01-study-materials\02-01-study-materials\code\02-01-03-08-gulp-compose-tasks\gulpfile.js
[16:10:43] Starting 'bar'...
[16:10:43] Starting 'task1'...
[16:10:43] Starting 'task2'...
[16:10:43] Starting 'task3'...
task1 working~
[16:10:44] Finished 'task1' after 1.01 s
task2 working~
[16:10:44] Finished 'task2' after 1.01 s
task3 working~
[16:10:44] Finished 'task3' after 1.01 s
[16:10:44] Finished 'bar' after 1.01 s
Done in 1.93s.

3.Gulp的异步任务

回调方式解决

  • promise的回调方案解决
  • node 环境是8以上的版本可以使用async await
  • stream是最常见的使用方式
const fs = require('fs')

exports.callback = done => {
  console.log('callback task')
  done()// 通过使用done()标志异步任务执行结束
}

exports.callback_error = done => {
  console.log('callback task')
  done(new Error('task failed')) // done函数也是错误优先回调函数。如果这个任务失败了,后序任务也不会工作了
}

exports.promise = () => {
  console.log('promise task')
  return Promise.resolve()// resolve执行的时候,表示异步任务执行结束了。resolve不需要参数,因为gulp会忽略它的参数	
}

exports.promise_error = () => {
  console.log('promise task')
  return Promise.reject(new Error('task failed'))// reject标志这是一个失败的任务,后序的任务也会不再执行
}

const timeout = time => {
  return new Promise(resolve => {
    setTimeout(resolve, time)
  })
}

exports.async = async () => {
  await timeout(1000)// 在node8以上可以使用async和await,await的就是一个Promise对象
  console.log('async task')
}

exports.stream = () => {
  const read = fs.createReadStream('yarn.lock')
  const write = fs.createWriteStream('a.txt')
  read.pipe(write)
  return read
}
//与stream 一致
exports.stream_copy = done => {// 最常用的就是基于stream的异步任务
  const read = fs.createReadStream('yarn.lock')
  const write = fs.createWriteStream('a.txt')
  read.pipe(write)
  read.on('end', () => {
    done()
  })
}

4.构建过程的核心原理

在这里插入图片描述
在这里插入图片描述
gulpfile.js

  • 首先将文件读取出来写入文件流
const fs = require('fs')

exports.default = () => {
  // 文件读取流
  const read = fs.createReadStream('normalize.css')

  // 文件写入流
  const write = fs.createWriteStream('normalize.min.css')
  //把读取出来的文件流导入写入文件流

  read.pipe(write)

  return read
}

  • 将文件转换后再导入
const fs = require('fs')
const { Transform } = require('stream')

exports.default = () => {
  // 文件读取流
  const read = fs.createReadStream('normalize.css')

  // 文件写入流
  const write = fs.createWriteStream('normalize.min.css')
   // 文件转换流
   const transform = new Transform({
    // 核心转换过程
    transform: (chunk, encoding, callback) => {
      // chunk=>读取流中读取到的内容buffer
      const input = chunk.toString()

      //替换掉空格,和注释
      const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
      callback(null, output)
    }
  })

  //把读取出来的文件流导入写入文件流
  read
  .pipe(transform)
  .pipe(write)
  
  return read
}

5.Gulp文件操作API

  • yarn add gulp-clean-css --dev 压缩css代码
  • yarn add gulp-rename --dev
const { src, dest } = require('gulp')
const cleanCSS = require('gulp-clean-css')
const rename = require('gulp-rename')
// 模拟 gulp 的原理:  读取流 => 转换流  => 写入流
exports.default = () => {
  return src('src/*.css')
    .pipe(cleanCSS())
    .pipe(rename({ extname: '.min.css' }))
    .pipe(dest('dist'))
}

运行后的结果
在这里插入图片描述

6.Gulp 案例

模拟构建:
在这里插入图片描述

安装的依赖

  • yarn add gulp --dev
  • yarn add gulp-sass --dev 处理 sass
  • yarn add gulp-babel @babel/core @babel/preset-env --dev 处理 es6+
  • yarn add gulp-swig --dev 模板引擎
  • yarn add gulp-imagemin --dev图片处理
  • yarn add gulp-load-plugins --dev 自动加载gulp插件 解决文件顶部插件引入很多,导致代码比较繁杂的问题
  • yarn add del --dev 清除文件
  • yarn add browser-sync --dev 开发服务器 支持HMR
  • yarn add gulp-useref --dev 处理文件引用关系
  • yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev 压缩文件
  • yarn add gulp-if --dev 判断 流的类型
  • yarn add bootstrap jquery popper.js 项目启动的其他依赖

1.样式的编译任务

const { src, dest } = require("gulp");
const sass = require("gulp-sass");

// scss 转 css
const style = () => {
  // 指定从 src 下保留路径
  return (
    src("src/assets/styles/*.scss", { base: "src" })
     // sass对_icons.css,默认不编译
     .pipe(sass({ outputStyle: "expanded" }))
      .pipe(dest("dist"))
  );
};

module.exports = {
  style
}

2.脚本的编译任务

const { src, dest } = require("gulp");
const sass = require("gulp-sass");
const babel = require('gulp-babel')

// scss 转 css
const style = () => {
  // 指定从 src 下保留路径
  return (
    src("src/assets/styles/*.scss", { base: "src" })
     // sass对_icons.css,默认不编译
     .pipe(sass({ outputStyle: "expanded" }))
      .pipe(dest("dist"))
  );
};
const script = () => {
  // 指定从 src 下保留路径
  return (
    src("src/assets/scripts/*.js", { base: "src" })
      //  ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
      .pipe(babel({ presets: ['@babel/preset-env'] }))
      .pipe(dest("dist"))
  );
};

module.exports = {
  style,
  script
}

3.页面模板的编译任务

const { src, dest, parallel } = require("gulp");
const sass = require("gulp-sass");
const babel = require('gulp-babel')
const swig = require("gulp-swig");

const data = {
  menus: [
    {
      name: "Home",
      icon: "aperture",
      link: "index.html",
    },
    {
      name: "Features",
      link: "features.html",
    },
    {
      name: "About",
      link: "about.html",
    },
    {
      name: "Contact",
      link: "#",
      children: [
        {
          name: "Twitter",
          link: "https://twitter.com/w_zce",
        },
        {
          name: "About",
          link: "https://weibo.com/zceme",
        },
        {
          name: "divider",
        },
        {
          name: "About",
          link: "https://github.com/zce",
        },
      ],
    },
  ],
  pkg: require("./package.json"),
  date: new Date(),
};

// scss 转 css
const style = () => {
  // 指定从 src 下保留路径
  return (
    src("src/assets/styles/*.scss", { base: "src" })
     // sass对_icons.css,默认不编译
     .pipe(sass({ outputStyle: "expanded" }))
      .pipe(dest("dist"))
  );
};
const script = () => {
  // 指定从 src 下保留路径
  return (
    src("src/assets/scripts/*.js", { base: "src" })
      //  ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
      .pipe(babel({ presets: ['@babel/preset-env'] }))
      .pipe(dest("dist"))
  );
};
const page = () => {
  // src/**/*.html 匹配任意子目录
  return src("src/*.html", { base: "src" })
    .pipe(swig({data }))
    .pipe(dest("dist"));
};

// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page)
module.exports = {
  compile
}

运行 yarn gulp compile

4.图片和字体文件的转换

const image = () => {
  return src('src/assets/images/**', { base: 'src' })
    .pipe(imagemin())
    .pipe(dest('dist'))
}
const font = () => {
  return src('src/assets/fonts/**', { base: 'src' })
    .pipe(imagemin())
    .pipe(dest('dist'))
}

// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page, image, font)

5.其他文件清除

const del = require("del")
// 清除文件
const clean = () => {
  // del 返回的是个 promise
  return del(["dist"]);
};
const extra = () => {
  return src('public/**', { base: 'public' })
    .pipe(dest('dist'))
}

// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page, image, font)
const build = series(clean,parallel(compile,extra))


module.exports = {
  compile,
  build
}

6.自动加载插件

安装 gulp-load-plugins

const loadPlugins = require("gulp-load-plugins");
const plugins = loadPlugins();
//sass 修改为plugins.sass

7. 开发服务器

browser-sync安装

const browserSync = require('browser-sync')
const bs = browserSync.create()
const serve = () => {
  bs.init({
    notify: false,
    port: 2080,
    // open: false,
    files: 'dist/**',
    server: {
      baseDir: 'dist',
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

8. 监视变化以及构建优化

watch
考虑如何在src原代码修改后自动编译

const serve = () => {
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  // watch('src/assets/images/**', image)
  // watch('src/assets/fonts/**', font)
  // watch('public/**', extra)
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'
  ], bs.reload)
  bs.init({
    notify: false,
    port: 2080,
    // open: false,
    files: 'dist/**',// 监听 dist 文件变化刷新
    server: {
      baseDir: ['dist', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page)

//上线之前执行的任务
const build = series(clean,parallel(compile,image, font,extra))
const develop = series(compile, serve)

module.exports = {
  clean,
  compile,
  build,
  serve,
  develop
}

9. useref文件引用处理

gulp-useref 根据构建注释构建css,js 路径
目前存在的一些问题:

  • dist中的index.html文件为例。引用的node_modules的文件目录,部署上线后,会找不到对应的目录
  • 未使用useref时文件内容 dist中的index.html部分内容
  <!-- build:css assets/styles/vendor.css -->
  <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
  <!-- endbuild -->
  <!-- build:css assets/styles/main.css -->
  <link rel="stylesheet" href="assets/styles/main.css">
  <!-- endbuild -->

gulpfile.js文件

const useref = () => {
  return src('dist/*.html', { base: 'dist' })
    .pipe(plugins.useref({ searchPath: ['dist', '.'] }))
    // html js css
    .pipe(dest('dist'))
}

使用后

  <link rel="stylesheet" href="assets/styles/vendor.css">
  <link rel="stylesheet" href="assets/styles/main.css">

10. 文件压缩

  • gulp-htmlmin 压缩 HTML 文件
  • gulp-uglify 压缩 JS 文件
  • gulp-clean-css 压缩 CSS 文件
  • gulp-if 判断文件类型
const useref = () => {
  return src('dist/*.html', { base: 'dist' })
    .pipe(plugins.useref({ searchPath: ['dist', '.'] }))
    // html js css
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      collapseWhitespace: true,
      minifyCSS: true,
      minifyJS: true
    })))
    .pipe(dest('dist'))
}

11.重新规划合理的构建过程

  • 添加临时文件 tmp 避免读写流冲突(不能读写都是dist 文件)
const { src, dest, parallel, series, watch } = require("gulp");
const del = require("del")
const browserSync = require("browser-sync");

const loadPlugins = require("gulp-load-plugins");

const plugins = loadPlugins();

const bs = browserSync.create()

// const sass = require("gulp-sass");
// const babel = require('gulp-babel')
// const swig = require("gulp-swig");
// const imagemin = require("gulp-imagemin")

const data = {
  menus: [
    {
      name: "Home",
      icon: "aperture",
      link: "index.html",
    },
    {
      name: "Features",
      link: "features.html",
    },
    {
      name: "About",
      link: "about.html",
    },
    {
      name: "Contact",
      link: "#",
      children: [
        {
          name: "Twitter",
          link: "https://twitter.com/w_zce",
        },
        {
          name: "About",
          link: "https://weibo.com/zceme",
        },
        {
          name: "divider",
        },
        {
          name: "About",
          link: "https://github.com/zce",
        },
      ],
    },
  ],
  pkg: require("./package.json"),
  date: new Date(),
};

// 清除文件
const clean = () => {
  // del 返回的是个 promise
  return del(["dist","temp"]);
};

// scss 转 css
const style = () => {
  // 指定从 src 下保留路径
  return (
    src("src/assets/styles/*.scss", { base: "src" })
     // sass对_icons.css,默认不编译
     .pipe(plugins.sass({ outputStyle: "expanded" }))
      .pipe(dest("temp"))
  );
};
const script = () => {
  // 指定从 src 下保留路径
  return (
    src("src/assets/scripts/*.js", { base: "src" })
      //  ES6+ 处理 注意这里要提供 babel 预设, 不然就不转换
      .pipe(plugins.babel({ presets: ['@babel/preset-env'] }))
      .pipe(dest("temp"))
      .pipe(bs.reload({ stream: true }))
  );
};
const page = () => {
  // src/**/*.html 匹配任意子目录
  return src("src/*.html", { base: "src" })
    .pipe(plugins.swig({data }))
    .pipe(dest("temp"));
};

const image = () => {
  return src('src/assets/images/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}
const font = () => {
  return src('src/assets/fonts/**', { base: 'src' })
    .pipe(plugins.imagemin())
    .pipe(dest('dist'))
}

const extra = () => {
  return src('public/**', { base: 'public' })
    .pipe(dest('dist'))
}


const serve = () => {
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  // watch('src/assets/images/**', image)
  // watch('src/assets/fonts/**', font)
  // watch('public/**', extra)
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'
  ], bs.reload)
  bs.init({
    notify: false,
    port: 2080,
    // open: false,
    // files: 'dist/**',
    server: {
      baseDir: ['temp', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}
const useref = () => {
  return src('temp/*.html', { base: 'temp' })
    .pipe(plugins.useref({ searchPath: ['temp', '.'] }))
    // html js css
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      collapseWhitespace: true,
      minifyCSS: true,
      minifyJS: true
    })))
    .pipe(dest('dist'))
}

// 并行执行 样式-脚本-页面 编译
const compile = parallel(style, script, page)

//上线之前执行的任务
const build = series(clean,parallel(series(compile, useref),image, font,extra))
const develop = series(compile, serve)

module.exports = {
  clean,
  compile,
  build,
  serve,
  develop,
  useref
}

12.问题

导出可用任务,并放到scripts中

module.exports = {
  clean,
  build,
  develop
}

package.json

{
  "name": "zce-gulp-demo",
  "version": "0.1.0",
  "main": "index.js",
  "repository": "https://github.com/zce/zce-gulp-demo.git",
  "author": "zce <w@zce.me> (https://zce.me)",
  "license": "MIT",
  "scripts": {
    "clean": "gulp clean",
    "build": "gulp build",
    "develop": "gulp develop"
  },
  "dependencies": {
    "bootstrap": "^4.3.1",
    "jquery": "^3.4.1",
    "popper.js": "^1.15.0"
  },
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "browser-sync": "^2.26.7",
    "del": "^5.1.0",
    "gulp": "^4.0.2",
    "gulp-babel": "^8.0.0",
    "gulp-clean-css": "^4.2.0",
    "gulp-htmlmin": "^5.0.1",
    "gulp-if": "^3.0.0",
    "gulp-imagemin": "^6.1.0",
    "gulp-load-plugins": "^2.0.1",
    "gulp-sass": "^4.0.2",
    "gulp-swig": "^0.9.1",
    "gulp-uglify": "^3.0.2",
    "gulp-useref": "^3.1.6"
  }
}

.gitignore中忽略下生成的目录

  • dist
  • temp

13. 封装自动化构建工作流

在这里插入图片描述
在这里插入图片描述

gulpfile.js复用

  • 创建一个模块,将模块发布npm,新项目使用npm
  • 将gulpfile 中的代码替换到入口文件
  • 将 gulpfile 完成项目中的 package.json 依赖拷入新 package.json 项目依赖(dependencies)
  • 将模块 yarn link 到全局
  • 在项目中使用link的模块
  • 提取公共配置文件

6 FIS

FIS是百度的前端团队推出的构建系统,FIS相对于前两种微内核的特点,它更像是一种捆绑套餐,它把我们的需求都尽可能的集成在内部了,例如资源加载、模块化开发、代码部署、甚至是性能优化

  • 基本使用
yarn global add fis3

执行fis3 release查看效果

  • 创建 fis-conf.js
 fis.match('*.{js,scss,png}', {
  release: '/assets/$0'
})

fis.match('**/*.scss', {
  rExt: '.css',
  parser: fis.plugin('node-sass'),
  optimizer: fis.plugin('clean-css')
})

fis.match('**/*.js', {
  parser: fis.plugin('babel-6.x'),
  optimizer: fis.plugin('uglify-js')
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值