介绍
自动化构建工作流 就是 把开发出来的源代码自动化转换成生产环境中可以运行的代码或者程序
脱离运行环境兼容带来的问题
开发阶段去使用高效率的语法、规范和标准
构建转换那些不被支持的特性
常用的自动化构建工具
Grunt Gulp FIS
Grunt工作过程基于临时文件,构建速度较慢 ,每一步都会有磁盘读写的操作,超大型项目会很慢,生态完善
Gulp很好解决了构建速度问题,基于 内存实现,默认支持同时执行多个任务,生态完善
FIS更像是捆绑套餐,把项目中典型的需求全部集成到内部了,资源加载,模块化开发,代码部署 ,甚至是性能优化,大而全,所以流行
Grunt基本使用
mkdir grunt-sample
cd grunt-sample
yarn init -y
yarn add grunt
在根目录创建gruntfile.js
// grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接受一个 grunt 的形参,内部提供一些创建任务时可以用到的API
module.exports = grunt => {
// yarn grunt foo
grunt.registerTask('foo',() => {
console.log('hellow grunt');
})
// yarn grunt bar
grunt.registerTask('bar','任务描述',() => {
console.log('other task');
})
// grunt.registerTask('default',() => {
// console.log('default task');
// })
// 默认任务
// yarn grunt
grunt.registerTask('default',['foo','bar'])
// 错误异步任务
// grunt.registerTask('async-task',() => {
// setTimeout(() => {
// console.log('async task');
// }, 1000);
// })
// 正确异步任务
grunt.registerTask('async-task', function() {
const done = this.async();
setTimeout(() => {
console.log('async task');
// 标记任务结束,异步完成
done();
}, 1000);
})
}
grunt标记错误
// 失败任务
grunt.registerTask('bad',() => {
console.log('bad');
return false;
})
// 任务列表中失败任务会阻塞之后任务的执行
// 可以采用 --force(yarn grunt --force)全部执行
grunt.registerTask('default',['foo','bad','bar'])
// 异步任务标记失败
grunt.registerTask('bad-async', function() {
const done = this.async();
setTimeout(() => {
console.log('bad-async');
// 标记任务失败
done(false);
}, 1000);
})
grunt多目标任务
// 配置属性
grunt.initConfig({
// 任务名称
build: {
// 配置 选项
options: {
foo: 'bar'
},
css: {
// 子任务的配置选项会覆盖父任务
options: {
foo: 'baz'
}
},
js: '2',
}
})
// 多目标任务
grunt.registerMultiTask('build',function() {
// 获取配置选项
console.log(this.options())
console.log(`target: ${this.target},data: ${this.data}`)
console.log('build task')
})
grunt插件使用
以安装 sass 和babel为例
yarn add grunt-sass sass
yarn add grunt-babel @babel/core @babel/preset-env
使用插件需要
grunt.loadNpmTasks('插件名')
使用插件过多建议使用load-grunt-tasks
yarn add load-grunt-tasks --dev
只需
const loadGruntTasks = require('load-grunt-tasks')
loadGruntTasks(grunt)
即可全部引用
有时还需要监听文件修改完之后需要自动编译
安装 yarn add grunt-contrib-watch
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'
}
}
},
watch: {
js: {
files: ['src/js/*.js'],
tasks: ['babel']
},
css: {
files: ['src/css/*.scss'],
tasks: ['sass']
}
}
})
// grunt.loadNpmTasks('grunt-sass')
loadGruntTasks(grunt)
grunt.registerTask('default',['sass','babel','watch'])
}
Gulp
基本使用
mkdir gulp-sample
cd gulp-sample
yarn init -y
yarn add gulp --dev
安装gulp的同时也会安装gulp-cli可以使用一些gulp的命令完成我们的构建任务
创建gulp.js入口文件
通过exports导出一个函数,即为注册了一个任务,现在都是异步任务,可以通过注册任务时的形参可以 标记任务结束
default为默认任务
在4.0以前是通过gulp的一个方法来注册
// gulp入口文件
const gulp = require('gulp');
gulp.task('bar',done => {
console.log('bar');
done();
})
exports.default = done=>{
console.log('default task')
done();
}
exports.foo= done =>{
console.log('foo task')
done()
}
组合任务
可以通过gulp中的 series 和 parallel组合成一个组合任务
series(串行结构) 可以接收任务,会依次执行列表 中的任务
parallel(并行结构)可以接收任务,会同步执行列表中的任务
// gulp入口文件
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)
处理异步流程操作
- 通过形参来标记任务的任务的成功或者失败
- 通过返回promise来标记任务的成功或者失败
- 通过end事件来标记任务的成功或者失败
const fs = require('fs')
exports.promise = () => {
console.log('promise task')
return Promise.resolve()
}
exports.promise_error = () => {
console.log('promise task')
return Promise.reject(new Error('task failed'))
}
const timeout = time => {
return new Promise((resolve, reject) => {
setTimeout(resolve, time);
})
}
exports.async = async () => {
await timeout(1000)
console.log('async task')
}
exports.strem = done => {
const readStream = fs.createReadStream('package.json')
const writeStream = fs.createWriteStream('temp.txt')
readStream.pipe(writeStream)
return readStream
}
构建过程核心工作原理
读取流=>转换流=>写入流
gulp被称为基于流的构建系统,构建过程为什么采用构建流的方式,因为gulp希望实现一个构建管道的概念,在使用插件时,有一个很统一的方式
gulp文件操作api
一般使用
// 读取流,写入流
const { src,dest } = require('gulp')
// 压缩css转换流插件
const cleanCss = require('gulp-clean-css')
// 重命名转换流插件
const rename = require('gulp-rename')
// 默认任务
exports.default = () => {
return src('src/*.css')
.pipe(cleanCss())
.pipe(rename({
extname: '.min.css'
}))
.pipe(dest('dist'))
}