基于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 相关文章推荐
一个JS翻页效果
Jul 23 Javascript
qq悬浮代码(兼容各个浏览器)
Jan 29 Javascript
javascript将浮点数转换成整数的三个方法
Jun 23 Javascript
JavaScript数据结构与算法之集合(Set)
Jan 29 Javascript
JavaScript笔记之数据属性和存储器属性
Mar 31 Javascript
JS判断日期格式是否合法的简单实例
Jul 11 Javascript
微信小程序 本地存储及登录页面处理实例详解
Jan 11 Javascript
angular forEach方法遍历源码解读
Jan 25 Javascript
使用gulp搭建本地服务器并实现模拟ajax
Apr 05 Javascript
微信小程序实现滑动删除效果
May 19 Javascript
如何让node运行es6模块文件及其原理详解
Dec 11 Javascript
vue 中Virtual Dom被创建的方法
Apr 15 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
PHP 截取字符串专题集合
2010/08/19 PHP
PHP错误Parse error: syntax error, unexpected end of file in test.php on line 12解决方法
2014/06/23 PHP
2个比较经典的PHP加密解密函数分享
2014/07/01 PHP
php生成固定长度纯数字编码的方法
2015/07/09 PHP
PHP面向对象程序设计高级特性详解(接口,继承,抽象类,析构,克隆等)
2016/12/02 PHP
PHP基于简单递归函数求一个数阶乘的方法示例
2017/04/26 PHP
javascript 关闭IE6、IE7
2009/06/01 Javascript
24款非常有用的 jQuery 插件分享
2011/04/06 Javascript
关于全局变量和局部变量的那些事
2013/01/11 Javascript
使用jquery动态加载Js文件和Css文件
2015/10/24 Javascript
js阻止浏览器默认行为触发的通用方法(推荐)
2016/05/15 Javascript
jQuery遍历DOM的父级元素、子级元素和同级元素的方法总结
2016/07/07 Javascript
详解angular用$sce服务来过滤HTML标签
2017/04/11 Javascript
js使用原型对象(prototype)需要注意的地方
2017/08/28 Javascript
Thinkphp5微信小程序获取用户信息接口的实例详解
2017/09/26 Javascript
利用nodeJs anywhere搭建本地服务器环境的方法
2018/05/12 NodeJs
Python实现二叉树结构与进行二叉树遍历的方法详解
2016/05/24 Python
python退出命令是什么?详解python退出方法
2018/12/10 Python
Django admin禁用编辑链接和添加删除操作详解
2019/11/15 Python
Python使用urlretrieve实现直接远程下载图片的示例代码
2020/08/17 Python
关于多种方式完美解决Python pip命令下载第三方库的问题
2020/12/21 Python
移动端HTML5 input常见问题(小结)
2020/09/28 HTML / CSS
新加坡航空官方网站:Singapore Airlines
2016/10/13 全球购物
Move Free官方海外旗舰店:美国骨关节健康专业品牌
2017/12/06 全球购物
音乐学院硕士生的自我评价分享
2013/11/01 职场文书
文科生自我鉴定
2014/02/15 职场文书
供应链金融服务方案
2014/05/25 职场文书
关于工作经历的证明书
2014/10/11 职场文书
2014年党员发展工作总结
2014/12/02 职场文书
运动会宣传语
2015/07/13 职场文书
个人工作决心书
2015/09/22 职场文书
先进个人主要事迹范文
2015/11/04 职场文书
小学班主任心得体会
2016/01/07 职场文书
Golang 获取文件md5校验的方法以及效率对比
2021/05/08 Golang
React 并发功能体验(前端的并发模式)
2021/07/01 Javascript
MySQL实现用逗号进行拼接、以逗号进行分割
2022/12/24 MySQL