MG——基于的模块浏览器端延迟请求加载
MG
MG,Module Generation,模块时代。以Sea.js为基础,构建遵循CMD规范的模块。 解决两个问题:
- 解决模板中对脚本随意引用而引起的复和杂问题,实现解耦;
- 将脚本依赖从模板中迁移到脚本中,更接近使用的地方,实现内聚。
客户端延迟请求
页面中,大多数脚本处于等待使用的状态,这部分脚本完全可以按需加载,将依赖分析后移到浏览器端业务执行时,基于Sea.js实现客户端延迟请求解决方案。
页面加载完成之后,基于HTTP 1.1协议中的
和浏览器的并发加载,是否真的会比全部合并加载快。1
Connection: keep-alive
HTTP 2.0协议普及之后,combo的过程都可以省略,文件的加载将不是问题。
基础
(1
$header
类的全局单例)和1
HeaderLite
(1
$footer
类的全局单例)中的1
FooterLite
和1
importJavascript
两个静态资源引用方法会自动合并并更新资源的版本号(1
importCss
),用这两个方法引用的静态资源不用关心CDN缓存的问题。1
?ver=最新版本号
Header中的关键代码
1
2
3
4
5
6
$header->importJavascript('/img/mg/dist/lib/seajs/2.3.0/sea.js');
$header->importJavascript('/img/mg/dist/lib/seajs-preload/1.0.0/seajs-preload.js');
$header->importJavascript('/img/mg/dist/lib/seajs-css/1.0.4/seajs-css.js');
$header->importJavascript('/img/mg/dist/lib/seajs-combo/1.1.2/seajs-combo.js');
$header->importJavascript('/img/mg/dist/lib/seajs-flush/1.0.1/seajs-flush.js');
$header->importJavascript('/img/mg/dist/config.js');
Footer中的关键代码
1
seajs.flush();
JS模块代码进行Transport处理时,会自动为模块中依赖的JS脚本添加hash版本号解决CND缓存的问题。
页面中以模块为基本逻辑和代码组织单位,在单独的模块中引用对应的seajs_config.js入口配置文件,一个页面中可以多次引用,Sea.js会自动合并配置。
目的:提升使用的快感,解决无法编译的问题。
1
2
3
4
5
6
<?php
$footer->importJavaScript('/img/mg/dist/project/common/js/seajs_config.js');
?>
<script>
seajs.use('header');
</script>
页面中需要引入的JS文件
在页面的头部中共需要引入如下6个JS文件,前5个是Sea.js的基本文件。config.js是全局配置文件。
1
2
3
4
5
6
'lib/seajs/2.3.0/sea.js';
'lib/seajs-preload/1.0.0/seajs-preload.js';
'lib/seajs-css/1.0.4/seajs-css.js';
'lib/seajs-combo/1.1.2/seajs-combo.js';
'lib/seajs-flush/1.0.1/seajs-flush.js';
'config.js';
全局配置文件config.js详细
全局配置文件的作用共4个:
- 基于版本号统一管理Lib库中引用的第三方资源,当第三方资源更新时,只需要更新配置文件中的版本号,重新编译Lib库和config.js配置文件并上线即可在业务代码中生效;
- 设置统一的debug开关,当URL中出现dev参数时,即可调用debug版本的js;
- 设置模板后缀名映射;
- combo合并请求配置参数设置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
(function (seajs, location) {
'use strict';
var alias = {
'jquery': 'lib/jquery/1.11.2/jquery',
'hogan': 'lib/hogan/3.0.2/hogan'
},
map = [
[/\.tpl$/, '.tpl.js']
];
/*
* 匹配以下形式
* ?dev
* ?dev=***
* &dev
* &dev=
* 不匹配以下形式
* ?dev****
* &dev****
*/
if (/(?:\?|\&)dev(?:=|&|$)/.test(location.href)) {
map.push([/\-debug\.js$|\.js$/, '-debug.js']);
}
seajs.config({
alias: alias,
map: map,
comboSyntax: ['??/img/mg/dist/', ',/img/mg/dist/'],
comboBase: seajs.data.base
});
}(this.seajs, this.location));
第三方资源Lib管理
Lib目录结构设计
Lib库编译
Lib库中引用的第三方JS共有两类,一是Sea.js相关文件,只进行Uglify压缩处理;二是jQuery、Hogan等第三方库,引入源码文件并手工修改为CMD格式,随后按如下流程处理。
主要处理流程如下:
- SeaJs文件Uglify压缩;
- 第三方库CSS文件压缩;
- 第三方库JS文件Transport;
- 第三方库JS文件拷贝Debug版本;
- 第三方库JS文件Uglify压缩。
针对项目CSS编译
每个页面只引用1个CSS文件,CSS的依赖通过Less的
解决。1
@import
主要处理流程如下:
- Less文件预处理;
- CSSLint;
- ICON图片合并;
- 图片文件Hash化;
- 图片路径转换(符合静态资源部署规则);
- CSS文件压缩。
针对项目JS编译
JS目录的组织,每个业务或功能模块分别建立单独的文件夹,文件夹中以main.js为其入口文件,并以该文件夹名为启动入口名。
主要处理流程如下:
- 代码质量检查(JsLint,出现错误立刻中止);
- JS文件Transport;
- JS文件拷贝Debug版本;
- JS文件Uglify压缩;
- 生成模块入口配置文件(
)。1
seajs_config.js
生成的seajs_config.js文件示例
该文件的作用是避免模块入口启动文件的CND缓存问题。
1
!function(a,b,c){b.config({alias:{"activity-detail":"project/trials-m/js/activity-detail/main-4924f514","activity":"project/trials-m/js/activity/main-edcaa876","address":"project/trials-m/js/address/main-c13c8fd9","apply-detail":"project/trials-m/js/apply-detail/main-995383a0","attr":"project/trials-m/js/attr/main-91c9a520","comment":"project/trials-m/js/comment/main-e68e2a37","index":"project/trials-m/js/index/main-1bccee4f","report":"project/trials-m/js/report/main-72bdd139","reportlist":"project/trials-m/js/reportlist/main-30f4f51c","rule":"project/trials-m/js/rule/main-911e02e7","search":"project/trials-m/js/search/main-1323a6f8","settitle":"project/trials-m/js/settitle/main-6531f08a","survey":"project/trials-m/js/survey/main-6b945589","unlist":"project/trials-m/js/unlist/main-96ff2afe"}})}(this,this.seajs,this.bui);
目前存在的问题
- 文件编译的性能问题;
- 入口文件名标识容易冲突的问题;
- 可以增加以单个JS文件为粒度的客户端持久化缓存;
- Sea.js的CMD不符合国际事实,Require.js的AMD更友好,或者找到更好的方案;
- gulp的流模式比Grunt的配置在工程化上更有优势;
- 将开发开发构建和生产环境构建分离;
- JS、CSS和图片等静态资源和HTTP/2的兼容;
- 图片的优化处理(gulp方案中存在);
- NPM管理第三方库资源;
- 按正宗的CommonJS方案去写代码;
- Babel和ES6的使用;
- 肯定还有很多其他问题,需要大家一起携手搞定。