h2y / inspirations

采用 Issues 维护的个人灵感仓库,记录和讨论一些灵光一闪的点子。
https://github.com/h2y/inspirations/issues/created_by/h2y
7 stars 0 forks source link

前端资源载入工具 #9

Closed h2y closed 7 years ago

h2y commented 7 years ago

应用场景

在一个大型单页 Web App 中,不同的地方会使用一些特别的 JS 库来实现。比如,在点击应用中的 “导入 Excel” 按钮时,需要使用库 js-xlsx 来读取文件。

按照常理,我们需要在 <head> 中加入这个 js 文件的 <script> 标签,然而,在大型 Web App 中,“导入” 只是其中的一个功能,如果要把所有功能用到的所有依赖库都写到 <head> 中,将非常的臃肿,大大影响首屏加载速度。

目的

仅仅在需要的时候将需要的 js 库文件导入到浏览器运行环境中,自动处理依赖关系,也不会重复添加已添加过的依赖库。

h2y commented 7 years ago

在我的 XSYU-GMS 项目中,我已经简单实现了一个这样的轮子,取名为 Nsert,用法大概是这样的:

$.nsert(['js-xlsx', 'chart-JS'], function(){
    // code there
})

有时间会将其完善并发布。

h2y commented 7 years ago

与其他加载器的区别

这个库与 AMD 等加载器不同之处在于,AMD 要求被加载的代码通过 AMD 规范进行过 define,定义了一段代码暴露出的接口,以及依赖的其他模块。但是,并不是所有的第三方代码都进行了 AMD 声明。

Nsert 是一个通用的加载器,将任何的 JS 库按需加载到页面中。

下面是 API 设计

向全局暴露两个方法:NsertNsert_register

Nsert_register

用于注册一个模块的相关信息

Nsert_register(String mod_name, Object mod_config);

mod_config 写法:

{
    target: 'https://cdn.com/jq.min.js', 
    //必须。可以为链接也可以为相对地址

    require: 'anthor_mod_name', 
    //可选。依赖的其他模块的名字,可以为字符串、数组或对象,分别代表依赖单个模块、按指定加载顺序依赖一组模块,以及不按加载顺序依赖一组模块

    added: false,
    //可选,默认为 false。标记这个模块是否已被添加至浏览器,这决定着 Nsert 会不会重复加载该模块

    exports: ['$', 'jQuery'],
    //可选。模块向顶层暴露的接口。如果定义了该设置,Nsert 会拦截这些接口,在调用的时候用参数的方式供用户使用

    callback: function($, jQuery){},
    //可选。加载完这个模块后调用的一个回调函数,可用来对工具库进行相关配置

    kind: 'js'
    //可选,默认为 'js'。模块类型,Nsert 在以后将会支持更多类型模块的加载
}

Nsert

用于调用一个模块

Nsert(Mixed mod_name, Function? callback)

mod_name

需要调用的模块名,已通过 Nsert_register 注册。

可以为字符串、数组或对象,分别代表依赖单个模块、按指定加载顺序依赖一组模块,以及不按加载顺序依赖一组模块。

推荐在 Nsert_register 中对数组或对象再进行一次封装,为一个独立的模块后再使用 Nsert 单独调用。

callback

可选。调用完成后执行的代码。

如果调用的模块设定了 exports 属性,则将 exports 的对象依次作为参数传递给 callback。

mod_name 为数组或对象时,调用了多个模块,所以不会传递 exports 对应的参数!

h2y commented 7 years ago

使用 RequireJS + RequireCSS 可以达到目的。

没必要我重复造轮子了。

const bootcdn = 'https://cdn.bootcss.com/',
      bower = '../../bower_components/';

require.config({
    paths: {
        jquery: bootcdn+"jquery/3.1.1/jquery.min",
        bootstrap: bootcdn+'bootstrap/4.0.0-alpha.3/js/bootstrap.min'
    },
    shim: {
        bootstrap: ['jquery', 'css!'+bootcdn+'bootstrap/4.0.0-alpha.3/css/bootstrap.min']
    },
    map: {
      '*': {
        'css': bower+'require-css/css.min'
      }
    }
});

seaJS 在内部采用正则替换,有一些隐坑。

而 Webpack 原生不支持 require 来自 http:// 的资源,不满足我的要求。