基于gulp合并压缩Seajs模块的方式说明


Posted in Javascript onJune 14, 2016

之前的项目一直采用grunt来构建,然后用requirejs做模块化,requirejs官方有提供grunt的插件来做压缩合并。现在的项目切到了gulp,模块化用起了seajs,自然而然地也想到了模块合并压缩的问题。

然后一开始在解决这个问题的时候,并不是很顺利,在npm上并没有那种特别流行的专门用来做seajs合并压缩的gulp插件,虽然在seajs的github上也看了不少的issue,但是大多数都是只能将所有的模块文件合并成一个总的文件,这对于单页面的应用来说肯定没有问题,但是对于多页面的应用而言,显然就违背了模块化思想中按需加载的核心,所以我想要的是一个能够根据我每个页面各自所依赖的模块来按需合并的方法。

这个按需合并的意思,一方面是只合并一个页面所依赖的那些模块,另一方面是,还能过滤掉某些模块不参与合并,考虑这个的原因在于有些模块,比如jquery等,都属于第三方依赖的库,可能文件比较大,最重要的是你几乎不会去改动它的代码,所以这些模块不合并到页面的js中,会有助于更好地利用浏览器缓存。本文介绍一个简单可行的办法,来做基于gulp构建的中小型项目中的seajs合并压缩。

注:为了说明,seajs合并后的效果,本文提供了一个演示demo,它有两个页面:login.html和regist.html,分别用来模拟多页应用中的两个独立的文件,可通过以下链接来查看:

http://liuyunzhuge.github.io/blog/seajs/dist/html/login.html

http://liuyunzhuge.github.io/blog/seajs/dist/html/regist.html

以login.html为例,查看这个页面的源文件中,会看到它除了引用seajs以及相关的配置文件common.js外,只引用了app/login作为页面的main js,这个app/login模块其实对应的就是js/app/login.js:

基于gulp合并压缩Seajs模块的方式说明

但实际上,这个login.js依赖了更多的模块js,你可以通过chrome的soures来查看该页面加载的详细js资源:

基于gulp合并压缩Seajs模块的方式说明

基于gulp合并压缩Seajs模块的方式说明

在login.js合并之前,它的代码是这样的:

基于gulp合并压缩Seajs模块的方式说明

但是在前2个截图中,我们并没有看到mod/mod1.js , mod/mod2.js , deps/fastclick.js这三个文件,我们除了看到login.js,还看到了lib/bootstrap.js  , lib/jquery.js , lib/jquery.validate.js。这就是合并的效果。一方面保持了js/lib文件夹下的模块都不会参与合并,另一方面保证了页面的main js所依赖的其它模块,都合并到页面的main js文件中来。

该demo相关的代码可通过以下链接进行查看:

https://github.com/liuyunzhuge/blog/tree/master/seajs

1. 合并思路

其实方法还算比较简单,我最后再介绍。

1)我先说下自己对seajs的模块进行组织的一种文件夹结构,它是这样的:

基于gulp合并压缩Seajs模块的方式说明

这个结构借鉴于requirejs,尽量让文件组织扁平化,对于中小型前端项目来说,应该不会太麻烦。其中各个文件夹的作用是:

1)js/app 存放各个页面的main js,基本上是一个页面一个js的逻辑

2)js/deps 存放哪些需要被合并到main js的第三方模块

3)js/lib 存放哪些不需要参与合并的第三方模块

4)js/mod 存放各个项目中自己写的一些js模块

5)common.js 是seajs的配置文件。

2)在common.js中把js/lib下的模块都配置到了alias选项里面,因为这些js都不参与合并,需要使用到浏览器缓存,alias可以方便我们在修改或升级了js/lib下的文件的时候,对这些文件的加载地址做一点更新:

基于gulp合并压缩Seajs模块的方式说明

base配置到了js文件夹。在模块开发中,要require其他模块时,我的习惯都是直接写mod/mod1这样的模块标识,不用相对标识,即使要定义的这个模块所依赖的模块跟它存在于同一个文件夹中,这也是我为啥把base目录设置到js文件夹的原因,有点类似站点根目录的感觉。

3)合并的思路:主要是利用gulp-seajs-transport和gulp-seajs-concat这两个gulp插件。虽然它们在github上不是很热门,但是已经很好地解决我的问题了,使用起来也非常简单:

基于gulp合并压缩Seajs模块的方式说明

(更多内容需要查看本文开始处提供的源码链接,找到相关的gulpfile.js文件)

gulp-seajs-transport可以帮助你把seajs的模块文件从匿名模块,变成具名模块。比如js/mod/mod1.js在构建前是这样的:

基于gulp合并压缩Seajs模块的方式说明

但是经过transport处理后就会变成:

基于gulp合并压缩Seajs模块的方式说明

这个是seajs合并工作中比较关键的一点,它不像requirejs,直接做concat即可;它必须先经过一个transport的任务处理,将匿名模块变成具名模块,同时用define的第二个参数来描述这个模块的所有依赖,就像requirejs那样。只有做完了transport,才能利用gulp-seajs-concat做合并。原因请参考:https://github.com/seajs/seajs/issues/426。

gulp-seajs-concat做合并的时候,就很简单了,只要告诉它一个base选项即可,这个base选项跟js/common.js中base选项保持一致。因为gulp-seajs-concat根据base和transport之后的模块,就能找到它所依赖的其它模块文件。

4)页面中使用main js时要采用这种方式:

