黑马程序员技术交流社区

标题: requirejs的插件介绍与制作 [打印本页]

作者: 月亮是我掰弯的    时间: 2017-2-28 16:06
标题: requirejs的插件介绍与制作
requirejs的插件体系
requirejs的源码内部预留了hook,使得你可以创建插件来增强这个模块系统,并且这个插件可以做到影响到你的OPTIMIZER阶段,一些资源可以被处理为标准的AMD模块。
插件普遍被用来
example
比如它本身是不支持加载文本信息的,但是你可以通过text!插件来加载。
1
2
3
require(['text!foo.html', 'jquery'], function(foo, $){
        $('#anchor').html(foo);
})
需要注意的是由于文本无法用script标签进行加载,所以text内部是通过XHR来载入的,即它会受到同源策略的影响。
优化OPTIMIZER
由于requirejs同时提供工具(npm:requirejs)可以静态打包优化AMD,刚才的那个text!foo.html会同时被text插件转换为类似下面的AMD模块结构
1
2
3
define('text!foo.html',[],function () {
        return '<h2>早上好\n</h2>';
});
requirejs的插件其实是一个实现的特定接口的标准AMD模块,它在定义时与其它业务模块并无区别。
例如官方text插件的源文件
1
2
3
4
5
6
7
8
9

define(['module'], function (module) {
    'use strict';
    var text = {
            load: function(){}
            ....
    }
    return text
})
其中load等接口是插件必须实现的,
对于各个接口描述我就不细究了,大家可以参考官网
顺便列举一些有用的requirejs插件
其实由于amd等模块系统占据了开发中的模块入口这一环,其实在开发中可以有无限的可能性,这也是常规大公司都会自造一个轮子来最优配置的缘由之一,事实上requirejs目前的插件系统已经有足够的灵活性来定制自己的策略。
实现requirejs-regular的过程
背景
首先我们先理清我们的需求, 与常规的的模板预编译类似,我们的插件主要为了实现两个功能。
实现
一个插件模块会同时跑在浏览器端(开发环境)和node端(为线上或测试环境的打包优化工具),所以你的插件模块必须可以同时跑在浏览器端和node端,这个几乎是整个开发环境最麻烦的一部分
即插件会依赖这两个模块
1
2
3
4
5
6
7
define(['text', 'regular-parser'], function(text, parser){
        //blalalalala...
        return{
                load: load,
                write: write
        }
})
然后我们只需要实现两个接口:
1
2
3
4
5
6
7
8
9
var buildMap = {};

function load(name, req, onLoad, config){
    text.load(name, req, function(data,r){
        onLoad(
          (buildMap[name] = parser.parse(data, false))
        );
    }, config);
}
这里直接使用了text插件的纯文本加载,需要注意的是这个onLoad接口,传入参数相当于模块的内容,我们这里预parse了这段文本内容。即你通过rgl!template.html最终会获得解析后的AST数据。
其实对于regularjs来讲在浏览器端有无进行模块系统层面的预解析并无意义,关键是在打包优化阶段。这里的buildMap主要是为了保存这段内容用于打包使用。
write
实现write接口主要是为了在打包优化阶段改写相关模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var tpl = function(str, data){
    return str.replace(/\{\{(\w+)\}\}/g, function(all, name){
        return data[name] || ""
    })
}
var template ='define("{{pn}}!{{mn}}",function(){ return {{ast}} });\n';
function write(pn, mn, writeModule){
   if(buildMap[mn]){
       writeModule(
           tpl(template,{
               pn: pn,
               mn: mn,
               ast: parser.parse(buildMap[mn])
           })
       )
   }
}
此时这个插件必须依赖于两个模块,即必须同时保证text和regular-parser模块同时存在,类似的方案可以查看hogan,它必须保证环境中有hogan和text才可以运行. 熟悉requirejs打包过程的同学也知道,除了loader端的配置,我们在build的打包文件也需要一并将这些依赖模块剔除,因为上线时是不需要这些插件的。所以这将大大增加配置成本,其实解决方案也很简单,就是使用[webpack]再将其打包成一个standlone的AMD模块即可,具体可以参考这里的gulpfile
大功告成
使用就非常简单了,和你使用requirejs-text差不多,
1.首先下载rgl.js,最简单的就是bower安装
1
bower install regularjs-regular --save
save参数是安装后并写入到bower.json中,这个和npm一致
2.配置
1
2
3
4
5
6
7
require.config({
   paths : {
       "rgl": '../../bower_components/regularjs-regular/rgl'
       // 同时载入我们的regularjs来使用这些模板
       "regularjs": '../../bower_components/regularjs/dist/regular'
   }
});
3.使用
1
2
3
4
5
6
7
8
9
require(['rgl!./foo.html', 'regularjs'], function( tpl, Regular){

    var Foo = Regular.extend({
      template: tpl
    })

    new Foo({}).$inject("#app")

});
4.打包
模板文件<h2>{{message}}</h2>经过插件处理后会打包成
1
define("rgl!foo.html",function(){return [{"type":"element","tag":"h2","attrs":[],"children":[{"type":"expression","body":"_c_._sg_('message', _d_['message'])","constant":false,"setbody":"_c_._ss_('message',_p_,_d_, '=')"}]}] });
即上线后就不会有parse了,比如PO主目前正在开发的项目在初期就有几十个模板文件,build成单文件后的运行时开销还是应该尽量避免.
tip:build.js记得通过stubModules配置项目删除掉这个插件模块,具体看demo的build.js






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2