A Single SPA adapter for Aurelia framework v1. The module manually bootstraps the aurelia instance when the Single SPA bootstrap lifecycle method is called and will call instance.start() and instance.setRoot() when the application is mounted.
Due to a non existant Aurelia teardown API the root component is removed, detached and unbound manually as suggested by the author.
npm i single-spa-aurelia-framework
{
// Aurelia configure method provided in main.ts
configure: configure,
// Method to get the active aurelia instance from 'aurelia-dependency-injection'
getInstance: () => Container.instance.get(Aurelia),
// Manual bootstrap method from 'aurelia-bootstrapper'
bootstrap: aureliaBootstrap,
// Your root component, required by setRoot() the called in mount() lifecycle method.
component: PLATFORM.moduleName('app'),
// Logs single-spa lifecycle methods when invoked. Default false.
debug: true,
}
This example demonstrates how to expose the Single SPA lifecycle methods with an existing configure()
method in your main.ts file.
./src/main.single-spa.ts
import singleSpaAureliaFramework from 'single-spa-aurelia-framework';
// Rename the imported manual bootrap method due to a naming conflict with the
// exposed Single SPA lifecycle method
import { bootstrap as aureliaBootstrap } from 'aurelia-bootstrapper';
import { Container } from 'aurelia-dependency-injection';
import { Aurelia } from 'aurelia-framework';
export async function configure(aurelia: Aurelia) {
// ... your Aurelia configuration
/*
* Make sure to not call `aurelia.start()` and `aurelia.setRoot()` on the aurelia instance
* in this configure method. This will be handled when the single-spa mount
* lifecycle method is called.
*/
}
const lifecycles = singleSpaAureliaFramework({
configure,
getInstance: () => Container.instance.get(Aurelia),
bootstrap: aureliaBootstrap,
component: PLATFORM.moduleName('app'),
debug: true,
});
export const bootstrap = lifecycles.bootstrap;
export const mount = lifecycles.mount;
export const unmount = lifecycles.unmount;
If you want to pass data to the child applications when mounting you can use the customProps
method available in single-spa's registerApplication()
. Make sure to provide your data in the demonstrated format since the SingleSpaAureliaCustomProps
singleton in your instance will only expose the payload property.
registerApplication({
name: '@organisation/application',
app: () => System.import('@organisation/application'),
activeWhen: ['/route1', '/route2'],
customProps: () => {
return {
payload: {
user: user,
locale: locale,
},
};
},
});
Your Aurelia view model can then use regular DI to read the props registered for the instance.
@autoinject
export class SessionManager {
user: User;
constructor(readonly props: SingleSpaCustomProps) {
this.user = this.props['user'];
}
}
If your project is running webpack, make sure to adjust them to the single-spa recommended confguration. This is an example of a seperate remote
build environment.
./src/config/environment.remote.json
{
"debug": true,
"testing": true,
"remote": true
}
Important: This configuration should extend and not replace your current configuration.
./webpack.config.js
module.exports = ({ remote } = {}, { port } = {}) => ({
// A separate `main.single-spa.ts` entrypoint exposed with `au run --env.remote`.
entry: remote ? './src/main.single-spa.ts' : './src/main.ts',
// As per Single SPA's recommended setup you should pack for System.register() format.
output: {
libraryTarget: 'system',
publicPath: `https://localhost:${port}`,
},
// As per Single SPA's recommended setup all optimization should be disabled.
optimization: {
runtimeChunk: false,
},
// Your dev server should allow access from your Single SPA root app.
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
},
}
};