基于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 相关文章推荐
基于jquery的动态创建表格的插件
Apr 05 Javascript
Jsonp 跨域的原理以及Jquery的解决方案
Jun 27 Javascript
js实现拉伸拖动iframe的具体代码
Aug 03 Javascript
js实现图片拖动改变顺序附图
May 13 Javascript
js实现文本框中输入文字页面中div层同步获取文本框内容的方法
Mar 03 Javascript
基于jQuery实现弹出可关闭遮罩提示框实例代码
Jul 18 Javascript
使用Angular.js开发的注意事项
Oct 19 Javascript
详解JS对象封装的常用方式
Dec 30 Javascript
JavaScript轮播图简单制作方法
Feb 20 Javascript
微信小程序中form 表单提交和取值实例详解
Apr 20 Javascript
使用JavaScript实现alert的实例代码
Jul 06 Javascript
微信小程序抽奖组件的使用步骤
Jan 11 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
外媒评选出10支2020年最受欢迎的Dota2战队
2021/03/05 DOTA
PHP实现在线阅读PDF文件的方法
2015/06/17 PHP
laravel5.6框架操作数据curd写法(查询构建器)实例分析
2020/01/26 PHP
jQuery实现公告文字左右滚动的实例代码
2013/10/29 Javascript
jquery(hide方法)隐藏指定元素实例
2013/11/11 Javascript
JavaScript设置首页和收藏页面的小例子
2013/11/11 Javascript
jquery列表拖动排列(由项目提取相当好用)
2014/06/17 Javascript
javascript继承机制实例详解
2014/11/20 Javascript
浅谈jQuery中对象遍历.eq().first().last().slice()方法
2014/11/26 Javascript
node.js中的fs.createReadStream方法使用说明
2014/12/17 Javascript
纯css实现窗户玻璃雨滴逼真效果
2015/08/23 Javascript
简单实现JS对dom操作封装
2015/12/02 Javascript
JS设置下拉列表框当前所选值的方法
2015/12/22 Javascript
JS原型对象的创建方法详解
2016/06/16 Javascript
jQuery使用serialize()表单序列化时出现中文乱码问题的解决办法
2016/07/27 Javascript
jQuery中ajax错误调试分析
2016/12/01 Javascript
canvas知识总结
2017/01/25 Javascript
vue实现动态数据绑定
2017/04/28 Javascript
Vue开发中整合axios的文件整理
2017/04/29 Javascript
解决Linux无法正常安装与卸载Node.js的方法
2018/01/19 Javascript
解决Vue2.x父组件与子组件之间的双向绑定问题
2018/03/06 Javascript
node.js express框架简介与实现
2019/07/23 Javascript
JS操作json对象key、value的常用方法分析
2019/10/29 Javascript
javascript自定义右键菜单插件
2019/12/16 Javascript
理解Python中的With语句
2015/02/02 Python
python中模块查找的原理与方法详解
2017/08/11 Python
pygame游戏之旅 添加碰撞效果的方法
2018/11/20 Python
python利用多种方式来统计词频(单词个数)
2019/05/27 Python
VS2019+python3.7+opencv4.1+tensorflow1.13配置详解
2020/04/16 Python
深入了解Python 变量作用域
2020/07/24 Python
New Balance美国官网:运动鞋和健身服装
2017/04/11 全球购物
TripAdvisor西班牙官方网站:全球领先的旅游网站
2018/01/10 全球购物
迟到检讨书900字
2014/01/14 职场文书
医院安全生产月活动总结
2014/07/05 职场文书
纪念九一八爱国演讲稿600字
2014/09/14 职场文书
pytorch 运行一段时间后出现GPU OOM的问题
2021/06/02 Python