前端工作流,Grunt上手指南

Grunt ,  javascript

我想先花点时间回忆一下作为一个前端需要做的工作(Loading...)

  • JS合并
  • JS压缩
  • CSS压缩
  • CSS Sprite
  • 图片优化
  • 测试
  • 静态资源缓存(版本更新)
  • ...

对应的,一个全副武装的前端可能会是这样的:

  • JSHint
  • CSSLint
  • Jade
  • CoffeeScript
  • RequireJS/SeaJS
  • Compass/Stylus/Less
  • QUnit/Mocha/Jasmine
  • ...

就是这么苦逼的设定,但其实也正是有了这些天才的工具和解决方案才让我们的工作变得更美好,WTF

随身装备这么多武器,拔刀的姿势很重要,手忙脚乱焦头烂额的狼狈样肯定是不行的。如果每个工具(任务)对应一个招数的话,Grunt就是用来组合各种华丽连续技的辅助装备。这比喻略显白烂,高端大气国际化的说法叫“工作流”(Workflow)。所以开始进入正题: Grunt锻造指南,参见!

Note:这些都是基于Grunt 0.4.x版本,需要Nodejs版本>=0.8.0

命令行下安装:

# 如果之前有装过grunt,卸载之npm uninstall -g grunt# 安装grunt运行工具npm install -g grunt-cli

一个grunt项目需要两个文件:package.jsonGruntfile.js,前者用于nodejs包管理,比如grunt插件安装,后者是grunt配置文件,配置任务或者自定义任务。

先生成一个package.json文件,在grunt项目的目录下运行npm install就可以生成一个空的package.json

安装grunt到当前目录:npm install grunt --save-dev

再生成一个Gruntfile.js的模板文件,这时候可以用grunt-init,或者直接手写一个:

module.exports = function(grunt) {
    grunt.initConfig({
        // task configuration
    });

    // Load the plugin
    grunt.loadNpmTasks(‘grunt-contrib-uglify‘);

    // Default task(s)
    grunt.registerTask(‘default‘, [‘uglify‘]);});

关于插件

grunt利用不同的插件完成不同的任务,比如用uglifyJS压缩js对应的插件就是grunt-contrib-uglify

使用插件(以grunt-contrib-uglify为例):

  • 在grunt项目目录下安装对应的插件 npm install grunt-contrib-uglify --save-dev
  • 在 Gruntfile.js 中加载插件 grunt.loadNpmTasks(‘grunt-contrib-uglify‘)
  • 在 Gruntfile.js 中配置对应的插件任务,指定要压缩的js文件

关于配置和怎么运行任务往下细说。

这里可以看到可用的插件,基本上大部分你能想到或没想到的任务都能找到对应的插件,需要做什么就装什么。

以后如果要重用一个grunt项目的配置,只需要有package.jsonGruntfile.js这两个文件,然后npm install即可安装所有依赖的插件。

一个插件就是对应一个任务,一般来说,所有插件都会遵循下面将要说到的任务配置规则,很多插件的文档都不会很详细,所以你只能根据插件提供的示例套用这些规则看有没有更多配置的可能性。

关于任务

任务分为两种:"Basic" Tasks和"Multi" Tasks

Multi-tasks有所谓的target,比如下面的concat任务有foobar两个targets,而uglify任务有一个叫bar的target

grunt.initConfig({
    concat: {
        foo: {
            // concat task ‘foo‘ target options and files go here.
        },
        bar: {
            // concat task ‘bar‘ target options and files go here.
        }
    },
    uglify: {
        bar: {
            // uglify task ‘bar‘ target options and files go here.
        }
    }});

target的名字可以任意指定,因为target只是为了用特定配置运行指定的任务,比如grunt concat:foo或者grunt concat:bar会分别运行foo或者bar指定的concat任务。如果只运行grunt concat将会遍历所有concat下的targets按顺序运行。

但是任务的名称比如concatuglify是固定的,由对应的插件指定,在插件的使用文档里面都会有说明。

每个multi task都必须有至少一个target.

不需要配置的任务就是Basic Task,你可以这样来定义一个Basic Task,grunt.registerTask(taskName, [description, ] taskFunction)

