窃以为这两个插件是比较有用的,filerev是给js、css进行编码重命名,usemin修改html中被重命名的js、css文件的引用。另外说明下之前将concat、cssmin、uglify放在一篇中的原因,因为usemin会自动对引用中的css文件进行concat和cssmin,对js文件进行concat和uglify。也就是说,如果不是定制化需求,只是简单的合并和压缩,使用了usemin就不用配置concat、cssmin、uglify这些task了。

  filerev相对比较简单,更完filerev可能要过段时间来更usemin。

  filerev(V2.1.2)的options(github地址)

  1. argorithm: 编码方式,接受参数'md5'、'sha1'、'sha256'、'sha512'
  2. length: 截取用来重命名的字符串长度

  注意1:重命名后会生成map对象grunt.filerev.summary,key为源文件名,value为目的文件名,filerev任务后可使用此对象获取数据
  注意2:很多人采用grunt-rev这个插件,但由于grunt-filerev和grunt-usemin在github上为同一个账号下的项目(大名鼎鼎的yoeman),所以这里采用grunt-filerev

  usemin(V3.0.0)(github地址)

  这部分不采用列options的方式了,因为是核心,也是难点,一步一步跟着代码走起来。

  代码结构是源文件夹src下面包含base.css、main.css、helloworld.js、hellogrunt.js、index.html五个文件

  Gruntfile.js

module.exports = function (grunt) {
require('load-grunt-tasks')(grunt); var path = {
src : 'src',
dest : 'dist',
tmp : '.tmp'
} grunt.initConfig({
path : path,
clean : {
beforebuild : {
files : [{
src : ['<%= path.dest %>/', '<%= path.tmp %>/']
}
]
}
},
filerev : {
build : {
files : [{
src : ['<%= path.dest %>/**', '!<%= path.dest %>/index.html']
}
]
}
},
useminPrepare : {
build : {
files : [{
src : '<%= path.src %>/index.html'
}
]
}
},
usemin : {
html : {
files : [{
src : '<%= path.dest %>/index.html'
}
]
},
css : {
files : [{
src : '<%= path.dest %>/*.css'
}
]
}
},
copy : {
build : {
files : [{
expand : true,
cwd : '<%= path.src %>/',
src : ['index.html'],
dest : '<%= path.dest %>/'
}
]
}
},
imagemin : {
build : {
files : [{
expand : true,
cwd : '<%= path.src %>/',
src : ['*.{jpg, png, jpeg, gif}'],
dest : '<%= path.dest %>/'
}
]
}
}
});
grunt.registerTask('default', ['clean:beforebuild', 'copy', 'imagemin', 'useminPrepare', 'concat', 'cssmin', 'uglify', 'filerev', 'usemin']);
};

  index.html

<html>
<head>
<!-- build:css base.css -->
<link rel="stylesheet" href="base.css"/>
<!-- endbuild -->
<!-- build:css main.css -->
<link rel="stylesheet" href="main.css"/>
<!-- endbuild -->
</head>
<body>
<p>index</p>
<!-- build:js hello.js -->
<script type="text/javascript" src="helloworld.js"></script>
<script type="text/javascript" src="hellogrunt.js"></script>
<!-- endbuild -->
</body>
</html>

  在命令行输入grunt,输出目录下的文件base.33fa5f7d.css、main.d58400c3.css、hello.c2959b6b.js、index.html为,其中index.html如下

<html>
<head>
<link rel="stylesheet" href="base.33fa5f7d.css">
<link rel="stylesheet" href="main.d58400c3.css">
</head>
<body>
<p>index</p>
<script src="hello.c2959b6b.js"></script>
</body>
</html>

  如上是usemin最简单的实现,但直接抛出所有代码肯定会造成一定的困扰

  1. html中那些注释是什么意思
  2. gruntfile中dist和.tmp两个文件夹是什么
  3. gruntfile中useminPrepare是什么,跟usemin是什么关系
  4. gruntfile中useminPrepare指定的html和usemin中指定的html为什么不一样,能一样么
  5. gruntfile中usemin的target的名字为什么是html,而其他的都是build
  6. gruntfile中并未指定concat、cssmin、uglify等task,为什么最后执行了

  首先,html中的注释是有意义的,是usemin定义的一种语法结构,规则如下

