详解使用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 相关文章推荐
通过Unicode转义序列来加密,按你说的可以算是混淆吧
May 06 Javascript
jquery的ajax从纯真网(cz88.net)获取IP地址对应地区名
Dec 02 Javascript
JQuery实现倒计时按钮的实现代码
Mar 23 Javascript
js实现时间显示几天前、几小时前或者几分钟前的方法集锦
May 29 Javascript
JavaScript Math 对象常用方法总结
Apr 28 Javascript
AngularGauge 属性解析详解
Sep 06 Javascript
javascript添加前置0(补零)的几种方法
Jan 05 Javascript
JS实现多级菜单中当前菜单不随页面跳转样式而发生变化
May 30 Javascript
Gulp实现静态网页模块化的方法详解
Jan 09 Javascript
echarts统计x轴区间的数值实例代码详解
Jul 07 Javascript
实例分析JS中的相等性判断===、 ==和Object.is()
Nov 17 Javascript
Vue请求java服务端并返回数据代码实例
Nov 28 Javascript
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
php下实现折线图效果的代码
2007/04/28 PHP
PHP5中虚函数的实现方法分享
2011/04/20 PHP
PHP基于文件存储实现缓存的方法
2015/07/20 PHP
php获取本机真实IP地址实例代码
2016/03/31 PHP
用javascript实现无刷新更新数据的详细步骤 asp
2006/12/26 Javascript
JavaScript 精粹读书笔记(1,2)
2010/02/07 Javascript
JS getAttribute和setAttribute(取得和设置属性)的使用介绍
2013/07/10 Javascript
javascript定时器完整实例
2015/02/10 Javascript
Javascript实现颜色rgb与16进制转换的方法
2015/04/18 Javascript
Javascript节点关系实例分析
2015/05/15 Javascript
js+css简单实现网页换肤效果
2015/12/29 Javascript
深入解析AngularJS框架中$scope的作用与生命周期
2016/03/05 Javascript
使用jquery.form.js实现图片上传的方法
2016/05/05 Javascript
vue2.0开发实践总结之入门篇
2016/12/06 Javascript
JS使用正则截取两个字符串之间的字符串实现方法详解
2017/01/06 Javascript
ExtJs的Ext.Ajax.request实现waitMsg等待提示效果
2017/06/14 Javascript
jsonp跨域获取百度联想词的方法分析
2019/05/13 Javascript
详解基于 Node.js 的轻量级云函数功能实现
2019/07/08 Javascript
Nuxt使用Vuex的方法示例
2019/09/06 Javascript
跟老齐学Python之list和str比较
2014/09/20 Python
Python中比较特别的除法运算和幂运算介绍
2015/04/05 Python
Python 常用的安装Module方式汇总
2017/05/06 Python
python3学习之Splash的安装与实例教程
2018/07/09 Python
森海塞尔美国官网:Sennheiser耳机与耳麦
2017/07/19 全球购物
End Clothing美国站:英国男士潮牌商城
2018/04/20 全球购物
销售自我评价
2013/10/22 职场文书
中专三年学习的个人自我评价
2013/12/12 职场文书
社区国庆节活动方案
2014/02/05 职场文书
企业管理毕业生求职信
2014/03/11 职场文书
法律进学校实施方案
2014/03/15 职场文书
《音乐之都维也纳》教学反思
2014/04/16 职场文书
施工安全承诺书
2014/05/22 职场文书
企业法人代表任命书
2014/06/06 职场文书
竞选班干部演讲稿500字
2014/08/20 职场文书
JavaWeb 入门篇(3)ServletContext 详解 具体应用
2021/07/16 Java/Android
Smart 2 车辆代号 HC11 全新谍照曝光
2022/04/21 数码科技