I have a SPA (in Aurelia / TypeScript but that should not matter) which uses SystemJS. Let's say it runs at http://spa:5000/app
.
It sometimes loads JavaScript modules like waterservice/external.js
on demand from an external URL like http://otherhost:5002/fetchmodule?moduleId=waterservice.external.js
. I use SystemJS.import(url)
to do this and it works fine.
But when this external module wants to import another module with a simple import { OtherClass } from './other-class';
this (comprehensiblely) does not work. When loaded by the SPA it looks at http://spa:5000/app/other-class.js
. In this case I have to intercept the path/location to redirect it to http://otherhost:5002/fetchmodule?moduleId=other-class.js
.
Note: The Typescript compilation for waterservice/external.ts
works find because the typescript compiler can find ./other-class.ts
easily. Obviously I cannot use an absolute URL for the import.
How can I intercept the module loading inside a module I am importing with SystemJS?
One approach I already tested is to add a mapping in the SystemJS configuration. If I import it like import { OtherClass } from 'other-class';
and add a mapping like "other-class": "http://otherhost:5002/fetchmodule?moduleId=other-class"
it works. But if this approach is good, how can I add mapping dynamically at runtime?
Other approaches like a generic load url interception are welcome too.
Update
I tried to intercept SystemJS as suggest by artem like this
var systemLoader = SystemJS;
var defaultNormalize = systemLoader.normalize;
systemLoader.normalize = function(name, parentName) {
console.error("Intercepting", name, parentName);
return defaultNormalize(name, parentName);
}
This would normally not change anything but produce some console output to see what is going on. Unfortunately this seems to do change something as I get an error Uncaught (in promise) TypeError: this.has is not a function inside system.js
.
Then I tried to add mappings with SystemJS.config({map: ...});
. Surprisingly this function works incremental, so when I call it, it does not loose the already provided mappings. So I can do:
System.config({map: {
"other-class": `http://otherhost:5002/fetchModule?moduleId=other-class.js`
}});
This does not work with relative paths (those which start with .
or ..
) but if I put the shared ones in the root this works out.
I would still prefer to intercept the loading to be able to handle more scenarios but at the moment I have no idea which has
function is missing in the above approach.