自动化构建01——Grunt
概述
什么叫构建?
简单的来说就是把开发环境中的代码,给加工成生产环境的代码。
什么叫自动化?
就是不用程序员自己手动去做,而是交给工具去做
所以 所谓自动化构建 也就是通过工具 自动把开发环境的代码构建成生产环境的代码。
而这种转化的过程 称之为 自动化构建工作流。
最典型的就是我们在前端开发中使用的一些浏览器不支持的ES新特性,使用一些CSS的预处理器等等,最后项目完成我们需要把这些代码构建成生成环境能够执行的代码
常见的自动化构建工具
- Grunt (特点 功能多 构建慢)
- Gulp (好用)
- F.I.S (百度出品 功能大而全)
- webpack 是一个模块打包器,不在这个讨论范围之内
Grunt
最初我接触grunt,不是因为我知道它是什么东西,而是我单纯的觉得这玩意的logo有意思。
我好奇这个大犹猪到底是什么玩意。所以抱着这种心态才去了解的grunt。
这么一说初次接触这个东西要追述到2016年的时候了,但是因为并没有频繁使用,这么多年也都没有在实际项目中使用过它,所以grunt对于我来说,应该是 “有点熟悉的陌生工具”。
基本用法
注册执行任务 grunt.registerTask()
- 创建项目目录并初始化
yarn init
- 安装Grunt
yarn add grunt
- 在目录中创建 gruntfile.js 文件,这个文件用于定义一些需要grunt自动执行的任务
- 这个文件需要向外导出一个函数,这个函数接收一个形参grunt,它是一个对象,提供了一些在构建时用到的API
module.exports = grunt => {
/**
* registerTask 注册要执行的任务
* @param { string } 任务名称
* @param { string } 任务描述 可选参数
* @param { fn } 这个任务要执行的函数
*/
grunt.registerTask('foo','foo Task', () => {
console.log('hello grunt');
})
}
- 运行
yarn grunt foo
来执行这个任务,可以在终端看到执行结果 - 如果有多个任务 可以继续在后面添加grunt.registerTask
- 如果任务的名称是
default
那么这个任务会变成grunt的默认任务 那么在执行的时候 就可以省略任务名称 直接去执行yarn grunt
- 在default任务的第二个参数上,我们可以传入一个任务名称数组,这样在执行grunt的时候 就会依次去执行 数组里的任务
module.exports = grunt => {
/**
* registerTask 注册要执行的任务
* @param { string } 任务名称
* @param { string } 任务描述 可选参数
* @param { fn } 这个任务要执行的函数
*/
grunt.registerTask('foo','foo Task', () => {
console.log('hello grunt');
})
grunt.registerTask('bar',()=>{
console.log('bar TASK DONE');
})
grunt.registerTask('default',["foo","bar"])
}
- grunt 执行异步任务的时候,需要调用this.async() 方法得到一个done函数,在异步的回调中调用done函数,grunt在执行任务时 会等待这个done方法。
grunt.registerTask('asyncTask',function(){
const done = this.async()
setTimeout(()=>{
console.log('异步任务');
done()
},1000)
})
给任务添加执行错误标记
在添加任务函数的时候,我们会根据代码执行逻辑添加一些判断,如果进入错误逻辑,我们可以通过 return false
来标记这个任务是失败的。
而在任务列队中,一旦某一个任务执行错误了,那么后续的任务就都不会继续执行。
可以看到因为bar 被标记执行失败,在它之后的asyncTask任务就不会执行了。在执行结果中,我们可以看到有一句提示 Warning: Task "bar" failed. Use --force to continue.
让我们运行的时候 加上 --force 这样的话我们就可以继续执行后续的任务了 。
如果是异步任务需要标记执行错误,我们就不能return false了 需要在done中传入false
grunt.registerTask('asyncTask',function(){
const done = this.async()
setTimeout(()=>{
console.log('异步任务');
done(false) // 标记异步任务执行错误
},1000)
})
为任务添加配置选项 grunt.initConfig()
什么叫做为任务添加配置选项呢?简单的来说,就是我们可以通过initConfig方法设置一些任务需要用的参数。
通过 grunt.initConfig()
方法传递配置项给对应的任务。在任务中,使用grunt.config( 任务名称 )
来获取任务配置选项数据
initConfig 为任务传递配置选项,@param { Object } key: 任务的名称, value: 值可以是任意类型的数据
grunt.config 接收配置信息, 如果传递的配置数据是一个对象方式的方式可以写成:
- grunt.config(‘foo’).arg_1st
- grunt.config(‘foo.arg_2nd’)
为任务添加多个目标
什么叫做任务的多个目标? 玩过游戏的朋友应该比较了解,游戏里经常会接收NPC的任务,任务中有多个目标,只有这些目标都完成了,任务才能完成。
grunt也可以为任务配置多个目标
module.exports = grunt => {
// 配置多目标任务
grunt.initConfig({
multiTask: {
options: {
arg_1st: '多任务配置项参数1'
},
css: {
options:{
target_arg_1st:'目标1的配置项参数'
},
msg:'css_data'
},
js: "js_target_2"
}
})
grunt.registerMultiTask('multiTask', function(){
console.log(this.options());
console.log(`任务目标:${ this.target },data:${ this.data }`);
})
}
这里我们通过grunt.registerMultiTask方法来创建拥有多个目标的任务,在initConfig中一样可以为它传入配置选项,但是因为是多目标任务,任务配置选项要放在 options 属性中。
在执行任务的时候,每一个目标都会去执行 任务的执行函数。 其中 this.target 可以获得任务目标的名称,this.data可以获得任务目标的数据
如果在initConfig 里添加任务目标的时候 ,目标也写成对象的形式 并配置了 options 参数 那么options 中的值就是该目标的任务配置选项。
使用loadnpmtask执行grunt插件任务
Grunt 生态系统非常庞大,并且一直在增长。由于拥有数量庞大的插件可供选择,因此,你可以利用 Grunt 自动完成任何事,并且花费最少的代价
基本上所有的构建工作,都有对应的插件,我们只需要执行对应的插件任务就可以解决各种构建需求。
使用插件分为以下几个步骤:
- 安装需要的插件
- 引入插件任务
- 在intiConfig传入任务配置选项
比如 我们安装一个grunt-contrib-clean 插件用来清除多余的临时文件,grunt的插件名字 都是grunt-contrib-名字的格式
module.exports = grunt => {
grunt.initConfig({
clean: {
temp: 'temp/**' // ** 表示通配符删除所有temp目录下的文件
}
})
// 加载插件任务
grunt.loadNpmTasks('grunt-contrib-clean')
}
执行 yarn grunt clean 之后 ,temp下的文件就被移除了
常用的grunt插件
grunt 的插件非常多 我们可以在官网看到很多常用的。比如 grunt-sass, grunt-babel, grunt-contrib-watch 等等。
有的时候因为插件比较多,可以使用 loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
在使用 watch 监听文件变化的时候一开始不会自动先执行编译操作,只有等待文件变化才会编译,可以先执行一次default 编译一次文件 比如:
grunt.registerTask('default', ['sass', 'babel', 'watch'])
更多插件参考官方文档: grunt 插件