`
liuguofeng
  • 浏览: 453181 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

Gurnt任务的配置

 
阅读更多

在《Grunt教程——初涉Grunt》和《Grunt教程——安装Grunt》中得知,Grunt项目中都是通过Gruntfile.js来配置任务。可以说,Gruntfile.js文件在任何一个Grunt项目中都是必不可少的,从这也可以看出这个文件的重要性。欲要搞清楚Grunt怎么工作,就必须要先了解Grunt是如何通过Gruntfile.js配置任务,帮助你实现你需要的功能。如果你还不知道Gruntfile.js是什么,建议您先阅读Grunt了解一下,如果你觉得这样麻烦,也不必过于担心,你也可以通过下面将要介绍的内容,深入的了解Gruntfile.js,并学习如何配置。

Gruntfile.js创建

假设您已经在你的系统中创建了一个Grunt项目“my-grunt”。要正常的运行这个Grunt项目,其中package.jsonGruntfile.js是必不可少的,而且它们都必须位于Grunt项目的根目录之下。

你可以通过在你的终端下执行下面的命令(注,这里是Mac环境下操作的):

$ mkdir my-grunt
$ touch package.json Gruntfile.js

此时,在“my-grunt”项目的根目录下就创建了两个空文件:package.jsonGruntfile.js:

+my-grunt
|----Gruntfile.js
|----package.json

这样就完成了Gruntfile.js文件创建,这也是创建Gruntfile.js文件最简单的方法。除了这种方法之外,我们还可以通过grunt-init方法来创建。接下来我们简单的一起来过一下如何使用grunt-init创建Gruntfile.js文件。

首先你需要先安装grunt-init,如果还没有安装,在终端执行下面的命令:

$ npm install -g grunt-init

有的系统上面的命令安装会失败,如果失败了不用太过担心,你只要加上一个sudo就OK了,

$ sudo npm install -g grunt-init

这个时候,在命令终端你会看到一串这样的信息结尾,就表示你安装grunt-init:

npm http 200 https://registry.npmjs.org/request
/usr/local/bin/grunt-init -> /usr/local/lib/node_modules/grunt-init/bin/grunt-init
grunt-init@0.2.1 /usr/local/lib/node_modules/grunt-init
├── semver@1.0.14
├── colors@0.6.2
├── hooker@0.2.3
├── grunt@0.4.1 (which@1.0.5, dateformat@1.0.2-1.2.3, eventemitter2@0.4.13, async@0.1.22, lodash@0.9.2, coffee-script@1.3.3, underscore.string@2.2.1, iconv-lite@0.2.11, minimatch@0.2.12, glob@3.1.21, rimraf@2.0.3, findup-sync@0.1.2, nopt@1.0.10, js-yaml@2.0.5)
└── prompt@0.1.12 (async@0.1.22, pkginfo@0.3.0, winston@0.5.11)

至于这一大串信息是什么意思,我也不懂,先不管了,知道安装成功就行了。一旦grunt-init安装成功,你的系统下~/.grunt-init目录来放置模板地方。所以建议你使用gitGruntfile文件模板克隆到这个目录下:

git clone https://github.com/gruntjs/grunt-init-gruntfile.git ~/.grunt-init/gruntfile

如果使用的系统是Windows,那么你可以参考这里的文档来创建。

执行完上面的命令之后,你可以在~/.grunt-init目录下多了一个gruntfile目录:

$ cd  ~/.grunt-init
gruntfile
$ cd gruntfile
README.md   root    template.js

这个时候在终端上进入到项目“my-grunt”目录下,执行:

$ grunt-init gruntfile

终端会开始以提问的方式与你交互创建Gruntfile.js文件:

Running "init:gruntfile" (init) task
This task will create one or more files in the current directory, based on the
environment and the answers to a few questions. Note that answering "?" to any
question will show question-specific help and answering "none" to most questions
will leave its value blank.

"gruntfile" template notes:
This template tries to guess file and directory paths, but you will most likely
need to edit the generated Gruntfile.js file before running grunt. If you run
grunt after generating the Gruntfile, and it exits with errors, edit the file!

Please answer the following:
[?] Is the DOM involved in ANY way? (Y/n) 

我一路下来:

Please answer the following:
[?] Is the DOM involved in ANY way? (Y/n) n
[?] Will files be concatenated or minified? (Y/n) n
[?] Will you have a package.json file? (Y/n) y
[?] Do you need to make any changes to the above before continuing? (y/N) n

Writing Gruntfile.js...OK

Initialized from template "gruntfile".

Done, without errors.

这样就完成了Gruntfile.js文件创建,不过这种方式创建出的文件和手工创建的不一样,文件中有一定的内容:

/*global module:false*/
module.exports = function(grunt) {

  // 项目配置.
  grunt.initConfig({
    // 任务配置.
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        globals: {}
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      lib_test: {
        src: ['lib/**/*.js', 'test/**/*.js']
      }
    },
    nodeunit: {
      files: ['test/**/*_test.js']
    },
    watch: {
      gruntfile: {
        files: '<%= jshint.gruntfile.src %>',
        tasks: ['jshint:gruntfile']
      },
      lib_test: {
        files: '<%= jshint.lib_test.src %>',
        tasks: ['jshint:lib_test', 'nodeunit']
      }
    }
  });

  // 加载任务.
  grunt.loadNpmTasks('grunt-contrib-nodeunit');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // 默认执行的任务.
  grunt.registerTask('default', ['jshint', 'nodeunit']);

};

简单化一下,Gruntfiles.js文件将长成这屌样子:

//Wrapper函数
module.exports = function(grunt) {

  // 配置项目
  grunt.initConfig({
    // 配置任务
  });

  // 加载任务
  grunt.loadNpmTasks('grunt任务插件名');

  // 默认任务.
  grunt.registerTask('default', ['任务名']);

};

文件搞定后,我们更关心的是怎么在这个文件中配置我们需要的任务。接下来,我们一起来了解他的配置。

“Wrapper”函数

每个Gruntfile.js和Grunt插件都使用这个基本格式,前且所有你的Grunt代码都必须指定在这个函数里面:

module.exports = function(grunt){

}

Grunt配置

Grunt的任务配置都是在你的Gruntfile.js文件中的grunt.initConfig({})方法中指定。这个配置主要都是一些命名任务属性(通常任务都被定义为一个对象给grunt.initConfig({})方法,而任务都是作为这个对象的属性定义的),也可以包含任意其他数据。但这些属性(其他属性)不能与你的任务所需要的属性相冲突,否则它将被忽略(一般情况下任务中的属性名都是约定俗成的)。

此外,由于这本身就是JavaScript,因此你不仅限于使用JSON;你可以在这里使用任何有效的JavaScript。必要的情况下,你甚至可以以编程的方式生成配置(比如通过其他的程序生成一个或多个任务配置)。

grunt.initConfig({
    concat: {
        //这里是concat任务的配置信息
    },
    uglify: {
        //这里是uglify任务的配置信息
    },
    //任意非任务特定属性
    my_property: 'whatever',
    my_src_file: ['foo/*.js', 'bar/*.js']
});

项目和任务配置

前面说过,大多数Grunt任务所依赖的配置数据都被定义在传递给grunt.initConfig方法的一个对象中。

我们先来看一个简单的例子,为了实现示例中的功能,需要先完善package.json文件的内容,如下所示:

{
  "name": "my-grunt",
  "version": "0.1.0",
  "description": "this is test project with grunt.",
  "author": "airen",
  "license": "BSD",
  "devDependencies": {
        "grunt": "~0.4.1",
        "grunt-contrib-uglify": "*"
    }
}

如果你不知道如何创建package.json文件,建议你先阅读前面的《Grunt教程——初涉Grunt》一文,你将会有一个初步的了解,在下一节中,我们将会对package.json文件做一个较为详细的阐述。

在这个示例中,grunt.file.readJSON('package.json')会把存储在package.json中的JSON元素数据导入到Grunt配置中。由于<% %>模板字符串可以引用任意的配置属性,因此可以通过这种方式来指定诸如文件路径和文件列表类型的配置数据,从而减少一些重复的工作(比如我们通常需要通过复制粘贴的方式来在不同的地方引用同一个属性,使用<% %>的方式可以简单的理解为将某些特定的数据存储在变量中,然后在其他地方像使用变量一样就可以使用这些数据属性)。

与大多数任务一样,grunt-contrib-uglify插件的uglify任务要求它的配置被指定在一个同名属性中。在这里有一个例子,我们指定了一个banner选项(用于在文件顶部生成一个注释),紧接都会是一个单一的名为build的uglify目录,用于将一个js文件压缩为一个目标文件(比如将src/js目录下的jquery-1.9.0.js压缩为jquery-1.9.min.js,然后存储到dest/js目录)。

// 项目配置
grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
        options: {
            banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
        },
        build: {
            src: 'src/js/<%= pkg.name %>.js',
            dest: 'build/js/<%= pkg.name %>.min.js'
        }
    }
});

任务配置和目标

当运行一个任务时,Grunt会自动查找配置对象中的同名属性。多个任务可以有多个配置,每个任务可以使用任意的命名“targets”来自定义多个任务目标。在上面的示例中,添加Sass任务:

//Wrapper函数
module.exports = function(grunt) {

  // 配置项目
  grunt.initConfig({
    // 配置任务
    pkg:grunt.file.readJSON('package.json'),

    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: {
        src: 'src/js/<%= pkg.name %>.js',
        dest: 'build/js/<%= pkg.name %>.min.js'
      }
    },
    sass: {
      dist: {
        options: {
          style: 'compressed'
        },
        expand: true,
        cwd: 'src/styles/sass/',
        src: ['*.scss'],
        dest: 'build/styles/css',
        ext: '.css'
      },
      dev: {
        options: {
          style: 'expanded',
          debugInfo: true,
          lineNumbers: true
        },
        expand: true,
        cwd: 'src/styles/sass/',
        src: ['*.scss'],
        dest: 'build/styles/css',
        ext: '.css'
      }
    }
  });
};

在示例当中,sass任务有两个字任务distdev。在命令行中执行grunt sass:dist或者grunt sass:dev的任务和目标只会处理指定的任务目标配置,而运行grunt sass将遍历所有的(定义在sass任务中的)目标并依次处理。注意,如果一个任务使用grunt.renameTask重命过,Grunt将在配置对象中查找新的任务名称属性。

加载Grunt插件和任务

许多常用的任务像concatenation,minificationlinting都被作为grunt插件来使用。只要一个插件被作为一个依赖指定在项目的package.json文件中,并且已经通过npm install安装好,都可以在你的Gruntfile.js文件中使用下面这个简单的命令启用它(所依赖的任务)。

//加载提供“uglify”任务的插件
grunt.loadNpmTasks('grunt-contrib-uglify');
//加载提供"sass"任务插件
grunt.loadNpmTasks('grunt-contrib-sass');

设置默认任务

Gruntfile.js文件中,你可以通过定义一个default任务来配置Grunt,让它默认运行一个或者多个任务。在下面的例子中,在命令中运行grunt而不指定特定的任务将自动运行uglifysass任务。这个功能与显示的运行grunt uglifygrunt sass或者等价运行grunt default一样。你可以在任务参数数组指定任意数量的任务(这些任务可以带参数,也可以不带参数)。

// 默认任务
grunt.registerTask('default', ['uglify','sass']);

自定义任务

如果你的项目所需的任务没有对应的Grunt插件提供相应的功能,你可以在Grunt内定义自定义的任务。例如,下面的Gruntfile就定义了一个完整的自定义的default任务,它甚至没有利用任务配置(没有使用grunt.initConfig({})方法):

module.exports = function(grunt){
    //一个非常基础的default任务
    grunt.registerTask('default','Log some stuff.',function(){
        grunt.log.write('Logging some stuff...').ok();
    });
};

自定义的项目特定的任务可以不定义在Gruntfile.js中;它可以定义在一个外部.js文件中,然后通过grunt.loadTasks方法来加载。

options

在一个任务配置中,options属性可以用来指定覆盖内置属性的默认值。此外,每一个任务目标中更具体的目标都可以拥有一个options属性。目标级的选项将会覆盖任务级的选项(就近原则——options离目标越近,其优先级越高)。

options对象是可选,如果不需要,可以省略。

grunt.initConfig({
    concat: {
        options: {
            // 这里是任务级的Options,覆盖任务的默认值 
        },
        foo: {
            options: {
                // 这里是'foo'目标的options,它会覆盖任务级的options.
            }
        },
        bar: {
            // 没有指定options,这个目标将使用任务级的options
        }
    }
});

文件

由于大多的任务都是执行文件操作,Grunt有一个强大的抽象声明说明任务应该操作哪些文件。这里有好几种定义src-dest(源文件——目标文件)文件映射的方式,都提供了不同程度的描述和控制操作方式。任何一种多任务(包含多个任务目标的任务)都能理解下面的格式,所以你只需要选择满足你需要的格式就行。

所有的文件格式都支持srcdest属性。

简洁格式

这种形式允许每个目标对应一个src-dest文件映射。通常情况下它用于只读任务,比如grunt-contrib-jshint,它就只需要一个单一的src属性,而不需要关联的dest选项。这种格式还支持给每个src-dest文件映射指定附加属性。

grunt.initConfig({
    jshint: {
        src: ['src/js/a.js','src/js/aa.js']
    }
});

文件对象格式

这种形式支持每个任务目标对就多个src-dest形式的文件映射,属性名就是目标文件,源文件就是它的值(源文件列表则使用数组格式声明)。可以使用这种方式指定数个src-dest文件映射,但是不能够给每个映射指定附加的属性。

grunt.initConfig({
    concat: {
        foo: {
            files: {
                'dest/a.js': ['src/aa.js', 'src/aaa.js'],
                'dest/a1.js': ['src/aa1.js', 'src/aaa1.js']
            }
        },
        bar: {
            files: {
                'dest/b.js': ['src/bb.js', 'src/bbb.js'],
                'dest/b1.js': ['src/bb1.js', 'src/bbb1.js']
            }
        }
    }
});

文件数组格式

这种形式支持每个任务目标对应多个src-dest文件映射,同时也允许每个映射拥有附加属性:

grunt.initConfig({
    concat: {
        foo: {
            files: [
                {src: ['src/aa.js', 'src/aaa.js'], dest: 'dest/a.js'},
                {src: ['src/aa1.js', 'src/aaa1.js'], dest: 'dest/a1.js'}
            ]
        },
        bar: {
            files: [
                {src: ['src/bb.js', 'src/bbb.js'], dest: 'dest/b/', nonull: true},
                {src: ['src/bb1.js', 'src/bbb1.js'], dest: 'dest/b1/', filter: 'isFile'}
            ]
        }
    }
});

较老的格式

dest-as-target文件格式在多任务和目标形式出现之前是一个过渡形式,目标文件路径实际上就是目标名称。遗憾的是, 由于目标名称是文件路径,那么运行grunt task:target可能不合适。此外,你也不能指定一个目标级的options或者给每个src-dest文件映射指定附加属性。

grunt.initConfig({
    concat: {
        'dest/a.js': ['src/aa.js', 'src/aaa.js'],
        'dest/b.js': ['src/bb.js', 'src/bbb.js']
    }
});

自定义过滤函数

filter属性可以给你的目标文件提供一个更高级的详细帮助信息。只需要使用一个有效的fs.Stats方法名。下面的配置仅仅清理一个与模式匹配的真实的文件:

grunt.initConfig({
    clean: {
        foo: {
            src: ['temp/**/*'],
            filter: 'isFile'
        }
    }
});

或者创建你自己的filter函数根据文件是否匹配来返回true或者false。下面的例子将仅仅清理一个空目录:

grunt.initConfig({
    clean: {
        foo: {
            src: ['temp/**/*'],
            filter: function(filepath){
                return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0);
            }
        }
    }
});

通配符模式

 

原文档标题为Globbing patterns,大意是指使用一些通配符形式的匹配模式快速的匹配文件。

通常分别指定所有源文件路径的是不切实际的(也就是将源文件-目标文件一一对应的关系列出来),因此Grunt支持通过内置的node-globminimatch库来匹配文件名(又叫作globbing)。

当然这并不是一个综合的匹配模式方面的教程,你只需要知道如何在文件路径匹配过程中使用它们即可:

  • *匹配任意数量的字符,但不匹配/
  • ?匹配单个字符,但不匹配/
  • **匹配任意数量的字符,包括/,只要它是路径中唯一的一部分
  • {}允许使用一个逗号分割的列表或者表达式
  • !在模式的开头用于否定一个匹配模式(即排除与模式匹配的信息)

大多数的人都知道foo/*.js将匹配位于foo/目录下的所有的.js结尾的文件, 而foo/**/*js将匹配foo/目录以及其子目录中所有以.js结尾的文件。

此外, 为了简化原本复杂的通配符模式,Grunt允许指定一个数组形式的文件路径或者一个通配符模式。模式处理的过程中,带有!前缀模式不包含结果集中与模式相配的文件。 而且其结果集也是唯一的。

示例:

//可以指定单个文件
{src: 'foo/this.js', dest: …}
//或者指定一个文件数组
{src: ['foo/this.js', 'foo/that.js', 'foo/the-other.js'], dest: …}
//或者使用一个匹配模式
{src: 'foo/th*.js', dest: …}

//一个独立的node-glob模式
{src: 'foo/{a,b}*.js', dest: …}
//也可以这样编写
{src: ['foo/a*.js', 'foo/b*.js'], dest: …}

//foo目录中所有的.js文件,按字母排序
{src: ['foo/*js'], dest: …}
//这里首先是bar.js,接着是剩下的.js文件按字母排序
{src: ['foo/bar.js', 'foo/*.js'], dest: …}

//除bar.js之外的所有的.js文件,按字母排序
{src: ['foo/*.js', '!foo/bar.js'], dest: …}
//所有.js文件按字母排序, 但是bar.js在最后.
{src: ['foo/*.js', '!foo/bar.js', 'foo/bar.js'], dest: …}

//模板也可以用于文件路径或者匹配模式中
{src: ['src/<%= basename %>.js'], dest: 'build/<%= basename %>.min.js'}
//它们也可以引用在配置中定义的其他文件列表
{src: ['foo/*.js', '<%= jshint.all.src %>'], dest: …}

可以在node-globminimatch文档中查看更多的关于通配符模式的语法。

构建动态文件对象

当你希望处理大量的单个文件时,这里有一些附加的属性可以用来动态的构建一个文件. 这些属性都可以指定在CompactFiles Array映射格式中(这两种格式都可以使用)。

  • expand设置true用于启用下面的选项:
  • cwd相对于当前路径所匹配的所有src路径(但不包括当前路径。)
  • src相对于cwd路径的匹配模式。
  • dest目标文件路径前缀。
  • ext使用这个属性值替换生成的dest路径中所有实际存在文件的扩展名(比如我们通常将压缩后的文件命名为.min.js)。
  • flatten从生成的dest路径中移除所有的路径部分。
  • rename对每个匹配的src文件调用这个函数(在执行extflatten之后)。传递dest和匹配的src路径给它,这个函数应该返回一个新的dest值。 如果相同的dest返回不止一次,每个使用它的src来源都将被添加到一个数组中。

在下面的例子中,minify任务将在static_mappingsdynamic_mappings两个目标中查看相同的src-dest文件映射列表, 这是因为任务运行时Grunt会自动展开dynamic_mappings文件对象为4个单独的静态src-dest文件映射--假设这4个文件能够找到。

可以指定任意结合的静态src-dest和动态的src-dest文件映射。

grunt.initConfig({
    minify: {
        static_mappings: {
            //由于这里的src-dest文件映射时手动指定的, 每一次新的文件添加或者删除文件时,Gruntfile都需要更新
            files: [
                {src: 'lib/a.js', dest: 'build/a.min.js'},
                {src: 'lib/b.js', dest: 'build/b.min.js'},
                {src: 'lib/subdir/c.js', dest: 'build/subdir/c.min.js'},
                {src: 'lib/subdir/d.js', dest: 'build/subdir/d.min.js'}
            ]
        },
        dynamic_mappings: {
            //当'minify'任务运行时Grunt将自动在"lib/"下搜索"**/*.js", 然后构建适当的src-dest文件映射,因此你不需要在文件添加或者移除时更新Gruntfile
            files: [
                {
                    expand: true, //启用动态扩展
                    cwd: 'lib/', //批匹配相对lib目录的src来源
                    src: '**/*.js', //实际的匹配模式
                    dest: 'build/', //目标路径前缀
                    ext: '.min.js' //目标文件路径中文件的扩展名.
                }
            ]
        }
    }
});

模板

使用<% %>分隔符指定的模会在任务从它们的配置中读取相应的数据时将自动扩展扫描。模板会被递归的展开,直到配置中不再存在遗留的模板相关的信息(与模板匹配的)。

整个配置对象决定了属性上下文(模板中的属性)。此外,在模板中使用grunt以及它的方法都是有效的,例如:<%= grunt.template.today('yyyy-mm-dd') %>

  • <%= prop.subprop %>将会自动展开配置信息中的prop.subprop的值,不管是什么类型。像这样的模板不仅可以用来引用字符串值,还可以引用数组或者其他对象类型的值。
  • <% %>执行任意内联的JavaScript代码,对于控制流或者循环来说是非常有用的。

下面提供了一个concat任务配置示例,运行grunt concat:sample时将通过banner中的/* abcde */连同foo/*.js+bar/*.js+bar/*.js匹配的所有文件来生成一个名为build/abcde.js的文件。

grunt.initConfig({
    concat: {
        sample: {
            options: {
                banner: '/* <%= baz %> */\n' // '/* abcde */\n'
            },
            src: ['<%= qux %>', 'baz/*.js'], // [['foo/*js', 'bar/*.js'], 'baz/*.js']
            dest: 'build/<%= baz %>.js'
        }
    },
    //用于任务配置模板的任意属性
    foo: 'c',
    bar: 'b<%= foo %>d', //'bcd'
    baz: 'a<%= bar %>e', //'abcde'
    qux: ['foo/*.js', 'bar/*.js']
});

导入外部数据

在下面的Gruntfile中,项目的元数据是从package.json文件中导入到Grunt配置中的,并且grunt-contrib-uglify插件的uglify任务被配置用于压缩一个源文件以及使用该元数据动态的生成一个banner注释。

Grunt有grunt.file.readJSONgrunt.file.readYAML两个方法分别用于引入JSON和YAML数据。

grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    uglify: {
        options: {
            banner: '/* <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
        },
        dist: {
            src: 'src/<%= pkg.name %>.js',
            dest: 'dist/<%= pkg.name %>.min.js'
        }
    }
});

到此,Grunt的任务配置相关的知识都已涉及到了,但不同的Grunt的任务其配置都略有不同,不过针对不同的插件任务配置,可以查阅每个Grunt插件的说明文档。

对于初学者来说,或许上面的内容有很多都理解不过来,其实我也一样,不过不用担心,当你看得多,做得多,到一定的时候自然就整得明白是怎么一回事。现在我们返回到示例中。根据上面的内容,给"my-grunt"项目创建了grunt-contrib-uglifygrunt-contrib-sass两个任务,并且完成了一些简单的配置:

//Wrapper函数
module.exports = function(grunt) {

  // 配置项目
  grunt.initConfig({
    // 配置任务
    pkg:grunt.file.readJSON('package.json'),

    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
      },
      build: {
        src: 'src/js/<%= pkg.name %>.js',
        dest: 'build/js/<%= pkg.name %>.min.js'
      }
    },
    sass: {
      dist: {
        options: {
          style: 'compressed'
        },
        expand: true,
        cwd: 'src/styles/sass/',
        src: ['*.scss'],
        dest: 'build/styles/css',
        ext: '.css'
      },
      dev: {
        options: {
          style: 'expanded',
          debugInfo: true,
          lineNumbers: true
        },
        expand: true,
        cwd: 'src/styles/sass/',
        src: ['*.scss'],
        dest: 'build/styles/css',
        ext: '.css'
      }
    }
  });

  // 加载任务
  //加载提供“uglify”任务的插件
  grunt.loadNpmTasks('grunt-contrib-uglify');
  //加载提供"sass"任务插件
  grunt.loadNpmTasks('grunt-contrib-sass');

  // 默认任务.
  grunt.registerTask('default', ['uglify','sass']);

};

仅这样Grunt不会自动执行任何任务,因为我们只完成了配置,但没有安装Grunt里面的任务。如果你需要安装,只需要在命令终端执行:

$ npm install

在终端中,看到下面这样的结束信息,表示安装成功:

...
grunt-contrib-uglify@0.2.5 node_modules/grunt-contrib-uglify
├── grunt-lib-contrib@0.6.1 (zlib-browserify@0.0.1)
└── uglify-js@2.4.3 (uglify-to-browserify@1.0.1, async@0.2.9, optimist@0.3.7, source-map@0.1.31)

同时在项目的根目录下会自生成一个node_modules目录,而且在Grunt中配置的相关的任务都放在这个目录中。

+my-grunt
|----Gruntfile.js
+----node_modules
|----+----grunt
|----+----grunt-contrib-sass
|----+----grunt-contrib-uglify
|----package.json

在整个项目中,uglify任务是用来压缩项目中.js文件,sass任务是用来编译项目中的.scss文件。为了证明我们创建的任务是正确的,我们在项目中创建一个js文件和.scss文件来检验是否成功。并且将.js文件放置在src/js目录下,.scss文件放置在src/styles/sass目录下。同时我们创建两测试文件:my-grunt.jsmain.scss

//my-grunt.js

(function($){
    var str = "<p>hello grunt!</p>";
    $("body").append(str);
})(jQuery)
//main.scss
$color: #f36;
$bgColor: #fff;
$unit: 30px;

body {
    background-color: $bgColor;
}
.container {
    margin: ($unit / 3) auto;
    width: $unit * 3;
}

注:因为我们uglify任务中使用是<% pk.name %>模板,而这里面的name对应的就是package.json中的name参数。因此需要创建一个my-grunt.js

你要执行Grunt任务的时候,只需要在命令行中执行:

$ grunt

这个时候,你在终端可以看到对应的信息:

Running "uglify:build" (uglify) task
File "build/js/my-grunt.min.js" created.

Running "sass:dist" (sass) task

Running "sass:dev" (sass) task

Done, without errors.

同时项目自动会生成一个名叫build的目录,而压缩的.min.js文件对应放置在build/js目录下;编译出来的.css放置在build/style/css下:

+my-grunt
+----build
+----+----js
+----+----|----my-grunt.min.js
+----+----styles
+----+----+----css
+----+----+----|----main.css
|----Gruntfile.js
+----node_modules
|----package.json
+----src
+----+----js
+----+----|----my-grunt.js
+----+----styles
+----+----+----sass
+----+----+----|----main.scss

因为我们在Grunt中配置了默认任务,如果没有设置默认任务,必须需要单独执行:

$ grunt uglify
$ grunt sass

结论

本文主要向大家介绍了Grunt项目中Gruntfile.js文件的配置以及如何在这个文件中配置对应的任务。并且详细介绍了配置任务中的一些参数与细节的使用。最后通过一个简单示例,向大家介绍了如何使用Grunt配置任务。虽然文章中有很多部分对于初学者来说理解有一定难度,但我相信,随着时间的推移,会慢慢搞懂文章中介绍的所有知识。最后希望本文对初学者有所帮助。

分享到:
评论

相关推荐

    构建工具的使用.xmind

    前端项目构建工具的使用官网:Gurnt、Gulp、Webpack

    generator-pat-marionette

    generator-pat-marionette generatorGetting Started全局安装 yeoman、grunt-cli、bowernpm install -g yonpm install -g grunt-clinpm install -g bower由于当前generator没有注册到gurnt上去,所以你要先把源文件...

    星之语明星周边产品销售网站的设计与实现-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip

    Spring Boot是Spring框架的一个模块,它简化了基于Spring应用程序的创建和部署过程。Spring Boot提供了快速启动Spring应用程序的能力,通过自动配置、微服务支持和独立运行的特性,使得开发者能够专注于业务逻辑,而不是配置细节。Spring Boot的核心思想是约定优于配置,它通过自动配置机制,根据项目中添加的依赖自动配置Spring应用。这大大减少了配置文件的编写,提高了开发效率。Spring Boot还支持嵌入式服务器,如Tomcat、Jetty和Undertow,使得开发者无需部署WAR文件到外部服务器即可运行Spring应用。 Java是一种广泛使用的高级编程语言,由Sun Microsystems公司(现为Oracle公司的一部分)在1995年首次发布。Java以其“编写一次,到处运行”(WORA)的特性而闻名,这一特性得益于Java虚拟机(JVM)的使用,它允许Java程序在任何安装了相应JVM的平台上运行,而无需重新编译。Java语言设计之初就是为了跨平台,同时具备面向对象、并发、安全和健壮性等特点。 Java语言广泛应用于企业级应用、移动应用、桌面应用、游戏开发、云计算和物联网等领域。它的语法结构清晰,易于学习和使用,同时提供了丰富的API库,支持多种编程范式,包括面向对象、命令式、函数式和并发编程。Java的强类型系统和自动内存管理减少了程序错误和内存泄漏的风险。随着Java的不断更新和发展,它已经成为一个成熟的生态系统,拥有庞大的开发者社区和持续的技术创新。Java 8引入了Lambda表达式,进一步简化了并发编程和函数式编程的实现。Java 9及以后的版本继续在模块化、性能和安全性方面进行改进,确保Java语言能够适应不断变化的技术需求和市场趋势。 MySQL是一个关系型数据库管理系统(RDBMS),它基于结构化查询语言(SQL)来管理和存储数据。MySQL由瑞典MySQL AB公司开发,并于2008年被Sun Microsystems收购,随后在2010年,Oracle公司收购了Sun Microsystems,从而获得了MySQL的所有权。MySQL以其高性能、可靠性和易用性而闻名,它提供了多种特性来满足不同规模应用程序的需求。作为一个开源解决方案,MySQL拥有一个活跃的社区,不断为其发展和改进做出贡献。它的多线程功能允许同时处理多个查询,而其优化器则可以高效地执行复杂的查询操作。 随着互联网和Web应用的快速发展,MySQL已成为许多开发者和公司的首选数据库之一。它的可扩展性和灵活性使其能够处理从小规模应用到大规模企业级应用的各种需求。通过各种存储引擎,MySQL能够适应不同的数据存储和检索需求,从而为用户提供了高度的定制性和性能优化的可能性。

    精选毕设项目-新浪读书.zip

    精选毕设项目-新浪读书

    智慧农业平台解决方案.pptx

    智慧农业平台解决方案

    精选毕设项目-小程序地图Demo.zip

    精选毕设项目-小程序地图Demo

    操作系统课程设计: 并发与调度

    实验目的 在本实验中,通过对事件和互斥体对象的了解,来加深对 Windows Server 2016 线程同步的理解。 1)回顾系统进程、线程的有关概念,加深对 Windows Server 2016 线程的理解; 2)了解事件和互斥体对象; 3)通过分析实验程序,了解管理事件对象的API; 4)了解在进程中如何使用事件对象; 5)了解在进程中如何使用互斥体对象; 6)了解父进程创建子进程的程序设计方法。 程序清单 清单2-1 1.// event 项目   2.#include <windows.h>   3.#include <iostream>   4.using namespace std;   5.   6.// 以下是句柄事件。实际中很可能使用共享的包含文件来进行通讯   7.static LPCTSTR g_szContinueEvent = "w2kdg.EventDemo.event.Continue";   8.   9.// 本方法只是创建了一个进程的副本,以子进程模式 (由命令行指定) 工作    10.BOOL CreateChild()   11.{  

    三相VIENNA整流,维也纳整流器simulink仿真 输入电压220v有效值 输出电压800v纹波在1%以内 0.1s后系统稳定 功率因数>0.95 电流THD<5% 开关频率20k 图一为拓扑,可

    三相VIENNA整流,维也纳整流器simulink仿真 输入电压220v有效值 输出电压800v纹波在1%以内 0.1s后系统稳定 功率因数>0.95 电流THD<5% 开关频率20k 图一为拓扑,可以看到功率因数和THD以及输出电压 图二为直流输出电压 图三四为a相电压电流 图五为控制等计算的总体框图 图六为svpwm调制框图 图七为双闭环控制图八为输出调制波 可作为电力电子方向入门学习~~

    chromedriver-linux64_122.0.6251.0.zip

    chromedriver-linux64_122.0.6251.0

    操作系统课程设计-进程控制描述与控制

    一、实验目的 实验1.1 Windows“任务管理器”的进程管理 通过在Windows任务管理器中对程序进程进行响应的管理操作,熟悉操作系统进程管理的概念,学习观察操作系统运行的动态性能。 实验1.2 Windows Server 2016进程的“一生” 1)通过创建进程、观察正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉 操作系统的进程概念,理解Windows Server 2016进程的“一生”; 2)通过阅读和分析实验程序,学习创建进程、观察进程和终止进程的程序设计方法。 1.// proccreate项目   2.#include <windows.h>   3.#include <iostream>   4.#include <stdio.h>   5.using namespace std;   6.   7.// 创建传递过来的进程的克隆过程并赋与其ID值   8.void StartClone(int nCloneID) {   9.    // 提取用于当前可执行文件的文件名   10.    TCHAR szFilename[MAX_PATH];   11

    MATLAB环境下一种基于稀疏优化的瞬态伪影消除算法 程序运行环境为MATLAB R2018A,执行一种基于稀疏优化的瞬态伪影消除算法 GRAY = 1 1 1 * 0.7; subplot(4

    MATLAB环境下一种基于稀疏优化的瞬态伪影消除算法 程序运行环境为MATLAB R2018A,执行一种基于稀疏优化的瞬态伪影消除算法。 GRAY = [1 1 1] * 0.7; subplot(4, 1, 4) line(n, y, 'color', GRAY, 'lineWidth', 1) line(n, y - x, 'color', 'black'); legend('Raw data', 'Corrected data') xlim([0 N]) xlabel('Time (n)') 压缩包=数据+程序+参考。

    多机系统的暂态稳定仿真 MATLAB编程 针对多机电力系统,通过编程,计算当发生故障时,多台发电机的功角曲线(pv节点发电机与平衡节点发电机的功角差),通过功角曲线来分析判断多机系统的

    多机系统的暂态稳定仿真 MATLAB编程 针对多机电力系统,通过编程,计算当发生故障时,多台发电机的功角曲线(pv节点发电机与平衡节点发电机的功角差),通过功角曲线来分析判断多机系统的暂态稳定性。 注: 可指定故障发生位置及故障清除时间 下面以IEEE30节点系统为例

    中药实验管理系统设计与实现-springboot毕业项目,适合计算机毕-设、实训项目、大作业学习.zip

    Spring Boot是Spring框架的一个模块,它简化了基于Spring应用程序的创建和部署过程。Spring Boot提供了快速启动Spring应用程序的能力,通过自动配置、微服务支持和独立运行的特性,使得开发者能够专注于业务逻辑,而不是配置细节。Spring Boot的核心思想是约定优于配置,它通过自动配置机制,根据项目中添加的依赖自动配置Spring应用。这大大减少了配置文件的编写,提高了开发效率。Spring Boot还支持嵌入式服务器,如Tomcat、Jetty和Undertow,使得开发者无需部署WAR文件到外部服务器即可运行Spring应用。 Java是一种广泛使用的高级编程语言,由Sun Microsystems公司(现为Oracle公司的一部分)在1995年首次发布。Java以其“编写一次,到处运行”(WORA)的特性而闻名,这一特性得益于Java虚拟机(JVM)的使用,它允许Java程序在任何安装了相应JVM的平台上运行,而无需重新编译。Java语言设计之初就是为了跨平台,同时具备面向对象、并发、安全和健壮性等特点。 Java语言广泛应用于企业级应用、移动应用、桌面应用、游戏开发、云计算和物联网等领域。它的语法结构清晰,易于学习和使用,同时提供了丰富的API库,支持多种编程范式,包括面向对象、命令式、函数式和并发编程。Java的强类型系统和自动内存管理减少了程序错误和内存泄漏的风险。随着Java的不断更新和发展,它已经成为一个成熟的生态系统,拥有庞大的开发者社区和持续的技术创新。Java 8引入了Lambda表达式,进一步简化了并发编程和函数式编程的实现。Java 9及以后的版本继续在模块化、性能和安全性方面进行改进,确保Java语言能够适应不断变化的技术需求和市场趋势。 MySQL是一个关系型数据库管理系统(RDBMS),它基于结构化查询语言(SQL)来管理和存储数据。MySQL由瑞典MySQL AB公司开发,并于2008年被Sun Microsystems收购,随后在2010年,Oracle公司收购了Sun Microsystems,从而获得了MySQL的所有权。MySQL以其高性能、可靠性和易用性而闻名,它提供了多种特性来满足不同规模应用程序的需求。作为一个开源解决方案,MySQL拥有一个活跃的社区,不断为其发展和改进做出贡献。它的多线程功能允许同时处理多个查询,而其优化器则可以高效地执行复杂的查询操作。 随着互联网和Web应用的快速发展,MySQL已成为许多开发者和公司的首选数据库之一。它的可扩展性和灵活性使其能够处理从小规模应用到大规模企业级应用的各种需求。通过各种存储引擎,MySQL能够适应不同的数据存储和检索需求,从而为用户提供了高度的定制性和性能优化的可能性。

    精选毕设项目-鱼缸表盘系统小程序.zip

    精选毕设项目-鱼缸表盘系统小程序

    法院安防系统解决方案Word(77页).docx

    在科技与司法的交响曲中,智慧法院应运而生,成为新时代司法服务的新篇章。它不仅仅是一个概念,更是对法院传统工作模式的一次深刻变革。智慧法院通过移动信息化技术,为法院系统注入了强大的生命力,有效缓解了案多人少的矛盾,让司法服务更加高效、便捷。 立案、调解、审判,每一个阶段都融入了科技的智慧。在立案阶段,智慧法院利用区块链技术实现可信存证,确保了电子合同的合法性和安全性,让交易双方的身份真实性、交易安全性得到了有力见证。这不仅极大地缩短了立案时间,还为后续审判工作奠定了坚实的基础。在调解阶段,多元调解服务平台借助人工智能、自然语言处理等前沿技术,实现了矛盾纠纷的快速化解。无论是矛盾类型的多元化,还是化解主体的多元化,智慧法院都能提供一站式、全方位的服务,让纠纷解决更加高效、和谐。而在审判阶段,智能立案、智能送达、智能庭审、智能判决等一系列智能化手段的应用,更是让审判活动变得更加智能化、集约化。这不仅提高了审判效率,还确保了审判质量的稳步提升。 更为引人注目的是,智慧法院还构建了一套完善的执行体系。移动执行指挥云平台的建设,让执行工作变得更加精准、高效。执行指挥中心和信息管理中心的一体化应用,实现了信息的实时传输和交换,为执行工作提供了强有力的支撑。而执行指挥车的配备,更是让执行现场通讯信号得到了有力保障,应急通讯能力得到了显著提升。这一系列创新举措的实施,不仅让执行难问题得到了有效解决,还为构建诚信社会、保障金融法治化营商环境提供了有力支撑。智慧法院的出现,让司法服务更加贴近民心,让公平正义的阳光更加温暖人心。

    计算机网络复习要点:OSI模型、TCP/IP协议、IP地址、路由算法及网络安全

    内容概要:本文针对计算机网络这门课程的期末复习,全面介绍了多个关键点和重要概念。主要内容涵盖了计算机网络的基本概念、OSI七层模型及其每一层的具体职责和协议、详细的TCP/IP协议介绍,尤其是三次握手和四次挥手机制、IP地址(IPv4 和 IPv6)的概念和子网划分的技术、静态路由和动态路由的区别及其路由选择算法、TCP和UDP作为两种主要传输层协议的功能区别、各种常用的应用层协议如HTTP、HTTPS、FTP、SMTP等,此外还包括了一些关于网络性能优化的关键参数以及常见的网络安全措施。所有理论均配有相应的案例分析帮助深入理解和巩固知识点。 适合人群:正在准备计算机网络相关考试的学生,或希望深入理解计算机网络架构和原理的人群。 使用场景及目标:为用户提供详尽的期末复习指南,助力理解复杂的技术概念并提高解决具体应用问题的能力,同时通过实例演示使学习变得更加直观。 其他说明:强调不仅要记住公式和定义,更要关注概念背后的运作逻辑及实际应用情况来达到良好的复习效果。

    精选毕设项目-移动端商城.zip

    精选毕设项目-移动端商城

    基于Python的B站视频数据分析可视化系统论文

    本文介绍了基于Python的B站视频的数据分析可视化系统设计与实现。该系统帮助用户深入了解B站视频的趋势,并通过数据分析和可视化技术展示相关信息。利用Python的网络爬虫技术获取B站上的视频数据,包括视频标题、上传者、播放量、点赞数等信息。借助数据分析库Pandas对获取的数据进行处理和分析,例如计算了不同用户视频发布个数、粉丝量、视频长度、视频观阅人数,还分析了不同视频的舆情分布和流行趋势。接着,利用可视化库Echarts将分析结果呈现为图表,例如柱状图、饼图、折线图等,以便用户直观地理解数据。为了提供更加个性化的服务,系统还集成了协同过滤算法推荐功能,根据用户的历史观看记录和偏好,推荐可能感兴趣的视频。最后,设计并实现了一个交互式的用户界面,用户可以通过界面选择感兴趣的话题和日期范围,系统将动态展示相关视频的数据分析结果。通过本系统,用户可以更好地了解B站视频的特点和趋势,同时享受到个性化的视频推荐服务,为用户提供了一个便捷而全面的数据分析工具。 感兴趣自行下载学习!

    MPU6050.zip

    标题 "MPU6050.zip" 暗示了这个压缩包可能包含了与MPU6050陀螺仪和加速度传感器相关的资源。MPU6050是一款广泛应用的惯性测量单元(IMU),它能检测设备在三个轴上的角速度和线性加速度,常用于运动控制、姿态估算、导航等领域。 描述中只提到了"MPU6050.zip",没有提供额外信息,但我们可以通过标签 "stm32cubemx" 来推测,这个压缩包里的内容可能与STM32系列微控制器以及使用STM32CubeMX配置工具有关。STM32CubeMX是一款强大的配置工具,用户可以利用它来初始化STM32微控制器的外设,生成相应的初始化代码。 在压缩包的文件名列表中,我们看到以下几个文件: 1. mpu6050.c:这是一个C源文件,通常包含了与MPU6050交互的驱动程序代码。在这个文件里,开发者可能会定义函数来初始化传感器、读取数据、处理中断等。 2. mpu6050.h:这是对应的头文件,包含了函数声明、常量定义和结构体等,供其他模块调用时包含,以实现对MPU60。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    IPSO-SVR 改进粒子群算法优化支持向量机的多变量回归预测 Matlab语言 1.多变量单输出,通过非线性权重递减方式对粒子群算法进行改进,优化SVR中的两个参数,评价指标包括R2、MAE、MSE

    IPSO-SVR 改进粒子群算法优化支持向量机的多变量回归预测 Matlab语言 1.多变量单输出,通过非线性权重递减方式对粒子群算法进行改进,优化SVR中的两个参数,评价指标包括R2、MAE、MSE、MAPE,效果如图所示,可完全满足您的需求~ 2.直接替Excel数据即可用,注释清晰,适合新手小白[火] 3.附赠测试数据,输入格式如图3所示,可直接运行 4.仅包含模型代码 5.模型只是提供一个衡量数据集精度的方法,因此无法保证替数据就一定得到您满意的结果~

Global site tag (gtag.js) - Google Analytics