I am working on an open source platform, similar to WordPress and other CMS apps, but focusing on interopability with the typical Java build pipeline.
The goal is to create some reusable libraries that provide build/runtime dependencies for developers to create feature modules that can be applied to the platform after it's deployed [plugins].
I created an original version that did this well, using AngularJS + Spring framework.
Essentially it would scan dependency jars for static files matching a specific pattern, create MVC resource resolution to the files, then include those file urls into the index page.
This effectively allowed a resource library to include server and client side resources to extend the running platform.
*BUT! A coworker said my font-end was out of date, that I needed to update Angular =P
So I've began rewriting the UI in Angular 4 as a separate resources dependency that can be used in a feature module project for testing, before publishing as a jar.
I really love Angular 4 [TS] as it's more like developing server code which I am proficient at.
Getting to the point... if a feature modules provides client side resources, how do I load them at runtime?
I think I could use JIT and load the js paths in the browser, but I want to use AOT for performance reasons.
I'm considering - unpacking the resources, running a compilation, then serving the page.
Or is there a way to dynamically load an Angular module after the AOT has already been performed?
Referenced Project - https://github.com/savantly-net/sprout-platform
I was able to load an external plugin by referencing the generated NgModuleFactory files in my main app, but still required some pre-compiled configuration in the host app.
After many hours of trying different solutions, I've determined the best for my use-case is to provide the plugins as typescript files in a folder external to the application directory, then do a compile when ready to start serving the app.
An example of how this is working for me - https://github.com/savantly-net/sprout-platform/tree/development/web/sprout-web-ui
I use a simple ts module to import/export the plugins -
[using a relative path here, but also works with an absolute path]
https://github.com/savantly-net/sprout-platform/blob/development/web/sprout-web-ui/sprout.conf.ts
import { WikiModule } from './plugins/wiki/';
export const plugins = [
WikiModule
]
Then use the spread operator to re-export the modules -
https://github.com/savantly-net/sprout-platform/blob/development/web/sprout-web-ui/src/app/plugins/plugins.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { plugins } from '../../../sprout.conf';
import { MenuModule } from '@savantly/ngx-menu';
import { SecurityModule } from '@savantly/ngx-security';
import { SproutPluginModule } from '@savantly/ngx-sprout-plugin';
import { Observable } from 'rxjs/Observable';
const log = (msg: string, obj?: any) => {
console.log('[PluginsModule] ' + msg);
if (obj) {
console.log(obj);
}
}
@NgModule({
imports: [
CommonModule,
SproutPluginModule,
MenuModule,
SecurityModule,
...plugins
],
exports: [...plugins],
declarations: []
})
export class PluginsModule {
private ngModules: NgModule[] = [];
getNgModules(): Observable<NgModule[]> {
return Observable.of(this.ngModules);
}
constructor() {
log('Loaded plugins');
}
}
This is not a true plug-and-play solution, but without having the plugin folders referenced explicitly in the [pre-compiled] configuration file, the build process would not be able to perform tree-shaking.