I’ll answer my own question for anyone planning to do anything similar.
I’ve decided to build an application consisting of independent components, each of them is currently running inside of an Angular app. Once we have ported every view, we’ll simply set-up the routing and nav menu and with some minor changes (like handling router view lifecycle along the component lifecycle) we should be able to get rid completely of Angular app.
In order to be able to run Aurelia inside of Angular views, I’ve defined a new webpack entrypoint
angularIntegration: [’./src/angular-integration.ts’]
and added all the modules in given subdirectory there (this is important, as there is no Router definition, so webpack-aurelia won’t discover and add the modules by itself)
new GlobDependenciesPlugin({
'angular-integration': ['src/main-modules/**/*']
}),
as the Aurelia index.html is built manually, I don’t want it to be generated from index.ejs template, I’ve also added AssetsPlugin
(more on this later)
new AssetsPlugin({filename: 'dist/assets.json', fullPath: false}),
now, this is my aureliaIntegration startup code:
function configure(aurelia: Aurelia, moduleName: string, host: Element) {
// ... standard aurelia configuration
aurelia.start().then(() => {
aurelia.setRoot(moduleName, host);
});
}
console.debug("angular<>aurelia integration entry point");
(window as any).startAurelia = (moduleName: string) => {
bootstrapper.bootstrap((aurelia) => configure(aurelia, moduleName, document.querySelector('div[aurelia-app]')));
}
I know setting startAurelia
method on window
is not very elegant, but it was the fastest way to share the aurelia bootstrapper with simple, plain, no-loader old JS code.
now on Angular side, I’ve added the assets to index.html (as the index.html is static and not generated, I’ve created a simple ASP.NET core middleware which handles the routes like “js/aurelia-integration.js” and serves the content of appropriate JS file, looking up its name in assets.json)
for every view defined in Angular that I want to replace with specific Aurelia module, I use this simple template code
<div aurelia-app>
</div>
<script>
window.startAurelia('main-modules/password-reset/password-remind');
</script>
also, to be able to access route (state) info in Aurelia, on Angular side I’ve configured to store it in window
$rootScope.$on('$stateChangeSuccess', function(ev, toState, toParams, fromState, fromParams) {
if (!window._angular_aurelia_integration )
window._angular_aurelia_integration = {};
window._angular_aurelia_integration.state = {
name: toState,
params: toParams
};
});
which is then used in Aurelia app
interface IAngularState {
name: string;
params?: any;
}
export function currentState(): IAngularState {
// see app.run angular & $stateChangeSuccess
let integration = (window as any)._angular_aurelia_integration;
if (integration)
return integration.state;
return undefined;
}
I know this could be much more elegant and performant, but we’re aiming for getting away from Angular as soon as possible