# angular-single-spa **Repository Path**: dh1992/angular-single-spa ## Basic Information - **Project Name**: angular-single-spa - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-08-12 - **Last Updated**: 2021-08-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: Angular ## README # angular-single-spa部署流程 ## 环境 - node -v 14.17.3 - npm -v 6.14.13 - angular -v 12.1.0 - VS code ## 分别创建一个容器,两个微应用 ```js ng new container --prefix=container ng new app1 --prefix=app1 ng new app2 --prefix=app2 ``` ## container部分 ### 安装依赖 ```js npm i single-spa --save npm i systemjs --save npm i import-map-overrides --save ``` ### 修改angular.json ```js //将build下的scripts修改如下: "scripts": [ "node_modules/systemjs/dist/system.min.js", "node_modules/systemjs/dist/extras/amd.min.js", "node_modules/systemjs/dist/extras/named-exports.min.js", "node_modules/systemjs/dist/extras/named-register.min.js", "node_modules/import-map-overrides/dist/import-map-overrides.js" ] ``` ### 修改index.html ```html Container ``` ### 创建微前端项目索引文件 import-map.json ```json { "imports": { "app1": "http://localhost:4201/main.js", "app2": "http://localhost:4202/main.js" } } ``` ### 创建spa-host component - src/app/components 下执行 ng g c spa-host ### 修改spa-host.component.html ```html
``` ### 修改spa-host.component.ts ```ts @ViewChild('app1', { static: true }) private app1: ElementRef; @ViewChild('app2', { static: true }) private app2: ElementRef; ``` ### 创建single-spa.service.ts - src/app/services 下执行 ng g service single-spa ```ts import { Injectable } from '@angular/core'; import { Parcel, mountRootParcel, } from 'single-spa'; import { Observable, from } from 'rxjs'; import { mapTo, tap } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class SingleSpaService { private loadedParcels: { [appName: string]: Parcel } = {}; constructor() { } mount(appName: string, domElement: HTMLElement): Observable { return from(window.System.import(appName)) .pipe( tap(app => { this.loadedParcels[appName] = mountRootParcel(app, { domElement }); }), mapTo(null) ); } unmount(appName: string): Observable { return from(this.loadedParcels[appName].unmount()).pipe( tap(() => delete this.loadedParcels[appName]), mapTo(null) ); } } ``` ### 为了防止Window.System.import报警的修改 - src目录下新建一个types文件夹,然后创建ambient.d.ts文件 ```ts import { ParcelConfig } from 'single-spa'; declare global { interface Window { System: { import: (app: string) => Promise; }; } } ``` ### 完善spa-host.component.ts ```ts import { Component, OnInit, ViewChild, ElementRef, OnDestroy } from '@angular/core'; import { SingleSpaService } from '../../service/single-spa.service'; import { zip } from 'rxjs'; @Component({ selector: 'slb-spa-host', templateUrl: './spa-host.component.html', styleUrls: ['./spa-host.component.scss'] }) export class SpaHostComponent implements OnInit, OnDestroy { constructor(private service: SingleSpaService) { } @ViewChild('app1', { static: true }) private app1: ElementRef; @ViewChild('app2', { static: true }) private app2: ElementRef; ngOnInit() { this.service.mount('app1', this.app1.nativeElement).subscribe(); this.service.mount('app2', this.app2.nativeElement).subscribe(); } async ngOnDestroy() { await zip( this.service.unmount('app1'), this.service.unmount('app2') ).toPromise(); } } ``` ### 注册app.module.ts ```ts import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { SpaHostComponent } from './spa-host/spa-host.component'; @NgModule({ declarations: [ AppComponent, SpaHostComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [ ], bootstrap: [AppComponent] }) export class AppModule { } ``` ### 修改路由表 app-routing.module.ts ```ts const routes: Routes = [ { path: '', component: SpaHostComponent } ]; ``` ### 修改app页面 ```html ``` ### 修改main.ts, 添加如下代码 ```ts import * as singleSpa from 'single-spa'; singleSpa.start(); ``` ## app1部分 ### 执行 ng add single-spa-angular - 端口选择 4201 ### 修改路由 ```ts import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { APP_BASE_HREF } from '@angular/common'; import { EmptyRouteComponent } from './empty-route/empty-route.component'; const routes: Routes = [ { path: '**', component: EmptyRouteComponent } ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], providers: [{ provide: APP_BASE_HREF, useValue: '/' }] }) export class AppRoutingModule { } ``` ### 修改app.component.html ```html

Mien's first Micro Front-end project

``` ## app2部分同上,记得把端口设置为4202 ## 启动服务 ```js // app1 npm run serve:single-spa:app1 // app2 npm run serve:single-spa:app2 // container npm run start ```