【问题标题】:JavaScript intercept module importJavaScript 拦截模块导入
【发布时间】:2016-12-10 13:06:50
【问题描述】:

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

它有时会根据需要从外部 URL(如 http://otherhost:5002/fetchmodule?moduleId=waterservice.external.js)加载 JavaScript 模块(如 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 编译工作 find 因为 typescript 编译器可以轻松找到 ./other-class.ts。显然我不能使用绝对 URL 进行导入。

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

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

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


更新

我试图按照 artem 的建议像这样拦截 SystemJS

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

这通常不会改变任何东西,但会产生一些控制台输出以查看发生了什么。不幸的是,这似乎确实改变了一些东西,因为我在system.js 中收到了一个错误Uncaught (in promise) TypeError: this.has is not a function

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

    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 builder 来捆绑您的代码,您将需要将该覆盖添加到 builder 使用的加载器(这完全是另一回事)。

    【讨论】:

    • 由于公共假期,我现在没有时间查看此建议,但会这样做。授予赏金,因为否则它将过期。不过我可能会带着问题回来;)
    • 感谢您的洞察力。我已经通过两次尝试更新了这个问题。您知道为什么在我的情况下拦截normalize 会产生错误吗?
    • 对不起,我的错误 - defaultNormalize 需要 this 参数:defaultNoramlize.call(loader, name, parentName);
    猜你喜欢
    • 2020-11-01
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    • 2013-09-03
    • 1970-01-01
    相关资源
    最近更新 更多