Wujie - transform Angular micro front-end project

Record how to use wujie to transform a micro front-end project based on angular


在学习无界这个微前端框架的时候,发现官方只提供了vue 和 react作为主应用的demo。作为Angular的使用者,是时候自己实践一遍如何从现有angular项目改造为微前端项目了!


项目工程搭建

为了模拟更真实的场景,我们首先利用脚手架生成一个Angular项目.

bash 复制代码
ng new wujie-angular

默认cli会采用npm帮我们安装好依赖,由于我们采用pnpm 安装,所以打开我们的项目后,删除 'package.lock', 'node_modules'文件夹后。

bash 复制代码
pnpm install

项目改造

目前我们的主项目文件都存在在src目录下,而我们的最终效果想在一个目录下管理我们的所有项目(主应用 + 子应用)。

最终效果:

  • apps/host-angular/: Angular 主应用
  • apps/vue-subapp/: Vue 3 + Vite 子应用
  • apps/react-subapp/: React + Vite 子应用
  • apps/ngx-wujie: 无界angular组件库

首先在根目录下创建文件夹apps > host-angular

然后将src文件夹public文件夹tsconfig.app.jsontsconfig.spec.json拖到 host-angular文件夹下作为我们的主应用。

接下来是比较重要的一步,由于我更改了主应用的位置,所以所有相关的配置文件都要做出相应的更改。

首先是移动过的 tsconfig.app.jsontsconfig.spec.json 文件

json 复制代码
"extends": "../../tsconfig.json"  //原来是"extends": "./tsconfig.json"

然后是重头戏angular.json配置文件,需要更改的位置很多图中只展示了部分(想了解所有的话可以参考源码 code)。

将以上所有修改完毕后执行 ng serve 发现我们的项目成功启动了!(如果报错了一定是angular.json文件没有修改完全)项目改造基本完成了。

接着我们在apps目录下新建两个新的项目模拟我们的子应用。

bash 复制代码
cd apps
pnpm create vite vue-subapp --template vue
pnpm create vite react-subapp --template react

然后安装依赖:

bash 复制代码
//安装完两个项目此时在apps目录下
cd vue-subapp
pnpm install
cd ../
cd react-subapp
pnpm install

接着生成我们的ngx-wujie组件库

bash 复制代码
ng generate library ngx-wujie

默认情况下cli会帮我们生成library到 projects文件夹下,我们依旧将他改到我们的apps目录下。更改过程同主应用就不再赘述了,执行命令 ng generate library ngx-wujie 成功打包证明我们迁移成功。

至此我们的准备工作完成了,此时每个项目都可以单独启动。整体的项目结构

wujie Angular组件的封装

由于官方只提供vue 和 react 组件,我们需要封装自己的angular 组件, 打开我们的 ngx-wujie library, 参考框架封装 对我们的 ngx-wujie.component.ts 改造。
首先在项目根目录下安装 wujie

bash 复制代码
//wujie-angular 目录下
pnpm install wujie

新增 peerDependencies

json 复制代码
"peerDependencies": {
  "@angular/common": "^19.2.0",
  "@angular/core": "^19.2.0",
  "wujie": "^1.0.0"
},

ngx-wujie.component.ts 保留组件最核心的功能,后续再进行补充。

ts 复制代码
import { Component, Input, ElementRef, ViewChild, AfterViewInit, OnDestroy } from '@angular/core';
import { startApp, destroyApp } from 'wujie';

@Component({
  selector: 'wujie-angular',
  standalone: true,
  template: `<div #container></div>`,
  styles: ``
})
export class NgxWujieComponent implements AfterViewInit, OnDestroy {
  @ViewChild('container', { static: true }) containerRef!: ElementRef<HTMLElement>;
  @Input({ required: true }) name!: string;
  @Input({ required: true }) url!: string;

  ngAfterViewInit(): void {
    this.start();
  }

  ngOnDestroy(): void {
    this.destroy();
  }

  private start(): void {
    if (!this.containerRef?.nativeElement || !this.name || !this.url) return;
    
    startApp({
      name: this.name,
      url: this.url,
      el: this.containerRef.nativeElement
    });
  }

  private destroy(): void {
    if (this.name) {
      try {
        destroyApp(this.name);
      } catch {}
    }
  }
}

执行 ng build ngx-wujie 打包我们的组件, 修改根目录下 tsconfig.json文件, 新增配置

json 复制代码
"paths": {
  "ngx-wujie": [
    "./dist/ngx-wujie"
  ]
},

Angular主应用中集成子应用

