我有一个 SPA(使用 Aurelia/TypeScript 编写,但这并不重要),它使用 SystemJS。假设它在 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 编译是能够正常工作的,因为 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
函数。
normalize
会产生错误? - ZoolWaythis
参数: defaultNoramlize.call(loader, name, parentName); - artem