A single SPA Utils for Angular 2+
Simliar Projects: https://github.com/worktile/ngx-planet (Production Ready)
based on single-spa && single-spa-angular-cli
difference:
- Host <-> Apps Architecture
- Configurable App (no loader require)
- Independent App in Different Repo and runnable
Examples: see in examples/
Online Demo:
- http://mooa.pho.im/ (host in AWS S3)
- http://mooa.phodal.com/ (host in GitHub Pages)
Features:
- SPA by Configurable file, ex:
apps.json
- Pluggable APP
- support Child APP navigate
- CLI for Generate Config
Goal:
- 构建插件化的 Web 开发平台,满足业务快速变化及分布式多团队并行开发的需求
- 构建服务化的中间件,搭建高可用及高复用的前端微服务平台
- 支持前端的独立交付及部署
If you are mooa, please provide you case to help this project.
Research and Application of Micro Frontends
App Boilerplate: https://github.com/phodal/mooa-boilerplate
in Host and Child App
yarn add mooa
- add get Apps logic in AppComponent (
app.component.ts
)
constructor(private renderer: Renderer2, http: HttpClient, private router: Router) {
// config Mooa
this.mooa = new Mooa({
mode: 'iframe',
debug: false,
parentElement: 'app-home',
urlPrefix: 'app',
switchMode: 'coexist',
preload: true,
includeZone: true
});
http.get<IAppOption[]>('/assets/apps.json')
.subscribe(
data => {
this.createApps(data);
},
err => console.log(err)
);
}
private createApps(data: IAppOption[]) {
data.map((config) => {
this.mooa.registerApplication(config.name, config, mooaRouter.matchRoute(config.prefix));
});
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
this.mooa.reRouter(event);
}
});
return this.mooa.start();
}
- config App
main.ts
for load
import { mooaPlatform } from 'mooa';
if (environment.production) {
enableProdMode();
}
mooaPlatform.mount('help').then((opts) => {
platformBrowserDynamic().bootstrapModule(AppModule).then((module) => {
opts['attachUnmount'](module);
});
});
- setup app routing in
app.module.ts
const appRoutes: Routes = [
{path: '*', component: AppComponent}
...
];
@NgModule({
declarations: [
AppComponent,
...
],
imports: [
BrowserModule,
RouterModule.forRoot(
appRoutes
)
],
providers: [
{provide: APP_BASE_HREF, useValue: mooaPlatform.appBase()},
],
bootstrap: [AppComponent]
})
export class AppModule {
}
- Add for handle URL Change in
app.component.ts
constructor(private router: Router) {
mooaPlatform.handleRouterUpdate(this.router, 'app1');
}
- install global cli
npm install -g mooa
- create URL list files
Examples: apps.txt
http://mooa.phodal.com/assets/app1
http://mooa.phodal.com/assets/help
- Generate Config File
mooa -g apps.txt
Examples:
[
{
"name": "app1",
"selector": "app-app1",
"baseScriptUrl": "/assets/app1",
"styles": [
"styles.bundle.css"
],
"prefix": "app/app1",
"scripts": [
"inline.bundle.js",
"polyfills.bundle.js",
"main.bundle.js"
]
}
]
config in Host app's app.component.ts
this.mooa = new Mooa({
mode: 'iframe',
debug: false,
parentElement: 'app-home',
urlPrefix: 'app',
switchMode: 'coexist'
})
use iframe as application container:
<app-home _nghost-c2="">
<iframe frameborder="" width="100%" height="100%" src="http://localhost:4200/app/help/homeassets/iframe.html" id="help_206547"></iframe>
</app-home>
hidden application when inactive:
<app-home _nghost-c2="">
<app-app1 _nghost-c0="" ng-version="5.2.8" style="display: none;"><nav _ngcontent-c0="" class="navbar"></app-app1>
<iframe frameborder="" width="100%" height="100%" src="http://localhost:4200/app/help/homeassets/iframe.html" id="help_206547"></iframe>
</app-home>
inline.bundle.js
will load script for /
path.
So, just copy *.chunk.js
files to dist/
, then deploy it.
exmples:
mooa.registerApplicationByLink('help', '/assets/help', mooaRouter.matchRoute('help'));
mooa.registerApplication(config.name, config, mooaRouter.matchRoute(config.prefix));
hybrid
if (config.sourceType) {
that.mooa.registerApplicationByLink(config.name, config.link, mooaRouter.matchRoute(config.name));
} else {
that.mooa.registerApplication(config.name, config, mooaRouter.matchRoute(config.prefix));
}
mooaPlatform.navigateTo({
appName: 'help',
router: 'home'
});
Copyright (c) 2013-2014 Christopher Simpkins Copyright (c) 2017-2018 Robin Coma Delperier
© 2018 A Phodal Huang's Idea. This code is distributed under the MIT license. See LICENSE
in this directory.