JavaScript拦截模块导入

JavaScript拦截模块导入,javascript,ecmascript-6,systemjs,es6-module-loader,Javascript,Ecmascript 6,Systemjs,Es6 Module Loader,我有一个SPA(在Aurelia/TypeScript中,但这不重要),它使用SystemJS。假设它在http://spa:5000/app 它有时会根据需要从外部URL(如waterservice/external.js)加载JavaScript模块http://otherhost:5002/fetchmodule?moduleId=waterservice.external.js。我使用SystemJS.import(url)来实现这一点,它工作得很好 但是当这个外部模块想要从'/othe

我有一个SPA(在Aurelia/TypeScript中,但这不重要),它使用SystemJS。假设它在
http://spa:5000/app

它有时会根据需要从外部URL(如
waterservice/external.js)加载JavaScript模块http://otherhost:5002/fetchmodule?moduleId=waterservice.external.js
。我使用
SystemJS.import(url)
来实现这一点,它工作得很好

但是当这个外部模块想要从'/other class'导入另一个具有简单的
import{OtherClass}的模块时这(可以理解)不起作用。当SPA加载时,它会查看
http://spa:5000/app/other-class.js
。在这种情况下,我必须截取路径/位置以将其重定向到
http://otherhost:5002/fetchmodule?moduleId=other-class.js

注意:
waterservice/external.ts
的Typescript编译可以找到,因为Typescript编译器可以轻松找到
/other class.ts
。显然,我不能使用绝对URL进行导入

如何在使用SystemJS导入的模块中拦截模块加载

我已经测试过的一种方法是在SystemJS配置中添加映射。如果我像从'other class'导入{OtherClass}一样导入它
并添加一个映射,如
“其他类”:http://otherhost:5002/fetchmodule?moduleId=other-类“
它可以工作。但如果这种方法很好,我如何在运行时动态添加映射

其他方法,如通用加载url拦截,也很受欢迎


更新

我试图按照artem的建议拦截SystemJS,如下所示

var systemLoader = SystemJS;
var defaultNormalize = systemLoader.normalize;
systemLoader.normalize = function(name, parentName) {
    console.error("Intercepting", name, parentName);
    return defaultNormalize(name, parentName);
}
这通常不会改变任何东西,但会产生一些控制台输出来查看发生了什么。不幸的是,这似乎改变了一些事情,因为我得到了一个错误Uncaught(在promise中)TypeError:this.has不是
system.js
中的函数

然后我尝试使用
SystemJS.config({map:…})添加映射。令人惊讶的是,这个函数是增量工作的,所以当我调用它时,它不会丢失已经提供的映射。所以我可以做到:

System.config({map: {
   "other-class": `http://otherhost:5002/fetchModule?moduleId=other-class.js`
}});
这不适用于相对路径(那些以
.
开头的路径),但如果我将共享路径放在根中,则可以解决此问题

我仍然希望拦截加载以便能够处理更多的场景,但目前我不知道在上述方法中缺少哪个
功能

如何在运行时动态添加映射

只需调用

SystemJS.config({ map: { additional-mappings-here ... }});
如果它对您不起作用,您可以重写loader.normalize,并在其中添加您自己的从模块ID到URL的映射。大致如下:

// assuming you have one global SystemJS instance
var loader = SystemJS;

var defaultNormalize = loader.normalize;
loader.normalize = function(name, parentName) {
    if (parentName == 'your-external-module' && name == 'your-external-submodule') {
        return Promise.resolve('your-submodule-url');
    } else {
        return defaultNormalize.call(loader, name, parentName);
    }
}
我不知道这是否适用于typescript。此外,您还必须弄清楚在您的案例中到底传递给loader.normalize的名称是什么


此外,如果您使用systemjs builder捆绑代码,则需要将该覆盖添加到builder使用的加载程序中(这完全是另一回事)。

由于公共假日,我现在没有时间考虑这一建议,但我会这样做。奖励奖金,否则就过期了。不过,我可能会带着问题回来;)谢谢你的洞察力。两次尝试我都更新了这个问题。你知道为什么截取
normalize
会在我的例子中产生错误吗?哦,对不起,我的错误-defaultNormalize需要
这个
参数:defaultNoramlize.call(loader,name,parentName);