基于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 相关文章推荐
javascript的onchange事件与jQuery的change()方法比较
Sep 28 Javascript
Jquery选择子控件"大于号"和" "区别介绍及使用示例
Jun 25 Javascript
javascript限制文本框输入值类型的方法
May 07 Javascript
JavaScript实现审核流程状态的动态显示进度条
Mar 15 Javascript
整理关于Bootstrap导航的慕课笔记
Mar 29 Javascript
实现微信小程序的wxml文件和wxss文件在webstrom的支持
Jun 12 Javascript
jQuery+ajax实现修改密码验证功能实例详解
Jul 06 jQuery
在Js页面通过POST传递参数跳转到新页面详解
Aug 25 Javascript
ES6中的Promise代码详解
Oct 09 Javascript
js实现一个简易计算器
Mar 30 Javascript
vue封装swiper代码实例解析
Oct 08 Javascript
如何在postman中添加cookie信息步骤解析
Jun 30 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的日期与时间函数技巧
2008/04/24 PHP
php教程 插件机制在PHP中实现方案
2012/11/02 PHP
php将日期格式转换成xx天前的格式
2015/04/16 PHP
jQuery结合Json提交数据到Webservice,并接收从Webservice返回的Json数据
2011/02/18 Javascript
jquery 利用show和hidden实现级联菜单示例代码
2013/08/09 Javascript
jquery弹出层类代码分享
2013/12/27 Javascript
js正则表达exec与match的区别说明
2014/01/29 Javascript
JQuery实现带排序功能的权限选择实例
2015/05/18 Javascript
Nodejs抓取html页面内容(推荐)
2016/08/11 NodeJs
vue-quill-editor实现图片上传功能
2017/08/08 Javascript
微信小程序录音与播放录音功能
2017/12/25 Javascript
从parcel.js打包出错到选择nvm的全部过程
2018/01/23 Javascript
使用 vue-i18n 切换中英文效果
2018/05/23 Javascript
Javascript实现异步编程的过程
2018/06/18 Javascript
WebSocket的简单介绍及应用
2019/05/23 Javascript
微信小程序基于高德地图查找位置并显示文字
2019/10/30 Javascript
react antd表格中渲染一张或多张图片的实例
2020/10/28 Javascript
vue 实现element-ui中的加载中状态
2020/11/11 Javascript
[01:18:36]LGD vs VP Supermajor 败者组决赛 BO3 第一场 6.10
2018/07/04 DOTA
Python Web框架Flask信号机制(signals)介绍
2015/01/01 Python
numpy使用fromstring创建矩阵的实例
2018/06/15 Python
Python初学者需要注意的事项小结(python2与python3)
2018/09/26 Python
Python字节单位转换实例
2019/12/05 Python
详解有关PyCharm安装库失败的问题的解决方法
2020/02/02 Python
基于TensorFlow中自定义梯度的2种方式
2020/02/04 Python
tensorflow的ckpt及pb模型持久化方式及转化详解
2020/02/12 Python
CSS3盒子模型详解
2013/04/24 HTML / CSS
毕业生精彩的自我评价分享
2013/10/06 职场文书
入党积极分子思想汇报范文
2014/01/05 职场文书
村干部群众路线教育活动对照检查材料
2014/10/01 职场文书
清明节扫墓活动总结
2015/02/09 职场文书
辞职信范文大全
2015/03/02 职场文书
消防宣传标语大全
2015/08/03 职场文书
公司客户答谢酒会祝酒词
2015/08/11 职场文书
SpringBoot整合minio快速入门教程(代码示例)
2022/04/03 Java/Android
Vue.Draggable实现交换位置
2022/04/07 Vue.js