MG

MG,Module Generation,模块时代。以Sea.js为基础,构建遵循CMD规范的模块。 解决两个问题:

  1. 解决模板中对脚本随意引用而引起的复和杂问题,实现解耦;
  2. 将脚本依赖从模板中迁移到脚本中,更接近使用的地方,实现内聚。

客户端延迟请求

页面中,大多数脚本处于等待使用的状态,这部分脚本完全可以按需加载,将依赖分析后移到浏览器端业务执行时,基于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
两个静态资源引用方法会自动合并并更新资源的版本号(
1
?ver=最新版本号
),用这两个方法引用的静态资源不用关心CDN缓存的问题。

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个:

  1. 基于版本号统一管理Lib库中引用的第三方资源,当第三方资源更新时,只需要更新配置文件中的版本号,重新编译Lib库和config.js配置文件并上线即可在业务代码中生效;
  2. 设置统一的debug开关,当URL中出现dev参数时,即可调用debug版本的js;
  3. 设置模板后缀名映射;
  4. 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库编译

Lib库中引用的第三方JS共有两类,一是Sea.js相关文件,只进行Uglify压缩处理;二是jQuery、Hogan等第三方库,引入源码文件并手工修改为CMD格式,随后按如下流程处理。

主要处理流程如下:

  1. SeaJs文件Uglify压缩;
  2. 第三方库CSS文件压缩;
  3. 第三方库JS文件Transport;
  4. 第三方库JS文件拷贝Debug版本;
  5. 第三方库JS文件Uglify压缩。

针对项目CSS编译

每个页面只引用1个CSS文件,CSS的依赖通过Less的

1
@import
解决。

CSS目录结构

主要处理流程如下:

  1. Less文件预处理;
  2. CSSLint;
  3. ICON图片合并;
  4. 图片文件Hash化;
  5. 图片路径转换(符合静态资源部署规则);
  6. CSS文件压缩。

针对项目JS编译

JS目录的组织,每个业务或功能模块分别建立单独的文件夹,文件夹中以main.js为其入口文件,并以该文件夹名为启动入口名。

JS目录结构

主要处理流程如下:

  1. 代码质量检查(JsLint,出现错误立刻中止);
  2. JS文件Transport;
  3. JS文件拷贝Debug版本;
  4. JS文件Uglify压缩;
  5. 生成模块入口配置文件(
    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);

目前存在的问题

  1. 文件编译的性能问题;
  2. 入口文件名标识容易冲突的问题;
  3. 可以增加以单个JS文件为粒度的客户端持久化缓存;
  4. Sea.js的CMD不符合国际事实,Require.js的AMD更友好,或者找到更好的方案;
  5. gulp的流模式比Grunt的配置在工程化上更有优势;
  6. 将开发开发构建和生产环境构建分离;
  7. JS、CSS和图片等静态资源和HTTP/2的兼容;
  8. 图片的优化处理(gulp方案中存在);
  9. NPM管理第三方库资源;
  10. 按正宗的CommonJS方案去写代码;
  11. Babel和ES6的使用;
  12. 肯定还有很多其他问题,需要大家一起携手搞定。