I am working on a MEAN stack app that features plugins. In the server app I managed to load the plugins files using fs.lstatSync()
and stat.isDirectory()
. I also managed to expose to the public each plugin's /public
directory using app.use( pluginPublicPath, express.static( pluginServerPath ));
.
Now I have to inject each plugin's main-service.ts
inside the angular app. I am using standard Typescript Angular 2 services as illustrated bellow. App classes are imported with system.js
, nothing fancy.
Project structure
project
└─── plugins
| └─── my-plugin
| | └─── server // Some server stuff, all ok here
| | └─── public // Managed to expose it in the browser
| | └─── main.ts
| | └─── ...
| └─── some-plugin
| | └─── server
| | └─── public
| └─── another-plugin
| └─── server
| └─── public
└─── server // The server app
| └─── ...
└─── public // The public angular app, nothing special, the usual files
| └─── services
| | └─── foo-service.ts
| | └─── ...
| └─── app.component.ts
| └─── main-module.ts
| └─── ...
└─── server.js
└─── package.json
└─── ...
foo-service.ts
// Static file, known and fixed path, no trouble here
import { Injectable } from '@angular/core';
import { AnotherService } from './another-service'
@Injectable()
export class MyService {
constructor( private _anotherService: AnotherService ) {}
}
I can inject the plugin's main-service.ts
in app.component.ts or in foo-service.ts by typing it directly in the constructor()
method.
import { MyPluginMainService } from '../../plugins/my-plugin/public/main-service'
export class MyService {
constructor( private _myPluginMainService : MyPluginMainService ) {}
}
What I want to achieve is to import the main-service.ts
file from each plugin dynamically. Basically I want to have a plugin framework that loads the plugins by convention, not by configuration. I pursued this design in order to avoid changing core files when adding a new plugin in the project. Similarly to how a CMS detects automatically a plugin.
I was expecting to do this by injecting the plugin services from a list generated by the server. The server app already knows which plugins are available and enabled. How should I proceed to inject dynamically plugins/some-plugin/main-service.ts
? I could export from the server through an api/modules
endpoint a list of file names and file paths required to bootstrap the public app. Also a sample of code covering this situation for components would be welcomed. Thank you!
app.components.ts - My wild guess...
modules.forEach( module => import { module.name } from module.path );
export class MyService {
constructor( ??? ) {}
}
Also my wild guess for main-module.ts
listOfProviders = [];
modules.forEach( module =>
listOfProviders.push( import { module.name } from module.path );
);
@NgModule({
imports: ...
declarations: ...
providers: listOfProviders,
bootstrap: [ AppComponent ]
})