// foo taskgrunt.register(‘foo‘, function(arg1, arg2) {
    // do something});

这样运行:grunt foo,或者grunt foo:a:bab就是传递给foo的参数

模板变量

grunt可以通过类似<%= k.sub.k %>这种格式插入配置的其他属性值

Options

在一个任务配置里面,option属性可以用来覆盖默认的配置,另外,每个target都可以有自己的option属性。target的option优先级高于task的。options是可选的。

grunt.initConfig({
    concat: {
        options: {
            // Task-level options may go here, overriding task defaults.
        },
        foo: {
            options: {
                // ‘foo‘ target options may go here, overriding task-level options.
            },
        },
        bar: {
            // No options specified; this target will use task-level
            options.
        },
    },});

不一定所有的任务都会有option的。

指定文件

这应该是刚接触grunt时最让人不知所措的地方了,想想这么多插件,每个插件都需要指定对应要应用到的文件,但是咋一看好像每个插件都有一套自己配置文件的方式,配置方式看上去很随意,所以总是会觉得有一丝不靠谱。

就像之前提到的,其实是有一套通用的规则的:

Grunt提供了几种不同的格式定义src-dest形式的文件映射。任何multi-task都支持这几种格式。

文件映射可以有3种格式:Compact Format, Files Object Format和File Array Format, 其中"Compact"和"File Array"这两种形式提供了一些额外的属性可用:

  • filter 过滤,接受fs.Stats方法定义的名字,比如isFileisDirectory,或者自定义函数接受一个源文件名做为参数,返回true or false
  • nonull Retain src patterns even if they fail to match files. Combined with grunt‘s --verbose flag, this option can help debug file path issues.
  • matchBase Patterns without slashes will match just the basename part.
  • ......(剩下几个看文档吧)
  • 另外还有一个动态文件列表生成(批量匹配文件)

以下示例中的属性名srcdestfiles都是固定的key名,一开始就不必纠结了。

Compact Format

这种形式只允许单个src-dest映射在一个target里面,只有src属性是必须的,可以没有dest,这种形式一般用在只读的task,比如jshint

grunt.initConfig({
  jshint: {
    foo: {
      src: [‘src/aa.js‘, ‘src/aaa.js‘]
    },
  },
  concat: {
    bar: {
      src: [‘src/bb.js‘, ‘src/bbb.js‘],
      dest: ‘dest/b.js‘,
    },
  },});

Files Object Format

这种形式支持指定多个src-dest对应多个target,属性名(key)是要输出的目标文件名,value值是源文件列表。不支持额外的属性

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‘],
      },
    },
  },});

Files Array Format

同上,只是支持额外的属性

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‘},
      ],
    },
  },});

通配符支持

由nodejs内置的node-glob库支持,这些都可以用在上面所说的各种文件配置中

  • *匹配任何字符,除了/
  • ?匹配单个字符,除了/
  • **匹配任何字符,包括/,所以用在目录路径里面
  • {}逗号分割的“或”操作(逗号后面不要有空格)
  • ! 排除某个匹配
    // You can specify single files:{src: ‘foo/this.js‘, dest: ...}// Or you can generalize with a glob pattern:{src: ‘foo/th*.js‘, dest: ...}// This single node-glob pattern:{src: ‘foo/{a,b}*.js‘, dest: ...}// Could also be written like this:{src: [‘foo/a*.js‘, ‘foo/b*.js‘], dest: ...}// All files in alpha order, but with bar.js at the end.{src: [‘foo/*.js‘, ‘!foo/bar.js‘, ‘foo/bar.js‘], dest: ...}// Templates may be used in filepaths or glob patterns:{src: [‘src/<%= basename %>.js‘], dest: ‘build/<%= basename %>.min.js‘}

