Dynamic ESM microfrontend loading
- SystemJS Version: 6.12.1
- Which library are you using?
- system.js
- s.js
- system-node.cjs
- Which extras are you using?
- AMD extra
- Named Exports
- Named Register
- Transform
- Use Default
- Global
- Dynamic Import Maps
- Are you using any custom hooks?
SystemJS.constructor.prototype.createScript = (url: string) => {
const script = document.createElement('script');
script.src = url;
script.type = 'module';
return script;
}Question
I'm in the process of upgrading an Angular based microfrontend application. With the upgrade Angular switched from UMD to ESM. The microfrontends are provided as libs and dynamically lazy loaded when a route (path) is accessed. The setup worked fine with UMD modules and without the hook.
This is a code listing from the router in the host application:
const routes: Routes = [{
path: 'mf',
loadChildren: () => {
const SystemJS = (window as any).System;
SystemJS.constructor.prototype.createScript = (url: string) => {
const script = document.createElement('script');
script.src = url;
script.type = 'module';
return script;
}
// see https://github.com/systemjs/systemjs/blob/main/docs/api.md#systemsetid-module---module
SystemJS.set("app:@angular/core", AngularCore);
return SystemJS.import('http://localhost:4200/assets/mf.mjs') // put in assets for demonstration
.then(m => m.MfModule);
}
}];And the "importmap" in the host application:
<script type="systemjs-importmap">
{
"imports": {
"@angular/core": "app:@angular/core"
}
}
</script>The first lines of the microfrontend ESM to import (mf.mjs):
import * as i0 from '@angular/core';
import { Injectable, Component, NgModule } from '@angular/core';
class MfService {
constructor() { }
}
MfService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.9", ngImport: i0, type: MfService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });The problem is, the imports from the imported microfrontend can not be resolved.
Chrome 102.0 and Firefox 100.0.2 end up with:
Uncaught TypeError: Failed to resolve module specifier "@angular/core". Relative references must start with either "/", "./", or "../".
Firefox Nightly 102.0a1 (with enabled importsmaps support):
Uncaught TypeError: The specifier “@angular/core” was a bare specifier, but was not remapped to anything.
This is the proposed resolve Algorithm: https://wicg.github.io/import-maps/#new-resolve-algorithm
I'm a bit wondering about the need for real importmaps and the internals of SystemJS. As SystemJS seems to specify its own systemjs-importmaps, are browser importmaps still needed? If I specify browser importmaps, the browser just tries to load the remapped specifier "app:@angular/core", which of course fails.
I verified, that SystemJS would be able to resolve @angular/core. So I think I'm just somehow mistaken in how I'm utilizing SystemJS to import the Module. As SystemJS just seems to create a
Source: systemjs/systemjs