需求

在angular18版本中使用微服务。

创建主应用 

 通过angular脚手架ng new demo_zhu 创建一个名为demo_zhu的angular项目,正常装依赖使其可以运行,然后就可以配置主应用入口文件。

主应用配置 

 首先需要新建一个文件(如:qiankun-sub)作为入口文件,html内给一个标签就可以了

<div id="qiankun" class="qiankun" style="width: 100%; height: 100%">
  </div>

ts文件内写qiankun的注册方法和启动,如此主应用就配置好了。

import { registerMicroApps, start } from 'qiankun';

registerMicroApps([
  {
    name: 'demo_zi',//子应用的项目名称
    entry: '//localhost:4300',// 本地调试(发布需改为实际地址)
    container: '#containerqiankun',//html的id名
    activeRule: '/qiankun',//主应用跳转子应用的主路径
    props: this.msg//msg可以作为给子应用传输的数据
  },
],{
        beforeLoad: [
          (app) => {
            console.log('[LifeCycle] before load %c%s', 'color: green;', app.name)
            return Promise.resolve()
          },
        ],
        beforeMount: [
          (app) => {
            console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name)
            return Promise.resolve()
          },
        ],
        afterUnmount: [
          (app) => {
            console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name)
            return Promise.resolve()
          },
        ],
      });
// 启动 qiankun
start();

配置子应用 

新建一个名为demo_zi的angular项目 。

由于angular18版本已经没有module文件,需要手动创建一个app.module文件以用来做main.ts内的一些配置用。我按照官网使用single-spa-angular插件,在angular18不好用,所以新建了一个module文件。由于18版本都组件化了,所以要把app.component的standalone和imports给注释掉。

@Component({
  selector: '#angular18 app-root',
  // standalone: true,
  // imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})

app.module文件,如果app.component的standalone和imports不注释app.module文件使用就会报错。

import { NgModule, provideZoneChangeDetection } from '@angular/core';
import { AppComponent } from './app.component';
import { BrowserModule } from '@angular/platform-browser';
import { CeshiComponent } from './ceshi/ceshi.component';
import { AppRoutingModule } from './app-routing';


@NgModule({
  declarations: [AppComponent,CeshiComponent],
  imports: [BrowserModule,AppRoutingModule],
  bootstrap: [AppComponent],
  providers: []
})
export class AppModule {}

修改main.ts文件内配置,这里需要使用app.module文件

import { AppModule } from './app/app.module';
import { NgModuleRef, NgZone, enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { environment } from './environments/environment';


  let app: void | NgModuleRef<AppModule>;
  async function render(props?:any) {
    app = await platformBrowserDynamic()
      .bootstrapModule(AppModule,{ ngZone: (window as any).ngZone })
      .catch((err) => console.error(err));
      console.log(`子应用数据接收`,props);
  }
  
  if (!(window as any).__POWERED_BY_QIANKUN__) {
    render();
  }
  if (environment.production) {
    enableProdMode();
  }
  
export async function bootstrap(props: Object) {
  console.log(props);
}

export async function mount(props: Object) {
  render(props);
}

export async function unmount(props: Object) {
  console.log(props);
  // @ts-ignore
  app.destroy();
}

安装@angular-builders/custom-webpack 插件 npm i @angular-builders/custom-webpack 

在根目录增加 custom-webpack.config.js文件,这一段和官网一样,内容是:

const appName = require('./package.json').name;
module.exports = {
  devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  output: {
    library: `${appName}-[name]`,
    libraryTarget: 'umd',
    jsonpFunction: `webpackJsonp_${appName}`, // webpack 5 需要把 jsonpFunction 替换成 chunkLoadingGlobal
  },
};

修改 angular.json,将 [packageName] > architect > build > builder 和 [packageName] > architect > serve > builder 的值改为我们安装的插件,将我们的打包配置文件加入到 [packageName] > architect > build > options

- "builder": "@angular-devkit/build-angular:browser",
+ "builder": "@angular-builders/custom-webpack:browser",
  "options": {
+    "customWebpackConfig": {
+      "path": "./custom-webpack.config.js"
+    }
  }

...


- "builder": "@angular-devkit/build-angular:dev-server",
+ "builder": "@angular-builders/custom-webpack:dev-server",

 修改配置文件package.json文件,将运行的端口号改为和主应用入口一致的端口"start": "ng serve --port 4300 --open" 。 "browser": "src/main.ts",改为 "main": "src/main.ts",

子应用的路由文件要加上@NgModule和export导出 。providers中/qiankun是需要跳转的路由,需要和主应用入口文件的路径一致。

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { CeshiComponent } from './ceshi/ceshi.component';
import { CeshiComponentTwo } from './ceshi copy/ceshi.component';
import { APP_BASE_HREF } from '@angular/common';
export const routes: Routes = [
  { path: 'add', component: CeshiComponent},
  { path: 'ceshi', component: CeshiComponentTwo },
  {
    path: '**',
    redirectTo: '/add',
    pathMatch: 'full'
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [{ provide: APP_BASE_HREF, useValue: (window as any).__POWERED_BY_QIANKUN__ ? '/qiankun' : '/' }]
})
export class AppRoutingModule {}

问题 

配置到这个地方基本上已经可以运行了。在主应用配置相应的跳转路由就可以了。

其中碰到了几个问题

1、跳转的时候路径会闪烁刷新或者直接报错说找不到路径,找了好几个方法都不好用。

2、跳转之后会报一个zone不存在问题,按照官网的方法在18版本也不行。

解决方法:

1、跳转到子应用的路由需要在主应用的路由配置里面添加完整的路由,子应用的路由文件内的providers中的路由一定要一致,否则也会导致路由闪烁。

2、在主应用的入口文件添加构造器,将ngZone 存放到window 里面。然后子应用的main文件中加进去


  constructor(private ngZone: NgZone) {
    (window as any).ngZone = this.ngZone
  }
 let app: void | NgModuleRef<AppModule>;
  async function render(props?:any) {
    app = await platformBrowserDynamic()
      .bootstrapModule(AppModule,{ ngZone: (window as any).ngZone })
      .catch((err) => console.error(err));
      console.log(`子应用数据接收`,props);
  }

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