动态生成文件名

  • expand 设置为true打开以下选项
  • cwd 所有src指定的文件相对于这个属性指定的路径
  • src 要匹配的路径,相对与cwd
  • dest 生成的目标路径前缀
  • ext 替换所有生成的目标文件后缀为这个属性
  • flatten 删除所有生成的dest的路径部分
  • rename 一个函数,接受匹配到的文件名,和匹配的目标位置,返回一个新的目标路径
    grunt.initConfig({
        minify: {
            dynamic_mappings: {
                // Grunt will search for "**/?.js" under "lib/" when the "minify" task runs 
                files: [
                    {
                        expand: true,     // Enable dynamic expansion.
                        cwd: ‘lib/‘       // Src matches are relative to this path.
                        src: [‘**/?.js‘], // Actual pattern(s) to match.
                        dest: ‘build/‘,   // Destination path prefix.
                        ext: ‘.min.js‘,   // Dest filepaths will have this extension.
                    }
                ]
            }
        }});

自定义任务

这里总结一些遇到的问题吧

获取/设置配置(模板变量)

  • 可以读取json配置文件:config: grunt.file.readJSON(‘config.json‘)
  • 获取json对象的属性:grunt.config(‘config.key.subkey‘)
  • 对应的模板变量:‘<%= config.key.subkey %>‘
  • 设置配置段:grunt.config(‘config‘, ‘value‘)

动态更改任务配置,循环执行某个任务

grunt的任务都会放入一个队列顺序执行,但是队列本身是异步执行的,所以下面的这种做法是不会如预期输出:

grunt.registerTask(‘demo‘, function() {
    for (var i = 0; i < 5; i++) {
        grunt.task.run(‘t‘);
    }

    // 期望执行完5次`t`任务之后打印输出
    // 实际上会立即输出,在`t`任务开始之前
    console.log(‘run after t‘);

    // 执行5次`t`任务之后才会执行这个`final`任务
    grunt.task.run(‘final‘);});

动态更改任务配置可以利用模板变量来做,由于如上所说的异步,所以不能直接在循环中给模板变量赋值,而是要额外做一个任务来接受配置:

// 假如有这样的一个配置t: {
    target: ‘some <%= param %>‘}// 在这个demo任务中需要多次调用t任务,每次都要设置paramgrunt.registerTask(‘demo‘, function() {
    for (var i = 0; i < 5; i++) {
        // 要一个额外任务去更改配置
        grunt.task.run(‘t_wrapper:‘ + i);
    }});// 更改`t`配置并运行grunt.register(‘t_wrapper‘, function(i) {
    grunt.config(‘param‘, i);
    grunt.task.run(‘t‘);});

还有一种方法可以克隆一个新的target,然后直接更改这个cloned target的配置

grunt.config和grunt.option的区别

grunt.config如上所述可以用来动态更改模板变量,但是grunt.option不能这样,如果在配置中直接使用grunt.option,则option在运行时就已经确定了,不能再更改,假设这样配置:

t: {
    target: ‘some ‘ + grunt.option(‘param‘)}

运行grunt t --param=0,则target对应就是‘some 0‘,不能再通过grunt.option(param, 1)这样来更改配置

grunt.optiongrunt.config都可以用来在任务之间共享一些信息,但option更多用来接受额外的任务参数。

设置输出文字颜色

直接在字符串后面点一个颜色:grunt.log(‘test color‘.green)

References

假如你已经熟悉了Grunt,可以去看看Yeoman,也许能为你提供更多灵感。

时间: 2024-10-08 07:56:23

前端工作流,Grunt上手指南的相关文章

Grunt上手指南(转)

Grunt ,  javascript 我想先花点时间回忆一下作为一个前端需要做的工作(Loading...) JS合并 JS压缩 CSS压缩 CSS Sprite 图片优化 测试 静态资源缓存(版本更新) ... 对应的,一个全副武装的前端可能会是这样的: JSHint CSSLint Jade CoffeeScript RequireJS/SeaJS Compass/Stylus/Less QUnit/Mocha/Jasmine ... 就是这么苦逼的设定,但其实也正是有了这些天才的工具和解

前端开发神器WebStorm--自动化工作流Grunt(02)

为何要用构建工具? 一句话:自动化 对于需要反复重复的任务,例如压缩(minification).编译.单元测试.linting等,自动化工具可以减轻你的劳动,简化你的工作. 当你正确配置好了任务,任务运行器就会自动帮你或你的小组完成大部分无聊的工作. Grunt这货是啥? 最近很火的前端自动化小工具,基于任务的命令行构建工具 http://gruntjs.com 为什么使用Grunt? 使 用Grunt的最大好处在于它带给团队的一致性.如果你曾经多人合作完成工作,你就会知道代码中的不一致性是多

