# 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
```