背景

        首先,前端技术日新月异,从最初的jQuery,Ext.js,Ajax等技术,到近几年AngularJS,Angular,Vue,React等热门框架的出现,技术框架层出不穷,为了解决遗留系统迁移的问题,我们不得不考虑微服务架构,不重写原有系统,同时可以开发新的业务,是一个相当有吸引力的特性,而且对技术人员来说,也是一件相当不错的事情。人生苦短,请尽量不重写。

        其次,随着业务发展,开发变得越来越复杂。新增,修改某个功能等操作,都需要重新部署整个系统,任意一个模块的问题,都有可能引起整个系统的崩溃等问题。庞大的系统采用微服务架构,将单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用可以实现独立开发、独立部署,减少部署时间,以及引起系统崩溃的原因。同时它们也可以进行并行开发——这些组件可以通过NPM、Git TagGit来进行管理。

        最后,对大部分公司和团队来说,如果我们前期选定Angular,大概率我们将继续使用原有的框架,毕竟已经拥有大量成熟的基础设施。但是随着市场的变化,我们不得不考虑增加技术栈,更好的迎合市场,即微服务架构。微服务架构并不只是为了在架构上好看,还可以提升开发效率,尤其是庞大的应用系统,由单一应用拆分为多个小型前端应用,每个应用可以实现独立开发和独立部署,项目维护起来也会变得容易很多。

Micro-app使用说明

下面是以Angular为基座,默认基座的路由为history模式,Vue为子应用的使用:

基座应用,也叫主应用

1.安装依赖

npm install  @micro-zoe/micro-app -S

2.main.ts文件引入

import microApp from '@micro-zoe/micro-app';

microApp.start({
  disableScopecss: true // 禁用样式隔离可以提升页面渲染速度,在此之前,请确保各应用之间样式不会相互污染
});

3. 创建主应用入口文件夹,在src文件中,新建practice文件夹,在页面中嵌入子应用

微服务前端 微服务前端架构_前端多技术框架组合

 index.component.html

<button nz-button (click)="onSendMessage()">下发消息</button>

<micro-app #microApp
    *ngIf="mode == 'development'"
    name="app1"
    url="http://localhost:8080"
    [data]="data"
    (created)="onCreated($event)"
    (mounted)="onMounted($event)"
    (unmount)="onUnmount($event)"
    (error)="onError($event)"
    (datachange)="onHandleDataChange($evnet)"
    baseroute="/index/practice">
</micro-app>

mode 配置不同的环境变量

url 根据环境不同配置URL地址

data 初始化给子应用的数据;只接受对象类型,采用严格对比(===),当传入新的data对象时会重新发送 

index.component.ts

import { Component, OnInit } from "@angular/core";
import { MicroAppService } from "src/app/service/microapp.service";
import { environment } from "src/environments/environment";

@Component({
selector: 'app-index',
templateUrl: './index.component.html',
})
export class IndexComponent implements OnInit {
public mode: string = environment.mode;
data: any;

constructor(
    private microAppService: MicroAppService,
) { }
ngOnInit() { 
    this.data = {
        id: '111',
        name: 'test',
      }
}
onCreated(e) {
    console.log('onCreated', e);
}
onBeforemount(e) {
    console.log('onBeforemount', e);
}
onMounted(e) {
    console.log('onMounted', e);
}

onUnmount(e) {
    console.log('onUnmount', e);
}
onError(e) {
    console.log('onError', e);
}
onSendMessage() {
    this.microAppService.onSendData('新的数据');
}
merchantProjectCode() {
    this.microAppService.onSendData('新的数据');
}
}

practice.routing.ts

import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { IndexComponent } from "./index/index.component";

const routes: Routes = [
    {
        path: '',
        component: IndexComponent
    }
];

@NgModule({
    declarations: [],
    imports: [
        RouterModule.forChild(routes)
    ]
})

export class PracticeRoutingModule{}

practice.module.ts

import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core";
import { IndexComponent } from "./index/index.component";
import { PracticeRoutingModule } from "./practice.routing";
import { CommonModule } from "@angular/common";

@NgModule({
    declarations: [IndexComponent],
    imports: [
        CommonModule,
        PracticeRoutingModule
    ],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})

export class PracticeModule {}

提醒:Module模块必须引入CommonModule,否则将引起下面的报错。

微服务前端 微服务前端架构_前端微服务micro-app_02

 4.路由导航

在app-routing.module.ts文件中增加子应用的入口

{
      path: 'portal',
      children: [
        {
          path: '**',
          loadChildren: () => import('./pages/portal/portal.module').then((m) => m.PortalModule),
        }
      ]
 }

子应用

        初始化一个vue的demo,具体实现过程我就不在这里展示了,直接进入到vue项目的钩子函数的调用及与基座应用的互动。

  在主应用index.component.ts中,我们调用了一个服务MicroAppService,代码如下:

import { Injectable } from "@angular/core";
import microApp from "@micro-zoe/micro-app";

@Injectable({
    providedIn: 'root'
})
export class MicroAppService {

    onSendData(data) {
        microApp.setData('app1', { type: 'send', data });
    }
}

 data属性用来初始化给子应用数据

比如:主应用ts模块中

ngOnInit() {
    this.data = {
        id: '111',
        name: 'test',
    }
}

在vue子应用中,在onMounted函数中

const data = (window as any).microApp.getData(); 
console.log('getData', data)

微服务前端 微服务前端架构_前端_03

 主应用通知子应用,根据需求采用两种不同的传入方式:

第一种:

// 主应用
this.microAppService.onSendData('新的数据')
// 子应用
 onMounted(() => {
      (window as any).microApp.addDataListener(e => {
          console.log('刷新列表页面', e)
      })
 });

微服务前端 微服务前端架构_微服务背景_04

第二种:

// 主应用
this.microAppService.onSendData({type: '主应用通知子应用', data: '刷新列表'});
// 子应用
 onMounted(() => {
      (window as any).microApp.addDataListener(e => {
          console.log('刷新列表页面', e)
      })
 });

微服务前端 微服务前端架构_前端多技术框架组合_05

子应用给主应用发送通知,代码如下:

// 子应用的触发事件
// dispatch只接收对象作为参数
(window as any).microApp.dispatch({ type: "子应用发送的数据"})
// 主应用接收事件
onHandleDataChange(e) {
    console.log('datachange', e.detail.data)
}

微服务前端 微服务前端架构_前端_06

总结

        以上demo是总结的开发过程,主要陈述了以Angular为基座应用和Vue为子应用的使用方式,从依赖安装到主应用与子应用的互动,我们选择Micro-App作为实现方案,Micro-App是当下最火、讨论热度最高,使用起来最方便的技术栈。