Android SDK上手指南 3:用户交互

在这篇教程中,我们将对之前所添加的Button元素进行设置以实现对用户点击的检测与响应.为了达成这一目标,我们需要在应用程序的主Activity类中略微涉及Java编程内容.如果大家在Java开发方面的经验不太丰富也没必要担心,只要按步骤进行即可完成学习.我们将在本系列的下一篇文章中深入探讨Java语法,从而保证大家了解初步Android开发任务中所必需的编程语言知识. 大家可以在Android当中以多种不同方式实现用户交互.我们将学习两种最为典型的处理方案,从而实现应用按钮对用户点击的感应--

Android SDK上手指南 2:用户界面设计

http://mobile.51cto.com/ahot-419184.htm 内容简介 我们将为应用程序项目添加布局方案,在这方面XML与Eclipse ADT接口将成为工作中的得力助手--不过在后面两节中还会用到一部分Java开发知识.XML与Java在Android平台的开发工作当中可谓无处不在,如果大家对二者还缺乏基本的了解,请尽快想办法补补课.对于刚刚入门的读者朋友来说,本文所介绍的要点将成为各位日后开发工作的重要基础. 1. XML基础知识 在我们开始讨论布局之前,先来梳理作为标记语

Rancher 快速上手指南操作(1)

Rancher 快速上手指南操作(1)该指南知道用户如何快速的部署Rancher Server 管理容器.前提是假设你的机器已经安装好docker了.1 确认 docker 的版本,下面是 ubuntu 的输出 [#63#[email protected] ~]$sudo docker version [sudo] password for cloudsoar: Client: Version:      1.9.1 API version:  1.21 Go version:   go1.4.

Model Maker上手指南

Model Maker上手指南 目录 1.MM可爱的脸 2.MM中的工程Project 3.新建类图 4.添加类成员 5.实现类的方法 6.生成Delphi代码 7.逆向到模型 8.完全的逆向工程 作者:郭方明 完成日期:2005-12-06 version 1.0 联系信箱:[email protected] 注:转载文章,请注明作者信息. 引文: 本文通过一个简单的例子介绍使用MM(ModelMaker)设计类图和生成Delphi代码,以及代码逆向同步的过程:让你在最短的时间内上手MM. 编

树莓派(Raspberry Pi Model B+)无显示器和无线网卡上手指南

树莓派(Raspberry Pi Model B+)无显示器和无线网卡上手指南 最近买了一块树莓派板子(Raspberry Pi Model B+)平时作学习之用,只买了块裸板没有显示器和网卡(现在觉得完全没有必要去买显示器),在搭建环境的时候就遇到了一些问题,现在对在搭建树莓派环境遇到的问题做一个总结. 现在我知道的能够连接到树莓派的方法一共有四种,分别是串口终端操作.局域网.PC直连和手机USB网络共享,后面3种方法都是通过ssh的方式登陆树莓派(装好VNC-server后也可以用VNC查看

UnityShader快速上手指南(三)

简介 这一篇还是一些基本的shader操作:裁剪.透明和法向量的应用 (纠结了很久写不写这些,因为代码很简单,主要是些概念上的东西) 先来看下大概的效果图:(从左到右依次是裁剪,透明,加了法向量的透明) 裁剪 代码 Shader "LT/Lesson3_Cull" { Properties { _Color ("Color", Color) = (1, 1, 1, 1) } SubShader { Pass { Cull Off CGPROGRAM #pragma

DPDK快速上手指南(18.02)

DPDK快速上手(linux) 本文档主要来自linux_gsg-18.02.pdf的翻译,翻译肯定有不妥之处,请批评指正,我会随后修改,不胜感激. 1. 介绍 本文档包含有关DPDK(Data Plane Development Kit的缩写)软件的安装和配置的说明,目的就是让用户快速用起来.本文档描述怎样在linux应用环境下编译和运行一个DPDK应用程序,而不过多深入细节. 1.1文档路线图 以下是针对所有DPDK文档建议的阅读顺序: 发布说明(Release Notes):提供具体的发布