按需[延迟加载]模块的模式 [英] Pattern for [lazy-loading] modules on demand

查看:82
本文介绍了按需[延迟加载]模块的模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我不需要在初始化阶段加载模块(通过在./modules/modules中枚举它们),而是稍后根据某些条件(例如,用户授权结果)按需加载.想象一下,我想为用户A 提供计算器模块,为用户B 提供文本编辑器模块.

In my application I need to load modules not at the initialization stage (by enumerating them in ./modules/modules), but on demand later based on some condition (e.g. user authorization results). Imagine I want to provide User A with calculator module, and User B with text editor module.

为简单起见,我们以 boilerplatejs 示例应用程序为例,并假定将按需加载sampleModule1sampleModule2.

Let's take boilerplatejs example app for simplicity, and assume that sampleModule1 and sampleModule2 are to be loaded on demand.

所以我从 src \ modules \ modules.js 的初始加载顺序中删除了模块:

So I remove the modules from initial loading sequence in src\modules\modules.js:

    return [
        require('./baseModule/module'),
        /*require('./sampleModule1/module'),
        require('./sampleModule2/module')*/
    ];

并将控件添加到摘要页面( src \ modules \ baseModule \ landingPage \ view.html )以按需加载它们:

and add a control to summary page (src\modules\baseModule\landingPage\view.html) to load them on-demand:

<div>
    Congratulations! You are one step closer to creating your next large scale Javascript application!
</div>
<div>
    <select id="ModuleLoader">
        <option value="">Select module to load...</option>
        <option value="./modules/sampleModule1/module">sampleModule1</option>
        <option value="./modules/sampleModule2/module">sampleModule2</option>
    </select>
</div>

然后我修补 src \ modules \ baseModule \ module.js ,以将上下文传递给 LandingPageComponent (由于某种原因,它不在原始源代码中):

Then I patch src\modules\baseModule\module.js to pass context to the LandingPageComponent (for some reason it doesn't in the original source code):

        controller.addRoutes({
            "/" : new LandingPageComponent(context)
        });

,最后将加载代码添加到 src \ modules \ baseModule \ landingPage \ component.js :

and finally add the loading code to src\modules\baseModule\landingPage\component.js:

            $('#ModuleLoader').on('change', function(){
                require([this.value], function(mod){
                    moduleContext.loadChildContexts([mod]);
                    alert('Module enabled. Use can now use it.');
                });
            });

这似乎可行,但这是最好的方法吗?

This appears to be working, but is this the best way to do it?

它可以正确处理上下文加载吗?

Does it handle context loading properly?

如何防止两次加载同一模块?

How to protect against loading the same module twice?

推荐答案

这里的思路很聪明.最近几天,我也在努力改进BoilerplateJS以将模块作为插件延迟加载.我做了类似的事情,您可以在以下位置访问POC代码:

Smart thinking here.. I was too working on improving BoilerplateJS to lazy-load modules as plugins last few days. I did something similar, and u can access the POC code at:

https://github.com/hasith/boilerplatejs

在我所做的POC中,我试图同时实现延迟加载" +可配置ui".

In the POC I did, I'm trying to achieve 'lazy loading' + 'configurable ui' at the same time.

  • 每个屏幕(称为应用程序)是放置在布局上的组件(插件)的集合.这些应用程序定义只是一个JSON对象,可以从服务器API动态返回,也可以静态定义为JSON文件(就像在POC中一样).在POC中,应用程序定义存储在"/服务器/应用程序"中.

  • Each of the screen (called an application) is a collection of components (plugins) placed on to a layout. These application definitions are just a JSON object either dynamically returned from server API or statically defined as JSON files (as it is in the POC). In the POC, application definitions are stored at "/server/application".

现在可以按照约定动态调用这些应用程序.例如,"/##/shipping-app"将在"/server/application"中查找具有相同名称的应用程序定义.

These applications can be called dynamically by convention now. For example "/##/shipping-app" will look for an application definition with the same name at "/server/application".

应用程序加载是通过我在'/modules/baseModule/appShell'中拥有的新组件进行的.任何以"/##/"开头的内容都将被路由到该组件,然后它将尝试从/server/application"文件夹中按约定加载应用程序定义.

Application loading happens via a new component I have at '/modules/baseModule/appShell'. Anything staring with '/##/' will be routed to this component and then it will try to load the application definition by convention from "/server/application" folder.

当"appShell"接收到应用程序定义(作为JSON)时,它将尝试动态地加载其中定义的组件(插件).这些可插拔组件放置在"src/plugins"中,并且也将按照惯例加载.

When the 'appShell' receives the application definition (as a JSON), it will try to load the components (plugins) that are defined in it dynamically too. These pluggable components are placed in 'src/plugins' and will be loaded by convention too.

示例应用程序定义如下所示:

Sample application definition will look like below:

{
    "application-id" : "2434",
    "application-name" : "Order Application",
    "application-layout" : "dummy-layout.css",

    "components" : [    
        {
            "comp-name" : "OrderDetails",
            "layout-position" : "top-middle"
        },
        {
            "comp-name" : "ShippingDetails",
            "layout-position" : "bottom-middle"
        }
    ]

}

该方法的优点如下:

  • 应用程序界面是组件驱动的,可在运行时进行配置
  • 根据用户角色等(后端中的逻辑),可能会向用户发送不同的应用程序定义
  • 可以通过组合现有组件来即时创建应用程序
  • 由于加载是基于约定的,因此在框架"中无需更改静态代码即可添加新的应用程序或组件

这些都是非常初步的想法.感谢任何反馈!

These are very initial thoughts around. Appreciate any feedback !

这篇关于按需[延迟加载]模块的模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