JavaScript拦截模块导入

时间:2016-08-04 12:03:56

标签: javascript ecmascript-6 systemjs es6-module-loader

我有一个使用 SystemJS 的SPA(在Aurelia / TypeScript中,但无关紧要)。我们假设它在http://spa:5000/app运行。

有时会根据waterservice/external.js之类的外部网址按需加载http://otherhost:5002/fetchmodule?moduleId=waterservice.external.js等JavaScript模块。我使用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"这样的映射就可以了。但如果这种方法很好,我怎样才能在运行时动态添加映射?

其他方法,如通用加载网址拦截也是受欢迎的。

更新

我试图像 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`
}});

这不适用于相对路径(以...开头的路径),但如果我将共享路径放在根中,则可以使用

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

1 个答案:

答案 0 :(得分:2)

  

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

AFAIK SystemJS可以随时调用

进行配置
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);
    }
}

我不知道这是否适用于打字稿。此外,您必须确定在您的情况下确切传递给loader.normalize的名称。

此外,如果使用systemjs构建器捆绑代码,则需要将该覆盖添加到构建器使用的加载器(以及另一个故事)。