grunt

Grunt 介绍

grunt 是一个基于 nodejs 的 task runner,简单来说,就是类似于.net 平台的 msbuild 以及 java 平台的 maven。

  • Grunt 中文主页
  • 是一套前端自动化构建工具,一个基于 nodeJs 的命令行工具
  • 它是一个任务运行器, 配合其丰富强大的插件(Grunt 是一个任务插件框架)
  • 常用功能:
    • 合并文件(js/css)
    • 压缩文件(js/css)
    • 语法检查(js)
    • less/sass 预编译处理
    • 其它…

grunt 可以使你的项目中重复的任务,比如压缩,语法检查,编译(比如 LESS 预处理,coffeescript 编译),单元测试等变得更加简单。

Project 实例结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|- build----------构建生成的文件所在的文件夹
|- src------------源码文件夹
|- js---------------js源文件夹
|- css--------------css源文件夹
|- index.html-----页面文件
|- Gruntfile.js---grunt配置文件(注意首字母大写)
|- package.json---项目包配置文件
{
"name": "grunt_test",
"version": "1.0.0"
"devDependencies": {
"grunt": "^1.0.3",
"grunt-contrib-clean": "^1.1.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-cssmin": "^2.2.1",
"grunt-contrib-uglify": "^3.2.1"
}
}

Grunt 安装

因为 grunt 是基于 node.js 的,所以我们首先要安装 node.js 以及 node.js 的包管理工具 npm。

  • Windows

    Windows 平台下只要在 NODE.JS 官方下载 MSI 安装包,直接安装,node.js 以及 npm 就能直接装好。
    查看版本:

    1
    2
    node -v
    npm -v

    全局安装 grunt-cli

    1
    npm install -g grunt-cli

    安装 grunt

    1
    2
    3
    4
    5
    npm init //init package.json
    npm install grunt --save-dev

    //批量install
    npm install --save-dev grunt-contrib-concat grunt-contrib-jshint grunt-contrib-sass grunt-contrib-uglify grunt-contrib-watch grunt-contrib-connect

    运行构建项目命令

    1
    grunt //Warning: Task "default" not found
  • Linux

    1
    2
    3
    sudo apt-get -y install npm
    sudo npm install -g grunt
    sudo npm install -g grunt-cli

package.json

package.json 用来存放项目的元数据,比如项目的版本,项目许可证书——比如 MIT,GPL 啥的,作者,项目依赖的库等:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"name": "ui",
"version": "1.0.0",
"description": "",
"main": "ui.min.js",
"directories": {
"doc": "doc"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": "",
"keywords": ["javascript", "ui", ""],
"author": "",
"license": "BSD",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-jsdoc": "~0.4.0",
"grunt-contrib-copy": "~0.4.1"
}
}

note: npm init //init package.json

配置文件: Gruntfile.js

  • 此配置文件本质就是一个 node 函数类型模块

  • 配置编码包含 3 步:

    1. 初始化插件配置(grunt.initConfig)
    2. 加载插件任务(grunt.loadNpmTasks)
    3. 注册构建任务(grunt.registerTask)
    1
    2
    3
    4
    5
    6
    7
    smodule.exports = function(grunt) {
    grunt.initConfig({
    //主要编码处
    });
    grunt.loadNpmTasks("grunt-contrib-concat");
    grunt.registerTask("default", []);
    };
  • 命令:

    grunt TASK:TARGET

    grunt = grunt default

  • Tips

    • 通过<%%>模板字符串可以引用任何的配置属性, 比如<%=pkg.name%>;也可以运行 grunt api, 比如<%= grunt.template.today(“yyyy-mm-dd”) %>。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      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/<%= pkg.name %>.js",
      dest: "build/<%= pkg.name %>.min.js"
      }
      }
      });
      grunt.loadNpmTasks("grunt-jsdoc");
      };

Grunt 插件介绍

  • Grunt 官网的插件列表页面
  • 插件分类:
    • Grunt 团队贡献的插件 : 插件名大都以 contrib-开头
      e.g. grunt-contrib-clean, grunt-contrib-concat, grunt-contrib-uglify…
    • 第三方提供的插件 : 大都不以 contrib-开头
    • 常用的插件:
      • grunt-contrib-clean 清除文件(打包处理生成的)
      • grunt-contrib-concat 合并多个文件的代码到一个文件中
      • grunt-contrib-uglify 压缩 js 文件
      • grunt-contrib-jshint javascript 语法错误检查;
      • grunt-contrib-cssmin 压缩/合并 css 文件
      • grunt-contrib-htmlmin 压缩 html 文件
      • grunt-contrib-imagemin 压缩图片文件(无损)
      • grunt-contrib-copy 复制文件、文件夹
      • grunt-contrib-requirejs 合并压缩 requirejs 管理的所有 js 模块文件
      • grunt-contrib-watch 实时监控文件变化、调用相应的任务重新执行