use的参数名称,必须跟合并之后的main js的主模块ID保持一致。比如js/app/login.js合并之后是这个样子:

基于gulp合并压缩Seajs模块的方式说明

第一个define对应的模块就是合并后文件内的主模块,红框的内容就是该主模块的id,seajs use这个模块的时候,参数名称必须和这个id一致。否则seajs即使成功的加载到了这个文件,也不会执行任何模块内的代码。因为seajs有一个规则:ID 和路径匹配原则,其中有点跟这个相关,就是:当seajs use到一个文件内包含多个模块时,会根据use的参数名来寻找这个文件内的主模块,只有它们完全匹配,才能找得到。

5)压缩混淆:使用gulp-uglify:

基于gulp合并压缩Seajs模块的方式说明

但是要注意那个mangle,必须把require exports module排除掉,否则会引发一些意外的问题。

2. 本文小结

本文内容虽然很简单,但是在刚切到gulp和seajs的时候,还是费了不少时间才把本文的问题解决,虽然在准备demo的时候进展地比我当时的情况要顺利的多…不管怎么样,希望本文的内容多多少少能帮助到一些朋友。

Javascript 相关文章推荐
JsEasy简介 JsEasy是什么?与下载
Mar 07 Javascript
jQuery live
May 15 Javascript
jQuery的实现原理的模拟代码 -4 重要的扩展函数 extend
Aug 03 Javascript
javascript各浏览器中option元素的表现差异
Apr 07 Javascript
jQuery语法总结和注意事项小结
Nov 11 Javascript
基于canvas实现的钟摆效果完整实例
Jan 26 Javascript
微信jssdk在iframe页面失效问题的解决措施
Mar 03 Javascript
微信小程序 setData的使用方法详解
Apr 20 Javascript
React中的render何时执行过程
Apr 13 Javascript
vuejs实现ready函数加载完之后执行某个函数的方法
Aug 31 Javascript
微信小程序 腾讯地图SDK 获取当前地址实现解析
Aug 12 Javascript
javascript设计模式 ? 原型模式原理与应用实例分析
Apr 10 Javascript
JS去除空格和换行的正则表达式(推荐)
Jun 14 #Javascript
javascript用正则表达式过滤空格的实现代码
Jun 14 #Javascript
三种带箭头提示框总结实例
Jun 14 #Javascript
js判断输入字符串是否为空、空格、null的方法总结
Jun 14 #Javascript
简单实现的JQuery文本框水印插件
Jun 14 #Javascript
JS不用正则验证输入的字符串是否为空(包含空格)的实现代码
Jun 14 #Javascript
浅析jQuery 3.0中的Data
Jun 14 #Javascript
You might like
服务器端解压缩zip的脚本
2006/12/22 PHP
来自phpguru得Php Cache类源码
2010/04/15 PHP
适用于php-5.2 的 php.ini 中文版[金步国翻译]
2011/04/17 PHP
PHP实现在线阅读PDF文件的方法
2015/06/23 PHP
Linux系统下PHP-FPM的安装和配置教程
2015/08/17 PHP
PHP基于反射机制实现插件的可插拔设计详解
2016/11/10 PHP
PHP错误处理函数register_shutdown_function使用示例
2017/07/03 PHP
PHP删除数组中指定值的元素常用方法实例分析【4种方法】
2018/08/21 PHP
PHP如何通过表单直接提交大文件详解
2019/01/08 PHP
PHP实现支持CURL字符串证书传输的方法
2019/03/23 PHP
js 延迟加载 改变JS的位置加快网页加载速度
2012/12/11 Javascript
浅析jQuery(function(){})与(function(){})(jQuery)之间的区别
2014/01/09 Javascript
js实现弹出窗口、页面变成灰色并不可操作的例子分享
2014/05/10 Javascript
jQuery中:first-child选择器用法实例
2014/12/31 Javascript
异步安全加载javascript文件的方法
2015/07/21 Javascript
js实现动态加载脚本的方法实例汇总
2015/11/02 Javascript
JS实现Select的option上下移动的方法
2016/03/01 Javascript
vue webuploader 文件上传组件开发
2017/09/23 Javascript
vue2.0父子组件间传递数据的方法
2018/08/16 Javascript
vue element table 表格请求后台排序的方法
2018/09/28 Javascript
Vue中实现权限控制的方法示例
2019/06/07 Javascript
vue动态配置模板 'component is'代码
2019/07/04 Javascript
解决vue.js提交数组时出现数组下标的问题
2019/11/05 Javascript
Vue中通过属性绑定为元素绑定style行内样式的实例代码
2020/04/30 Javascript
原生js实现分页效果
2020/09/23 Javascript
Python 修改列表中的元素方法
2018/06/26 Python
Python3搭建http服务器的实现代码
2020/02/11 Python
python图片剪裁代码(图片按四个点坐标剪裁)
2020/03/10 Python
学会迭代器设计模式,帮你大幅提升python性能
2021/01/03 Python
实例讲解CSS3中Transform的perspective属性的用法
2016/04/22 HTML / CSS
英国123鲜花网站:123 Flowers
2019/07/07 全球购物
国际残疾人日广播稿范文
2014/10/09 职场文书
爱护环境卫生倡议书
2015/04/29 职场文书
公务员保密工作承诺书
2015/05/04 职场文书
my.ini优化mysql数据库性能的十个参数(推荐)
2021/05/26 MySQL
go select编译期的优化处理逻辑使用场景分析
2021/06/28 Golang