详解使用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 相关文章推荐
jQuery autocomplate 自扩展插件、自动完成示例代码
Mar 28 Javascript
详解jQuery插件开发中的extend方法
Nov 19 Javascript
jQuery获得IE版本不准确webbrowser的解决方法
Feb 23 Javascript
Javascript中实现String.startsWith和endsWith方法
Jun 10 Javascript
javascript正则表达式定义(语法)总结
Jan 08 Javascript
使用jQuery调用XML实现无刷新即时聊天
Aug 07 Javascript
JavaScript“尽快失败”的原则实例详解
Oct 08 Javascript
js中删除数组中的某一元素实例(无下标时)
Feb 28 Javascript
Vue.js结合bootstrap实现分页控件
Mar 10 Javascript
JavaScript实现的简单Tab点击切换功能示例
Jul 06 Javascript
ES6 Array常用扩展的应用实例分析
Jun 26 Javascript
JS如何在不同平台实现多语言方式
Jul 16 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 程序员也要学会使用“异常”
2009/06/16 PHP
php 浮点数比较方法详解
2017/05/05 PHP
Laravel使用scout集成elasticsearch做全文搜索的实现方法
2018/11/30 PHP
thinkPHP5使用Rabc实现权限管理
2019/08/28 PHP
常见的5个PHP编码小陋习以及优化实例讲解
2021/02/27 PHP
javascript 面向对象全新理练之原型继承
2009/12/03 Javascript
用Javascript实现Sleep暂停功能代码
2010/09/03 Javascript
前端开发的开始---基于面向对象的Ajax类
2010/09/17 Javascript
javascript设计模式 封装和信息隐藏(上)
2012/07/24 Javascript
js写的评论分页(还不错)
2013/12/23 Javascript
nodejs通过phantomjs实现下载网页
2015/05/04 NodeJs
基于jquery fly插件实现加入购物车抛物线动画效果
2016/04/05 Javascript
论Bootstrap3和Foundation5网格系统的异同
2016/05/16 Javascript
引用jquery框架后出错的解决方法
2016/08/09 Javascript
angularjs实现猜数字大小功能
2020/05/20 Javascript
vue-cli脚手架引入图片的几种方法总结
2018/03/13 Javascript
使用JavaScript中的lodash编写双色球效果
2018/06/24 Javascript
JavaScript 对引擎、运行时、调用堆栈的概述理解
2018/10/22 Javascript
js实现html滑动图片拼图验证
2020/06/24 Javascript
js面试题之异步问题的深入理解
2020/09/20 Javascript
[47:39]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 LGD vs OPTIC
2018/03/31 DOTA
python pandas dataframe 按列或者按行合并的方法
2018/04/12 Python
pandas系列之DataFrame 行列数据筛选实例
2018/04/12 Python
每天迁移MySQL历史数据到历史库Python脚本
2018/04/13 Python
python Pillow图像处理方法汇总
2019/10/16 Python
Python中six模块基础用法
2019/12/08 Python
Python如何基于smtplib发不同格式的邮件
2019/12/30 Python
如何基于python实现画不同品种的樱花树
2020/01/03 Python
Django 解决新建表删除后无法重新创建等问题
2020/05/21 Python
python线程里哪种模块比较适合
2020/08/02 Python
海信商城:海信电视、科龙空调、容声冰箱官方专卖
2017/02/07 全球购物
连锁经营管理专业大学生求职信
2013/10/30 职场文书
毕业生自我鉴定
2013/12/04 职场文书
小学教师事迹材料
2014/01/13 职场文书
计算机网络及管理学专业求职信
2014/06/05 职场文书
电话客服工作职责
2014/07/27 职场文书