合并 js: 使用 concat 插件

  • 安装插件

    1
    npm install grunt-contrib-concat --save-dev
  • 实例编码:

    • src/js/test1.js

      1
      2
      3
      4
      5
      6
      (function() {
      function add(num1, num2) {
      return num1 + num2;
      }
      console.log(add(10, 20));
      })();
    • src/js/test2.js

      1
      2
      3
      4
      5
      6
      (function() {
      var arr = [2, 3, 4].map(function(item, index) {
      return item + 1;
      });
      console.log(arr);
      })();
  • 配置: Gruntfile.js

    • 配置任务:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      concat: {
      options: { //可选项配置
      separator: ';' //使用;连接合并
      },
      build: { //此名称任意, target的名字,调用的时候为concat:build
      src: ["src/js/*.js"], //合并哪些js文件
      dest: "build/js/built.js" //输出的js文件
      }
      }
    • 加载插件:

      1
      grunt.loadNpmTasks('grunt-contrib-concat');
    • 注册任务:

      1
      grunt.registerTask('default', ['concat']);
  • 运行命令:

    1
    grunt or grunt default

Creating tasks

  • Alias Tasks

    1
    2
    3
    4
    grunt.registerTask(taskName, [description, ] taskList)

    //e.g.
    grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);
  • Multi Tasks

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    grunt.registerMultiTask(taskName, [description, ] taskFunction)

    //e.g.
    grunt.initConfig({
    log: {
    foo: [1, 2, 3],
    bar: 'hello world',
    baz: false
    }
    });

    grunt.registerMultiTask('log', 'Log stuff.', function() {
    grunt.log.writeln(this.target + ': ' + this.data);
    });
  • “Basic” Tasks

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    grunt.registerTask(taskName, [description, ] taskFunction)

    //e.g.
    grunt.registerTask('foo', 'A sample task that logs stuff.', function(arg1, arg2) {
    if (arguments.length === 0) {
    grunt.log.writeln(this.name + ", no args");
    } else {
    grunt.log.writeln(this.name + ", " + arg1 + " " + arg2);
    }
    });

    note: Inside a task, you can run other tasks.

    1
    2
    3
    4
    5
    6
    grunt.registerTask("foo", 'My "foo" task.', function() {
    // Enqueue "bar" and "baz" tasks, to run after "foo" finishes, in-order.
    grunt.task.run("bar", "baz");
    // Or:
    grunt.task.run(["bar", "baz"]);
    });

快速搭建脚手架

利用 grunt 快速搭建脚手架出来。所谓的脚手架,就是指包含了目录结构和初始的一些功能,测试文件的一个环境。我们来搭建一个 jquery 插件的脚手架:

1
grunt init:jquery

测试:

1
2
3
grunt qunit
grunt lint
grunt watch

Grunt 的设计原理个人理解

Grunt 其实就是一个 singleton 的对象。框架提供了 task 注册和运行的功能。像项目管理一样,收集任务,编排任务,并规定执行顺序。

  • grunt.initConfig 是全局设置,配置 task 的执行参数或 context。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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 注册 task 信息。

    • grunt.loadTasks('tasks'), ‘tasks’是文件夹名,通过 node module 批量注册任务。

      1
      2
      3
      4
      5
      "use strict";
      module.exports = function(grunt) {
      grunt.initConfig({});
      grunt.registerTask("test", ["clean", "ui5_build", "nodeunit"]);
      };
      • node module 中 通过 API grunt.registerTask or registerMultiTask, 注册 task 信息。
    • grunt.loadNpmTasks, 加载注册 grunt plugin,别人设计的 task。

Grunt plugin

利用 Grunt 脚手架,快速创建贴合自己需要的项目需要的,项目内部可重用的 plugin。d
参考Grunt 项目脚手架

Debug Grunt in VSCode

VSCode 基于 NodeJS 构建,天生支持 JS 的调试,而 Grunt 又是 js 的,所以,可以调试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Grunt",
// "program": "${workspaceFolder}\\node_modules\\@sap\\approuter\\approuter.js"
"program": "${env:APPDATA}\\npm\\node_modules\\grunt-cli\\bin\\grunt",
"args": ["testBuild"],
"stopOnEntry": true,
"cwd": "${workspaceRoot}"
}
]
}
感谢支持,让我安静的做蚂蚁梦!