详解使用grunt完成requirejs的合并压缩和js文件的版本控制


Posted in Javascript onMarch 02, 2017

最近有一个项目使用了 requirejs 来解决前端的模块化,但是随着页面和模块的越来越多,我发现我快要hold不住这些可爱的js文件了,具体表现在每个页面都要设置一堆 requirejs 的配置( baseUrl paths 之类的)。

不知谁说过,一些事重复做了三次,就该考虑一下自动化了,于是我小心翼翼的掏出了我的 grunt

我们得使用 grunt-contrib-requirejs 这个插件来实现如上所说的自动化功能,这个就是根据 r.js 封装的 grunt 插件。

安装 grunt-contrib-requirejs

npm i --save-dev grunt-contrib-requirejs

配置 Grantfile

首先我们来看下项目目录

详解使用grunt完成requirejs的合并压缩和js文件的版本控制

src 是每个页面的依赖文件

moduleslib 是一些模块和库

dist 是合并压缩后的文件

Gruntfile 中首先得到需要处理的文件列表,并创建一个空对象,用来装requirejs的配置

var files = grunt.file.expand('static/js/src/*.js');
var requireOptions = {};

然后遍历这个文件列表数组,得到js文件的名称:

files.forEach(function (file) {
  var filenamelist = file.split('/');
  var num = filenamelist.length;
  var filename = filenamelist[num - 1].replace(/\.js$/,'');
}

接下来为每个js文件配置一个任务,任务名称就是js的文件名称:

files.forEach(function (file) {
  requireOptions[filename] = {
    options: {
      baseUrl: 'static/js',
      paths: {
        jquery: 'lib/jquery.min',
        lrz: 'lib/lrz.all.bundle',
        zepto: 'lib/zepto.min',
        ajax: 'modules/ajax',
        validators: 'modules/validators',
        page: 'modules/mixins/to_page',
        dialog: 'modules/mixins/toggle_login_dialog',
      },
      optimizeAllPluginResources: true,
      name: 'src/' + filename,
      out: 'static/js/dist/' + filename + '.js'
    }
  };
}

接着初始化 grunt 配置并加载并注册任务

grunt.initConfig({
  requirejs: requireOptions
})

grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('require', ['requirejs']);

到这里 requirejs 的配置部分就结束了,在命令行输入 grunt require 就会看到 static/js/dist 目录下面有东西蹦出来了,而且全部都是合并后并压缩好的。

在html页面中只需要:

<script src="static/js/require.js"></script>
<script src="static/js/dist/index.js"></script>

就能成功加载了。

增加js文件的版本号

浏览器有时会对加载过的js或css进行缓存,如果你的某些js依赖发生改变,那么就可能发生错误,解决办法是在文件后面增加查询字符串,例如 a.js?v=dsd712sd

那么如何控制版本,首先我们肯定想到用 new Date() ,但是如果每次发布都让浏览器重新加载(尽管有些文件根本就没有改变),难免会造成浪费。正确的方案是根据文件内容生成MD5值来作为版本号,这样当文件没有改变时,hash就不会变。

那么如何自动解决版本号的问题,我们可以用到 asset-cache-control 这个grunt插件

首先安装:

npm i --save-dev asset-cache-control

asset-cache-control 的用法个很简单,只要设置一个源文件,再设置html文件的路径就可以了

grunt.initConfig({
  cache: {
    demo: {
      assetUrl: 'js/demo.js',
      tmp: ['demo.html']
    }
  }
})

注意的是:html文件中需要引入 js/demo.js

<script src='js/demo.js'></script>

然后加载和注册 asset-cache-control 插件

grunt.loadNpmTasks('asset-cache-control');
grunt.registerTask('cache', ['cache']);

接着在命令行敲 grunt cache 就会发现 index.html 中的 script 标签加上了查询字符串。

<script src='js/demo.js?t=92e26c5d'></script>

对每个js文件配置 cache 的任务:

var files = grunt.file.expand('static/js/src/*.js');
var cacheOptions ={};
files.forEach(function (file) {
  var filenamelist = file.split('/');
  var num = filenamelist.length;
  var filename = filenamelist[num - 1].replace(/\.js$/,'');
  cacheOptions[filename] = {
    assetUrl: 'static/js/dist/' + filename +'.js',
    files: {
      'tmp': [filename+'.php']
    }
  }
});

检测每个文件的变化,自动执行任务

用到 grunt-contrib-watch 这个官方组件

grunt.initConfig 中配置:

watch: {
  files: ['static/js/src/*.js','static/js/modules/*.js'],
  tasks: ['requirejs', 'cache'],
  options: {
    spawn: false
  }
}

这样,当你修改 static/js/src/ static/js/modules/ 下的所有js文件时,就会执行 requirejs cache 任务。

完整配置清单

module.exports = function (grunt) {
  var files = grunt.file.expand('static/js/src/*.js');
  var requireOptions = {};
  var cacheOptions ={};
  files.forEach(function (file) {
    var filenamelist = file.split('/');
    var num = filenamelist.length;
    var filename = filenamelist[num - 1].replace(/\.js$/,'');
    requireOptions[filename] = {
      options: {
        baseUrl: 'static/js',
        paths: {
          jquery: 'lib/jquery.min',
          lrz: 'lib/lrz.all.bundle',
          zepto: 'lib/zepto.min',
          ajax: 'modules/ajax',
          validators: 'modules/validators',
          page: 'modules/mixins/to_page',
          dialog: 'modules/mixins/toggle_login_dialog',
        },
        optimizeAllPluginResources: true,
        name: 'src/' + filename,
        out: 'static/js/dist/' + filename + '.js'
      }
    };
    cacheOptions[filename] = {
      assetUrl: 'static/js/dist/' + filename +'.js',
      files: {
        'tmp': [filename+'.php']
      }
    }
  });

  grunt.initConfig({
    requirejs: requireOptions,
    cache: cacheOptions,
    watch: {
      files: ['static/js/src/*.js','static/js/modules/*.js'],
      tasks: ['requirejs', 'cache'],
      options: {
        spawn: false
      }
    }
  });

  grunt.loadNpmTasks('asset-cache-control'); 
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.registerTask('require', ['requirejs','cache'])
};

另外,浏览器加载一个大文件比加载n个小文件的效率要高很多,所以模块的合并对性能也有很大的提高。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
php gethostbyname获取域名ip地址函数详解
Jan 24 Javascript
jquery插件如何使用 jQuery操作Cookie插件使用介绍
Dec 15 Javascript
基于jQuery实现带动画效果超炫酷的弹出对话框(附源码下载)
Feb 22 Javascript
jQGrid动态填充select下拉框的选项值(动态填充)
Nov 28 Javascript
JS实现线性表的链式表示方法示例【经典数据结构】
Apr 11 Javascript
解决vue router使用 history 模式刷新后404问题
Jul 19 Javascript
微信小程序url与token设置详解
Sep 26 Javascript
关于在vue 中使用百度ueEditor编辑器的方法实例代码
Sep 14 Javascript
微信小程序使用template标签实现五星评分功能
Nov 03 Javascript
Vue.js中 v-model 指令的修饰符详解
Dec 03 Javascript
浅析vue-cli3配置webpack-bundle-analyzer插件【推荐】
Oct 23 Javascript
vue 通过base64实现图片下载功能
Dec 19 Vue.js
jQuery上传多张图片带进度条样式(DEMO)
Mar 02 #Javascript
jquery仿京东侧边栏导航效果
Mar 02 #Javascript
关于jQuery EasyUI 中刷新Tab选项卡后一个页面变形的解决方法
Mar 02 #Javascript
JavaScript html5利用FileReader实现上传功能
Mar 27 #Javascript
利用ES6语法重构React组件详解
Mar 02 #Javascript
深入理解在JS中通过四种设置事件处理程序的方法
Mar 02 #Javascript
JavaScript表单验证完美代码
Mar 02 #Javascript
You might like
phpMyadmin 用户权限中英对照
2010/04/02 PHP
php获取淘宝分类id示例
2014/01/16 PHP
微信公众号判断用户是否已关注php代码解析
2016/06/24 PHP
PHP中模糊查询并关联三个select框
2017/06/19 PHP
网页的标准,IMG不支持onload标签怎么办
2006/06/29 Javascript
Javascript开发包大全整理
2006/12/22 Javascript
基于jquery自己写tab滑动门(通用版)
2012/10/30 Javascript
终于解决了IE8不支持数组的indexOf方法
2013/04/03 Javascript
JQuery中使用ajax传输超大数据的解决方法
2014/07/14 Javascript
JavaScript代码实现禁止右键、禁选择、禁粘贴、禁shift、禁ctrl、禁alt
2015/11/17 Javascript
JS实现的驼峰式和连字符式转换功能分析
2016/12/21 Javascript
微信小程序 弹幕功能简单实例
2017/02/14 Javascript
vue-cli+axios实现文件上传下载功能(下载接收后台返回文件流)
2019/05/10 Javascript
小程序实现锚点滑动效果
2019/09/23 Javascript
[01:29]2014DOTA2展望TI 剑指西雅图DK战队专访
2014/06/30 DOTA
python自然语言编码转换模块codecs介绍
2015/04/08 Python
Python三级目录展示的实现方法
2016/09/28 Python
Python 专题四 文件基础知识
2017/03/20 Python
Python中super函数的用法
2017/11/17 Python
Python爬取qq空间说说的实例代码
2018/08/17 Python
详解Numpy数组转置的三种方法T、transpose、swapaxes
2019/05/27 Python
在python tkinter中Canvas实现进度条显示的方法
2019/06/14 Python
python实现kNN算法识别手写体数字的示例代码
2019/08/16 Python
Python通过fnmatch模块实现文件名匹配
2020/09/30 Python
荷兰皇家航空公司官方网站:KLM Royal Dutch Airlines
2017/12/07 全球购物
俄罗斯运动、健康和美容产品在线商店:Lactomin.ru
2020/07/23 全球购物
一套Delphi的笔试题二
2013/05/11 面试题
汉语专业应届生求职信
2013/10/01 职场文书
电视节目策划方案
2014/05/16 职场文书
化工专业自荐书
2014/06/16 职场文书
幼儿园校园小喇叭广播稿
2014/10/17 职场文书
六年级学生评语大全
2014/12/26 职场文书
关于教师节的广播稿
2015/08/19 职场文书
Feign调用全局异常处理解决方案
2021/06/24 Java/Android
阿里云k8s服务升级时502错误 springboot项目应用
2022/04/09 Servers
基于Python编写一个监控CPU的应用系统
2022/06/25 Python