- 将源代码编译成在线上环境运行的过程
- 优势:
- 编码阶段可以使用最新语法,提高开发效率
- 例如使用sass编写css,使用NPM scripts定义命令
- 常用的自动化构建工具
- Grunt:项目大的时候构建速度慢,基于磁盘读写
- Gulp:基于内存实现,默认同时执行多个任务
- FIS
Grunt
- yarn add grunt
- 创建gruntfile.js
// gruntfile.js 是grunt的入口// 用于定义一些需要grunt 自动执行的任务module.exports = grunt => {// 默认任务//grunt.registerTask('default', () => {////})grunt.registerTask('default',[ 'foo', 'bar'])grunt.registerTask('foo', () => {})grunt.registerTask('bar', () => {})// 异步操作grunt.registerTask('async-task', function() {const done = this.async()setTimeout(()=>{done()},1000)})}
Grunt标记任务失败
module.exports = grunt => {grunt.registerTask('bar', () => {return false})grunt.registerTask('async-task', function() {const done = this.async()setTimeout(()=>{done(false)},1000)})}//-- force 强制后面任务执行
Grunt配置选项方法
module.exports = grunt => {grunt.initConfig({foo: {bar: 123}})grunt.registerTask("foo",() => {console.log(grunt.config('foo.bar'))})}
Grunt多目标任务
module.exports = grunt => {grunt.initConfig({build: {options:{foo: 'bar'},css: {options: {foo: 'baz' // 会覆盖上面的值}},js: ''}})// 多目标模式,可以让任务根据配置形成多个子任务grunt.registerMultiTask('build', function () {console.log(this.options())console.log(`target: ${this.target}, data: ${this.data}`)})}
Grunt插件的使用
// 封装了通用的构建任务// grunt-contrib-clean 清除文件module.exports = grunt => {grunt.initConfig({clean:{temp: 'temp/**' // "temp/*.txt"}})grunt.loadNpmTasks('grunt-contrib-clean')}
Grunt常用插件
grunt-sass
// yarn add grunt-sass sassconst 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')}
grunt-babel
load-grunt-tasks
// yarn add grunt-babel @babel/core @babel/preset-env --dev// yarn add load-grunt-tasks --devconst loadGruntTasks = require('load-grunt-tasks')module.exports = grunt => {grunt.initConfig({babel:{options: {presets: ['@babel/preset-env'],sourceMap: true}main:{files: {"dist/js/app.js": 'src/js/app.js'}}}})loadGruntTasks(grunt) // 自动加载所有的grunt插件中的任务}
grunt-contrib-watch
module.exports = grunt => {grunt.initConfig({watch:{options: {presets: ['@babel/preset-env'],sourceMap: true}js: {files: ['src/js/*.js'],tasks: ['babel']},css: {files: ['src/scss/*.scss'],tasks: ['sass']}}})loadGruntTasks(grunt) // 自动加载所有的grunt插件中的任务grunt.registerTask('default',['sass','babel','watch'])}
Gulp
- yarn init 初始化package.json
- yarn add gulp —dev
- 创建gulpfile.js 入口文件
exports.foo = done => {conosle.log('foo task working')done() // 标识任务完成}// gulp fooexport.default = done => {console.log('default task')done()}// 直接运行 gulp// gulp4.0之前需要先引入gulpconst gulp = require('gulp')gulp.task('bar', done => {console.log("bar task")done()})
Gulp组合任务
const { series, parallel } = require('gulp')const task1 = done => {setTimeout(() => {console.log('task1')done()}, 1000)}const task2 = done => {setTimeout(() => {console.log('task1')done()}, 1000)}const task3 = done => {setTimeout(() => {console.log('task1')done()}, 1000)}exports.foo = series(task1, task2, task3)// 按顺序进行exports.bar = parallel(task1, task2, task3) // 同时进行
Gulp中的异步任务
// doneexports.callback_error = done => {done(new Error('task failed'))}exports.promise = () => {return Promise.resolve()}exports.promise_error = () => {return Promise.reject()}const timeout = time => {return new Promise( resolve => {setTimeout(resolve, time)})}exports.async = async () => {await timeout(1000)}// 这种方式看node版本支不支持async awaitexports.stream = () => {const readStream = fs.createReadStream('package.json')const writeStream = fs.createWriteStream('temp.txt')readStream.pipe(writeStream)return readStream}// stream 中end事件触发结束任务exports.stream = done => {const readStream = fs.createReadStream('package.json')const writeStream = fs.createWriteStream('temp.txt')readStream.pipe(writeStream)readStream.on('end', () => {done()})}
Gulp构建过程核心工作原理
const fs = require('fs')const { Transform } = require('stream')exporta.default = () => {const read = fs.createReadStream('normalize.css')const write = fs.createWriteStream('normalize.min.css')// 文件转换流const transform = new Transform({// 核心转换过程实现// chunk 读取流中读取到的内容(Buffer)const input = chunk.toString()const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')callback(null, output)})read.pipe(transform).pipe(write)}// gulp是基于文件流的构建方式
Gulp文件操作API + 插件的使用
const { src, dest } = require('gulp')const cleanCss = require('gulp-clean-css')const rename = require('gulp-rename')export.default = () => {return src('src/*.css').pipe(cleanCss()).pipe(rename({ extname: '.min.css' })).pipe(dest('dist'))}
Gulp案例
// yarn add gulp --dev// 项目根目录新建gulpfile.js文件const { src, dest, parallel, series } = require('gulp')// 自动加载插件const loadPlugins = require('gulp-load-plugins')const plugins = loadPlugins()//const sass = require('gulp-sass')//const babel = require('gulp-babel') // 需要安装@babel/core @babel/preset-env//const swig = require('gulp-swig')//const imagemin = require('gulp-imagemin')//const del = require('del')const style = () => {return src('src/assets/styles/*.scss', { base: 'src' })// 保留原本目录结构.pipe(plugins.sass({ outputStyle: 'expanded' })).pipe(dest('temp')).pipe(fs.reload({ stream: true })) // 与bs配置中的files属性用途类似}const script = () => {return src('src/assets/scripts/*.js', { base: 'src' }).pipe(plugins.babel({ presets: ['@babel/preset-env'] })).pipe(dest('temp'))}const page = () => {return src('src/**/*.html', { base: 'src' }).pipe(plugins.swig( { data, cache: false } )) // 将模板需要的数据导入.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 clean = () => {return del(['dist','temp'])}const compile = parallel(style, script, page, image, font)const build = series(clean, parallel(compile, extra))module.exports = {build}
Gulp配置开发热更新服务器
// browsersyncconst { watch } = require('gulp')const browsersync = require("browser-sync")const bs = browsersync.create()const server = () => {// 监听src源代码的变化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({server: {notify: false,port: 8080,open: true,//files: 'temp/**', // 用来被监听的文件baseDir: ['temp','src','public'],routes: {'/node_modules': 'node_modules'}}})}module.exports = {server}
Gulp文件引用处理 useref
// 将html中的build:css等构建注释的地方转换// yarn add gulp-useref --devconst useref = () => {return src('temp/*.html', { base: 'dist' }).pipe(plugins.useref({ searchPath: ['dist', '.'] }))// html js css 压缩 gulp-htmlmin gulp-uglify gulp-clean-css gulp-if.pipe(plugins.if(/\.js$/, plugins.uglify())).pipe(plugins.if(/\.html$/, plugins.htmlmin({ collapseWhitespace: true, minifyCss: true, minifyJs: true }))) // style script 标签中代码压缩.pipe(plugins.if(/\.css$/, plugins.cleanCss())).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,build,develop}
- 可以将构建命令放到package.json的scripts中
