前端工程化-Grunt

125 阅读2分钟

基本使用

在项目的的根目录下定义一个gruntfule.js

// Grunt 的入口文件
// 用于定义定义一些需要grunt立即执行的任务
// 需要导出一个函数, 此函数接收一个名叫 grunt 的形参,内部提供一些创建任务时可以用到的 API
module.exports = grunt => {
    grunt.registerTask(
        'foo', // 任务名称,如果是 default ,它将会成为grunt的默认任务
        '任务描述', // 任务描述,会出现在 grunt 的帮助信息当中
        () => { // 任务被调用时执行的函数,如果第三个参数是数组,Grunt 会依次执行数组中的每一项任务
            console.log('Hello grunt ~')
        }
    ) // yarn grunt foo
    grunt.registerTask(
        'async-task',
         function () {
            const done = this.async()
            setTimeout(() => {
                console.log('async task working ~')
                done()
            }, 1000)
         }
    ) // 
}

标记任务失败

如果在构架任务的逻辑代码当中发生错误,例如需要的文件找不到了,此时就可以将这个任务标记成失败。具体的实现方式就是在一个函数体当中去return false来实现。

module.exports = grunt => {
    grunt.registerTask(
        'bad',
        () => {
            console.log('bad task ~')
            return false
        }
    )
    grunt.registerTask(
        'foo',
        () => {
           console.log('foo task ~') 
        }
    )
    grunt.registerTask(
        'bar',
        () => {
            console.log('bar task ~')
        }
    )
    grunt.regesterTask('default', ['foo', 'bad', 'bar']) // yarn grunt
    grunt.registerTask(
        'bad-async',
        function () {
            const done = this.async()
            setTimeout(_ => {
                console.log('bad-async task ~')
                done(false)
            }, 1000)
        }
    )
}

配置方法

除了registerTask方法外,grunt还提供了一个用于去添加一些配置选项的API叫做initConfig,例如我们在使用 grunt 去压缩文件时就可以通过这种方式去配置我们需要依赖的压缩的文件路径。

module.exports = grunt => {
    grunt.initConfig({
        foo: {
            bar: 123
        }
    })
    grunt.regesterTask(
        'foo',
        () => {
            console.log(grunt.config('foo.bar'))
        }
    )
}

多目标任务

除了普通的任务形式以外,grunt还支持多目标模式任务,可以理解成子任务的概念这种形式的任务,在后续具体去通过grunt实现各种构建任务时非常有用。

module.exports = grunt => {
    grunt.initConfig({
        build: {
            css: 1,
            js: { // 目标的options 会覆盖掉,外部的同名options
                foo: 120
            },
            options: { // option 会作为配置选项
                foo: 100
            }
        }
    })
    // 多目标模式,可以让任务根据配置形成多个子任务
    grunt.regesterMultiTask(
        'build', // 任务名称
        () => { // 任务函数
            console.log(this.options())
            console.log(`traget:${this.target}, data:${this.data}`)
        }
    )
}

插件的使用

插件机制是grunt的核心,它存在的原因也非常简单因为很多构建任务都是通用的。一般情况下构建过程都是由这些通用的构建任务组成的,使用插件的过程非常简单。大体上就是先通过npm 安装这个插件yarn add grunt-contrib-clearn,在到gruntfile当中去载入这个插件提供的一些任务grunt.loadNpmTasks('grunt-contrib-clearn')。最后根据这些插件的文档,去完成相应的配置选项。

module.exports = grunt => {
    grunt.initConfig({
        clearn: {
            temp: 'temp/*.txt'
        }
    })
    grunt.loadNpmTasks('grunt-contrib-clearn')
}

常用插件及总结

yarn add load-grunt-tasks --dev / yarn add grunt-sass sass --dev / yarn add grunt-babel @babel/core @babel/preset-env --dev / yarn add grunt-contrib-watch --dev

const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')
module.exports = grunt => {
    grunt.initConfig({
        sass: {
            options: {
                implementation: sass,
                sourceMap: true
            },
            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/main.scss'],
                tasks: ['sass']
            }
        }
    })
    // grunt.loadNpmTasks('grunt-sass')
    loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
    gtunt.regesterTask('default', ['sass', 'babel', 'watch'])
}