JavaScript拦截模块导入

Zoo*_*Way 12 javascript ecmascript-6 systemjs es6-module-loader

我有一个使用SystemJS的SPA(在Aurelia/TypeScript中,但这无关紧要).让我们说它运行于http://spa:5000/app.

它有时会像waterservice/external.js外部URL一样按需加载JavaScript模块http://otherhost:5002/fetchmodule?moduleId=waterservice.external.js.我用SystemJS.import(url)它做这个,它工作正常.

但是当这个外部模块想要导入另一个模块时,import { OtherClass } from './other-class';这个(可理解的)不起作用.当它被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配置中添加映​​射.如果我像它一样导入它import { OtherClass } from 'other-class';并添加一个像"other-class": "http://otherhost:5002/fetchmodule?moduleId=other-class"它一样的映射.但是如果这种方法很好,我怎样才能在运行时动态添加映射?

其他方法,如通用加载URL拦截也是受欢迎的.


更新

我尝试拦截SystemJS,就像这样的artem

var systemLoader = SystemJS;
var defaultNormalize = systemLoader.normalize;
systemLoader.normalize = function(name, parentName) {
    console.error("Intercepting", name, parentName);
    return defaultNormalize(name, parentName);
}
Run Code Online (Sandbox Code Playgroud)

这通常不会改变任何东西,只会产生一些控制台输出以查看正在发生的事情.不幸的是,这似乎改变了一些东西,因为我得到一个错误未捕获(在承诺中)TypeError:this.has不是一个函数内部system.js.

然后我尝试添加映射SystemJS.config({map: ...});.令人惊讶的是,这个函数是增量的,所以当我调用它时,它不会松开已经提供的映射.所以我可以这样做:

System.config({map: {
   "other-class": `http://otherhost:5002/fetchModule?moduleId=other-class.js`
}});
Run Code Online (Sandbox Code Playgroud)

这不适用于相对路径(以.或开头的那些路径..),但如果我将共享路径放在根目录中,则可以解决这个问题.

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

art*_*tem 3

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

AFAIK SystemJS 可以随时通过调用进行配置

SystemJS.config({ map: { additional-mappings-here ... }});
Run Code Online (Sandbox Code Playgroud)

如果它不适合您,您可以覆盖 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我不知道这是否适用于打字稿。另外,您还必须弄清楚在您的情况下到底传递给 loader.normalize 的名称是什么。

另外,如果您使用 systemjs 构建器来捆绑代码,则需要将该重写添加到构建器使用的加载器中(这完全是另一个故事)。