<!-- build:<type> <output path> -->
... HTML Markup, list of script / link tags.
<!-- endbuild -->

  以上为一个block,其中声明的tags会被合并和压缩为一个文件output path,type定义不同的规则,原生支持js和css,也支持自定义,那是后话。

  接下来,后面的问题要先捋顺整个流程,执行grunt后打印的log如下

Running "clean:beforebuild" (clean) task
>> paths cleaned. Running "copy:build" (copy) task
Copied file Running "useminPrepare:build" (useminPrepare) task
Configuration changed for concat, uglify, cssmin Running "concat:generated" (concat) task
File .tmp\concat\base.css created.
File .tmp\concat\main.css created.
File .tmp\concat\hello.js created. Running "cssmin:generated" (cssmin) task
File dist\base.css created: B → B
File dist\main.css created: B → B Running "uglify:generated" (uglify) task
>> file created. Running "filerev:build" (filerev) task
Revved files Running "usemin:html" (usemin) task
Replaced reference to assets
  1. clean,删除dist和.tmp文件夹,涉及第二个问题
  2. copy,复制index.html到dist,涉及第四个问题
  3. useminPrepare,涉及第三、六个问题
  4. concat,合并文件,涉及.tmp文件夹,第二、六个问题
  5. cssmin、uglify,压缩文件,涉及dist文件夹,第二、六个问题
  6. filerev,给dist文件夹下的文件重命名,涉及第二个问题
  7. usemin,给html文件进行引用修改,涉及第四、五个问题

  useminPrepare,grunt-usemin包含两个task:一个是useminPrepare,一个是usemin。useminPrepare的功能是进行一些前期工作(第三个问题),主要是声明concat、cssmin、uglify等task,仅仅是声明,依赖、load、register还是要有的(第六个问题)。而这些task生成的临时文件即concat文件会存放到.tmp中,目标文件即压缩后的文件会存放到dist中(第二个问题)。那怎么找需要处理的资源文件呢,则是通过源html的引用(第四个问题)。经过这三个task和filerev后,usemin正式修改目标html中的引用(第四个问题),而且usemin不仅可以修改html中的引用,甚至可以修改css中的引用,前者为html target,后者为css target(第六个问题)。

  以上就是那几个问题行诸于文字的解释了,要行诸于代码,还要从options说起。

  useminPrepare的options

  1. dest: 默认是'dist',定义目标文件夹
  2. staging: 默认是'.tmp',定义临时文件夹
  3. root: 默认是源html所在的文件夹,定义处理的资源文件的相对路径
    举个栗子,我们把src中的目录结构标准化,如下:
    我这里添加了一张图片,后话解释
    结构变了,但是引用没变,也就是照之前的情况是找不到引用的源资源文件的,输入grunt,得到的结果如下
    Running "clean:beforebuild" (clean) task
    >> paths cleaned. Running "copy:build" (copy) task
    Copied file Running "useminPrepare:build" (useminPrepare) task
    Configuration changed for concat, uglify, cssmin Running "concat:generated" (concat) task
    File .tmp\concat\base.css created.
    File .tmp\concat\main.css created.
    File .tmp\concat\hello.js created. Running "cssmin:generated" (cssmin) task
    >> Destination not written because minified CSS was empty.
    >> Destination not written because minified CSS was empty. Running "uglify:generated" (uglify) task
    >> file created. Running "filerev:build" (filerev) task
    Revved files Running "usemin:html" (usemin) task
    Replaced reference to assets

    虽然在临时文件夹中生成了css和js,但因为没有源文件,生成的都是空文件,所以cssmin的时候报错了,uglify不过也是生成了空文件而已。

    这时候我们修改下useminPrepare,如下

    options: {
    root: [
    '<%= path.src %>/css',
    '<%= path.src %>/js'
    ]
    }

    然后grunt,是不是又正常了

  4. flow: 重点中的重点,核心中的核心,虽然用到的不多,但是对理解整个流程是有帮助的,默认值是这个样子的
    { steps: { js: ['concat', 'uglifyjs'], css: ['concat', 'cssmin'] }, post: {} }

    这个object中有两个属性,steps定义block中针对不同type的处理方式,post定义不同的处理过程中额外的行为,还是举个栗子
    比如concat中的separator是换行符,你如果想修改为;,那么可以这样做

    flow: {
    steps: {
    js: ['concat', 'uglifyjs'],   //注意不是uglify,是uglifyjs,下面的post中对应的name为uglify
    css: ['concat', 'cssmin']
    },
    post: {
    js: [{
    name: 'concat',
    createConfig: function (context, block) {
    var generated = context.options.generated;  //context.options即concat task
    generated.options = {
    separator: ';'
    };
    }
    }]
    }
    }

    上面的createConfig中的block对象为html中的block对象化

    <!-- build:js scripts/site.js -->',
    <script src="foo.js"></script>',
    <script src="bar.js"></script>',
    <script src="baz.js"></script>',
    <!-- endbuild -->'

    此段block对应的block对象为

    var block = {
    type: 'js',
    dest: 'scripts/site.js',
    src: [
    'foo.js',
    'bar.js',
    'baz.js'
    ],
    raw: [
    ' <!-- build:js scripts/site.js -->',
    ' <script src="foo.js"></script>',
    ' <script src="bar.js"></script>',
    ' <script src="baz.js"></script>',
    ' <!-- endbuild -->'
    ]
    };

  usemin的options

  1. assetsDirs: 类似useminPrepare中的root,指定html文件中资源根目录
  2. blockReplacements: 类似flow在useminPrepare的地位,流程的核心,默认的值如下
    { css: function (block) { return ...; }, js: function (block) { return ...; } }

    属性对应block中的type,return的值为最后输出的script / css tag,如果资源文件配置在CDN或静态服务器上,就需要修改原来的方法了

    js: function(block) {
    var sFile = path.dest + require('path').sep + block.dest.replace(/\//g, '\\'), //require('path').sep是用来获取文件分隔符的,windows下面为\,linux下面为/
    dFile = grunt.filerev.summary[sFile].replace(/\\/g, '/'); //记得filerev提到的那个对象么
    return '<script type="text/javascript" src="' + 'http://static.*.*/' + dFile + '"></script>';
    }

    同时也可以处理自定义type的函数

    比如我们开发过程中引用了less.js,但release版本肯定是不能上的,就在源html中自定义一个block

    <!-- build:remove -->
    <script type="text/javascript" src="less.js"></script>
    <!-- endbuild -->

    type为remove,然后在Gruntfile.js中添加处理函数

    blockReplacements: {
    remove: function(block) {
    return '';
    }
    }

    目标html中就不包含对less.js的引用了

  3. revmap: JSON文件的路径,文件对象写法参考grunt.filerev.summary

  这一节内容告一段落了,日后想到再行补充,下节介绍更简单、更有意思的connect和watch。

grunt之filerev、usemin的更多相关文章

  1. Grunt usemin

    yeoman/grunt-usemin 用来将 HTML 文件中(或者 templates/views)中没有优化的 script 和 stylesheets 替换为优化过的版本. usemin 暴露 ...

  2. Grunt针对静态文件的压缩,版本控制打包方案

    在讲之前先谈谈大致步骤:安装nodejs -> 全局安装grunt -> 项目创建package.json --> 项目安装grunt以及grunt插件 -> 配置Gruntf ...

  3. Grunt 一个专为JavaScript提供的构建工具

    新手最好找个视频来看看, Grunt的配置及使用(压缩合并js/css) - 每天都记录一点点! - CSDN博客https://blog.csdn.net/playboyanta123/articl ...

  4. Grunt Part 2

    Objectives and Outcomes In this exercise, you will continue to learn to use Grunt, the task runner. ...

  5. Grunt:GruntFile.js

    ylbtech-Grunt:GruntFile.js 1.返回顶部 1. module.exports = function (grunt) { grunt.initConfig({ useminPr ...

  6. 初识yeoman

    最近开始新项目,在项目构建上面寻找合适的东西,grunt,bower到发现yeoman;学习了下,把一些东西记录下来然留着以后用. 1.什么是Yeoman Yeoman是Google的团队和外部贡献者 ...

  7. Encoding::CompatibilityError: incompatible character encodings: GBK and UTF-8

    直接grunt serve读的css是.tmp/css/main.css 而这个文件不通过build生成出来是这样: /* Encoding::CompatibilityError: incompat ...

  8. 杂项-TMod:常见错误

    ylbtech-杂项-TMod:常见错误 1.返回顶部 1. 1.1. {Template Error} TypeError: dateDiff is not a function at Array. ...

  9. npm scripts + webpack 实践经验(React、Nodejs)

    最近用Webpack+npm scripts+Mongodb+Nodejs+React写了个后台项目,在用Webpack构建过程中遇到了许多坑,就写出来分享一下. 构建工具五花八门,想当年刚学会Gru ...

随机推荐

  1. VPS安装中文语言

    在CentOS VPS下修改语言编码: localedef -c -f UTF-8 -i zh_CN zh_CN.utf8 export LC_ALL=zh_CN.utf8 上面第一步是用来产生编码文 ...

  2. Hibernate批量操作(一)

    在项目的开发过程之中,我们常会遇到数据的批量处理问题.在持久层采用Hibernate框架时,在进行批量操作时,需要考虑Hibernate实现机制带来的一些问题. 我们知道在每个Hibernate Se ...

  3. Koa框架教程,Koa框架开发指南,Koa框架中文使用手册,Koa框架中文文档

    我的博客:CODE大全:www.codedq.net:业余草:www.xttblog.com:爱分享:www.ndislwf.com或ifxvn.com. Koa -- 基于 Node.js 平台的下 ...

  4. POJ-1861-NETWORK 解题报告

    Network Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 16628   Accepted: 6597   Specia ...

  5. java中使用poi导出excel表格数据并且可以手动修改导出路径

    在我们开发项目中,很多时候会提出这样的需求:将前端的某某数据以excel表格导出,今天就给大家写一个简单的模板. 这里我们选择使用poi导出excel: 第一步:导入需要的jar包到 lib 文件夹下

  6. 在Entity Framework 中用 Code First 创建新的数据库

    在Entity Framework 中用 Code First 创建新的数据库 (原文链接) 本文将逐步介绍怎样用Code First 创建新数据库,使用在代码中定义类和API中提供的特性(Attri ...

  7. Java面试题大全

    前言 关于赢在面试的Java题系列基本收集整理完成了,所有题目都是经过精心挑选的,很基础又考验求职者的基本功,应该说被面试到的几率很大.这里整理挑选出来供大家面试前拿来看一看,所有题目整理自网络,有一 ...

  8. django开发者模式中的autoreload是怎样实现的

    在开发django应用的过程中,使用开发者模式启动服务是特别方便的一件事,只需要 python manage.py runserver 就可以运行服务,并且提供了非常人性化的autoreload机制, ...

  9. JS进阶 ] 分析JS中的异步操作

    写在前面 JS因为是单线程的,所以在执行事务的时候,往往会因为某个事务的延迟,而导致服务器假死,这时候异步编程就显的格外重要,但是异步编程一般理解为回调函数callback,典型的就是node,回调函 ...

  10. 17个新手常见Python运行时错误

    当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂.这里列出了常见的的一些让你程序 crash 的运行时错误. 1)忘记在 if , elif , else , for , ...