环境变量配置

打开我们的主应用,在 src 目录下新建environments 文件夹,分别创建 environment.ts和 environment.prod.ts文件

ts 复制代码
export const environment = {
    production: false,
    VUE_SUBAPP_URL: 'http://localhost:4201/',
    REACT_SUBAPP_URL: 'http://localhost:4202/'
};

//environment.ts prod文件改为对应的线上地址

同时我们需要对我们的主应用和子应用的package.json script脚本做相应的调整,
例如 vue-subapp

json 复制代码
"scripts": {
  "dev": "vite --port 4201",
  "build": "vue-tsc -b && vite build",
  "preview": "vite preview"
},

我们要保证运行端口与配置保持一致。

新建组件

主应用src 目录下新建 components 文件夹
分别创建 我们vue 和 react 应用组件

ts 复制代码
//micro-vue.component.ts
import { Component } from '@angular/core';
import { environment } from '../../environments/environment';
import { NgxWujieComponent } from 'ngx-wujie';

@Component({
  selector: 'micro-vue',
  standalone: true,
  imports: [NgxWujieComponent],
  template: `
    <wujie-angular
      [name]="'vue-subapp'"
      [url]="env.VUE_SUBAPP_URL"
    />
  `
})
export class MicroVueComponent {
  env = environment;
}
ts 复制代码
//micro-react.component.ts
import { Component } from '@angular/core';
import { environment } from '../../environments/environment';
import { NgxWujieComponent } from 'ngx-wujie';

@Component({
  selector: 'micro-react',
  standalone: true,
  imports: [NgxWujieComponent],
  template: `
    <wujie-angular
      [name]="'vue-subapp'"
      [url]="env.REACT_SUBAPP_URL"
    />
  `
})
export class MicroReactComponent {
  env = environment;
}

这样我们就完成了对子应用的 angular组件的封装。

配置路由

打开主应用 app.route.ts文件

ts 复制代码
import { Routes } from '@angular/router';
import { MicroVueComponent } from './components/micro-vue.component';
import { MicroReactComponent } from './components/micro-react.component';

export const routes: Routes = [
    { path: '', pathMatch: 'full', redirectTo: 'micro/vue' },
    { path: 'micro/vue', component: MicroVueComponent },
    { path: 'micro/react', component: MicroReactComponent }
];

我们做了对子应用组件的路由映射。

一切准备就绪, 接下来就是见证奇迹的时刻!

启动项目

打开三个新的命令行窗口分别执行

bash 复制代码
cd apps/vue-subapp
pnpm dev
bash 复制代码
cd apps/react-subapp
pnpm dev
bash 复制代码
pnpm start

打开 http://localhost:4200/ 你会发现我们的主应用成功加载了vue子应用。

当然更改url http://localhost:4200/micro/react 也可以成功加载react子应用。
至此我们成功的用无界构建出了简版以angular项目为主应用的微前端项目。

pnpm + turbo

在开发环境下,大家可能觉得每次都要打开3个终端,分别执行启动命令,过于繁琐了,有没有好的办法可以让我一次命令就可以启动所有的项目呢 ? 当然有!

在根目录下:

新建 pnpm-workspace.yaml

yaml 复制代码
packages:
  - apps/*

新建 turbo.json

json 复制代码
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", "build/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": []
    },
    "lint": {
      "outputs": []
    }
  }
}

package.json文件修改

json 复制代码
{
  "packageManager": "pnpm@10.15.0",
  "scripts": {
     "dev": "turbo run dev --parallel --filter=!ngx-wujie",
  },
}

apps目录下还有 ngx-wujie 项目,我们将他排除
安装 turbo

bash 复制代码
pnpm add -D turbo@latest -w

如果安装失败,删除 node_modulespnpm-lock.yamlpnpm install 再试

最后在终端执行 turbo

bash 复制代码
pnpm dev

我们的三个应用同时启动了!
解释一下如何做到的:
pnpm dev 执行根目录的脚本 turbo run dev --parallel 被调用,--parallel 参数让 Turborepo 并行执行所有找到的 dev 脚本。
Turborepo 扫描工作空间(pnpm-workspace.yaml),找到所有有 dev 脚本的项目, 并行执行脚本。

Summary

我们实现了:

  • Angular 封装 Wujie 组件(精简版,后续持续集成wujie功能并打包发布到npm)
  • Angualr 主应用接入 Vue/React 子应用
  • 迁移 Monorepo 并实现 pnpm dev 并行开发

总体感觉下来基于无界改造项目可以说是很简单了。