![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@angular-architects/module-federation-tools
Advanced tools
Add-on for `@angular-architects/module-federation` helping to reduce boiler plate code.
Add-on for @angular-architects/module-federation
helping to reduce boiler plate code.
The current release is focusing on combining web components with module federation for multi framework and multi version micro frontends:
By compiling and loading these web components via module federation, we can share libraries like Angular if they use the same version. Otherwise, module federation would decide at runtime to load a dedicated version of the lib for the micro frontend in question:
This can help to balance the trade-off between bundle size and isolation of micro frontends.
Disclaimer: Multi-Framework and -Version Micro increase the overall complexity and call for some workarounds. This library tries to hide some of them.
Please find our tutorial here.
This helper packages assumes that Micro Frontends are exposed as Web Components.
To do this in Angular, install @angular/elements
:
npm i @angular/elements
Then you can directly convert your AppComponent to a Web Component:
import { createCustomElement } from '@angular/elements';
[...]
@NgModule({
[...]
declarations: [
AppComponent
],
bootstrap: [] // No bootstrap components!
})
export class AppModule {
constructor(private injector: Injector) {
}
ngDoBootstrap() {
const ce = createCustomElement(AppComponent, {injector: this.injector});
customElements.define('angular1-element', ce);
}
}
If you framework doesn't directly support exposing your application as a web component, you can easily write a simple Wrapper around it. Basically, a web component -- to be more precise: a custom element -- is just an EcmaScript class extending HtmlElement
and registered via customElements.register
. Please find an example for React here.
Add @angular-architects/module-federation
to your micro frontend:
ng add @angular-architects/module-federation
Make your webpack.config.js
expose the whole bootstrap.ts
that bootstraps your AppModule
.
// webpack.config.js
name: "angular3",
library: { type: "var", name: "angular3" },
filename: "remoteEntry.js",
exposes: {
'./web-components': './src/bootstrap.ts',
},
If the file that bootstraps your applications is called differently, adjust these settings accordingly.
For enabling Angular for a multi version/ multi framework scenario, we need some helper functions. The easiest way to use them, is to bootstrap your Angular app with our bootstrap helper:
// main.ts
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { bootstrap } from '@angular-architects/module-federation-tools';
bootstrap(AppModule, {
production: environment.production,
appType: 'shell',
// appType: 'microfrontend'
});
Use this bootstrap helper for both, your shell and your micro frontends!
Please make sure to set the appType
to shell
for your shell application and to microfrontend
for your Micro Frontends.
The WebComponentWrapper
helps you to route to web components:
export const APP_ROUTES: Routes = [
[...]
{
path: 'angular1',
component: WebComponentWrapper,
data: {
remoteEntry: 'https://nice-grass-018f7d910.azurestaticapps.net/remoteEntry.js',
remoteName: 'angular1',
exposedModule: './web-components',
elementName: 'angular1-element'
} as WebComponentWrapperOptions
},
[...]
}
Beginning with Angular 13, the CLI is emitting EcmaScript modules. Hence, we need to adjust the usage of the WebComponentWrapper when loading a remote that has been created with the CLI 13 or higher. For this, set type
to remote
and skip the remoteName
property (for Modules, we don't need a remoteName):
export const APP_ROUTES: Routes = [
[...]
{
path: 'angular1',
component: WebComponentWrapper,
data: {
type: 'module',
remoteEntry: 'https://your-path/remoteEntry.js',
exposedModule: './web-components',
elementName: 'angular1-element'
} as WebComponentWrapperOptions
},
[...]
}
If a web component has it's own router, you can use our UrlMatchers startsWith
and endsWith
to define, which part of the URL is intended for the shell and for the micro frontend:
// Shell
export const APP_ROUTES: Routes = [
[...]
{
matcher: startsWith('angular3'),
component: WebComponentWrapper,
data: {
remoteEntry: 'https://gray-river-0b8c23a10.azurestaticapps.net/remoteEntry.js',
remoteName: 'angular3',
exposedModule: './web-components',
elementName: 'angular3-element'
} as WebComponentWrapperOptions
},
[...]
}
// Micro Frontend
RouterModule.forRoot([
{ path: 'angular3/a', component: AComponent },
{ path: 'angular3/b', component: BComponent },
// To prevent issues when routing to other micro frontends
// a catch-all route should be defined
{ path: '**', component: EmptyComponent },
]);
The WebComponentWrapper
can also be used as a traditional component:
<mft-wc-wrapper [options]="item"></mft-wc-wrapper>
item: WebComponentWrapperOptions = {
remoteEntry: 'https://witty-wave-0a695f710.azurestaticapps.net/remoteEntry.js',
remoteName: 'react',
exposedModule: './web-components',
elementName: 'react-element'
},
The optional properties props
and events
allow to defined properties and events for the web component:
props = {
message: 'Hello from Shell',
};
events = {
clicked: (event) => {
console.debug('clicked!', event);
},
};
<mft-wc-wrapper
[options]="item"
[props]="props"
[events]="events"
></mft-wc-wrapper>
In a multi version micro frontend strategy, it is important to load the zone.js bundle to the window object only once. Also, one need to make sure that only one instance of the ngZone is used by all the micro frontends.
If you share @angular/core
and therefore also have one technical reference to the BrowserPlatform, that is used by more than one micro frondend, Angular's default setup is, to support only one platform instance per shared version. Be aware that you need to create multi platform instances in case of different versions, but also in case the version is the same, but @angular/core
is not shared, but packed into the micro frontend's bundles directly (like in Angular's default way w/o module federation).
Naturally, such technical details are hard to get into. Therefore the bootstrap()
function of this package helps to implement your multi version strategy w/o the need of implementing those low-level aspects on your own.
Some optional flags are offered to provide options for custom behavior of the bootstrap()
function:
ngZoneSharing: false
: Deactivate ngZone sharing in the window object (not recommended):
bootstrap(AppModule, {
production: environment.production,
ngZoneSharing: false, // defaults to true
});
platformSharing: false
: Deactivate Platform sharing in the window object (not recommended):
bootstrap(AppModule, {
production: environment.production,
platformSharing: false, // defaults to true
});
activeLegacyMode: false
: Deactivates the legacy mode that provides backwards compatibility for Platform sharing:
bootstrap(AppModule, {
production: environment.production,
activeLegacyMode: false, // defaults to true
});
@angular-architects/module-federation-tools
in version ^12.6.0
, ^13.1.0
or any newer major version you can switch off the legacy mode manually.bootstrap()
function even in such cases, where the same version is packed into different micro frontend bundles.Please find more information on the underlying ideas in this blog article.
FAQs
Add-on for `@angular-architects/module-federation` helping to reduce boiler plate code.
We found that @angular-architects/module-federation-tools demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.