專家解讀:利用Angular專案與資料庫融合例項

華為雲開發者社群發表於2020-06-23
摘要:面對如何在現有的低版本的框架服務上,執行新版本的前端服務問題,華為雲前端推出了一種融合方案,該方案能讓獨立的Angular專案整體執行在低版本的框架服務上,通過各種適配手段,讓Angular專案也能獲取到外層框架服務的資源。

華為雲前端服務前期採用AngularJs作為框架技術棧,技術較為老舊,效能較差,在華為雲快速發展的今天,顯然不能滿足要求。因此我們必須要升級前端技術棧,使用Angular2+來承載我們的前端服務。GeminiDB作為新服務,也是資料庫乃至華為雲未來的重點服務,作為前端部分,必須在技術上使用最前沿的框架,以最大地提高使用者體驗。

但是技術棧的升級不是一蹴而就的,尤其是在華為雲,所有的雲服務必須在框架服務的底座上執行,而框架服務承載了所有的雲服務,如果要進行技術棧升級,必然是一個緩慢的過程。GeminiDB作為華為雲服務裡的一員,也不可能脫離框架服務而存在。因此存在一個問題,就是如何在現有的低版本的框架服務上,執行新版本的前端服務。

為了解決以上問題,華為雲前端推出了一種融合方案,該方案能讓獨立的Angular專案整體執行在低版本的框架服務上,通過各種適配手段,讓Angular專案也能獲取到外層框架服務的資源。

底層專案

底層專案使用webpack打包,打包後通過在index.html裡引入businessAll.js檔案,以該檔案為入口啟動整個框架服務。

<script type="text/javascript" src="businessAll.js"></script>

在底層框架服務啟動後,再渲染出具體雲服務內容。

<div class="service-content-view" ui-view ng-animate="{enter:'fade-enter'}"></div>

Angular專案

Angular專案支援獨立執行,有單獨的index.html,也有單獨的main.ts入口。但是如果希望Angular專案執行在底層框架服務上,就必須把Angular專案看作是一個獨立的模組,把專案整體引入到底層專案中。因此,我們可以預先把Angular專案編譯好,放到底層專案的一個目錄下。在執行底層專案時,在index.html裡將Angular專案引進來,獨立執行。

<link rel="stylesheet" type="text/css" href="{底層專案中Angular專案的路徑}/styles.css" />
<script type="text/javascript" src="{底層專案中Angular專案的路徑}/runtime.js"></script>
<script type="text/javascript" src="{底層專案中Angular專案的路徑}/polyfills.js"></script>
<script type="text/javascript" src="{底層專案中Angular專案的路徑}/main.js"></script>

專案融合

底層專案和Angular專案均能獨立,但是要讓兩者融合起來,會遇到以下幾個問題:

1.底層專案中如何渲染出Angular專案。

2.Angular專案依賴底層專案的資源,如何保證Angular專案在底層專案執行起來後再執行。

3.如何解決底層專案和Angular專案的路由衝突問題。

渲染Angular專案

底層專案分為兩部分,一部分是底層框架服務,另一部分是具體雲服務。現在我們要做的是把老的雲服務專案替換成新的Angular專案,因此我們可以直接在渲染老的雲服務的地方替換成新的Angular專案的渲染容器。

<div class="service-content-view" ui-view ng-animate="{enter:'fade-enter'}"></div>
<app-root></app-root>

底層框架服務對頁面渲染上做了一些體驗上的優化,因此必須保留原模板中的ui-view,使底層專案正常執行起來,實際上老的雲服務專案的渲染內容已經轉發到新的Angular專案上面。

Angular專案對底層專案的依賴

底層框架服務給雲服務提供了很多公共變數與服務,這些變數和服務是各個雲服務必須要使用的,否則雲服務將不能正常運作。

啟動順序問題

對於Angular專案來說,要使用底層框架服務提供的內容,首先要求Angular專案在底層專案執行起來之後再執行。這裡採用Augular中的APP_INITIALIZER令牌來解決這個問題。APP_INITIALIZER是一個函式,在程式初始化的時候被呼叫。這裡在根模組的providers中以factory的形式來配置。

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppInitService } from './services/app-init.service';
import { AppComponent } from "./app.component";

@NgModule({
 declarations: [AppComponent],
 imports: [BrowserModule],
 providers: [
     AppInitService,
    {
         provide: APP_INITIALIZER,
         useFactory: initializeApp,
         deps: [AppInitService],
         multi: true
    }
],
 bootstrap: [AppComponent]
})
export class AppModule {}

export function initializeApp(appInitService: AppInitService) {
   return (): Promise<any> => {
       return appInitService.Init();
  };
}

在appInitService裡,先獲取到底層框架的資源,再進行Angular專案的初始化。

import { Injectable } from '@angular/core';

@Injectable()
export class AppInitService {
   constructor() {}

   Init() {
       return new Promise<void>((resolve, reject) => {
           // 獲取到底層框架服務的資源
           resolve();
      });
  }
}

資源依賴問題

底層專案使用的是AngularJs,Angular專案獲取底層框架服務提供的資源不能通過Angular的方式引入,因此需要藉助AngularJS的注入器獲取在底層框架中註冊的服務元件:

static get(inject: string): any {
return (window as any).angular.element('html').injector().get(inject);}
如,要獲取 $rootScope:
 rootScope = (window as any).angular.element('html').injector().get(‘$rootScope’);

路由衝突問題

Angular專案本身有自己的路由,但是Angular專案是執行在底層框架之上的,Angular專案的路由將會被底層框架所攔截。因此,我們也需要在底層框架的專案中配置相同的路由,以免Angular專案中的有效路由被底層框架識導向為404。

Angular專案路由:

{
   path: '',
   redirectTo: 'ng2app1',
   pathMatch: 'full'
},
{
   path: 'ng2app1',
   loadChildren: './ng2app1/ng2app1.module#Ng2app1Module',
},
{
   path: 'ng2app2',
   loadChildren: './ng2app2/ng2app2.module#Ng2app2Module',
}
 
底層框架路由:
var configArr = [
  {
       name: 'ng2app1',
       url: '/ng2app1'
  },
  {
       name: 'ng2app2',
       url: '/ng2app2'
  }
];

另外,由於底層專案使用的是hash路由,Angular專案中也要做相應的配置,預設是使用的是PathLocationStrategy,需要切換到hash模式。

import { LocationStrategy, HashLocationStrategy } from '@angular/common';

...
providers: [
  {
       provide: LocationStrategy,
       useClass: HashLocationStrategy
  }
]

總結

以上方案是在底層框架升級週期長的前提下的一個臨時方案,實際上還是存在著不少的問題。比如底層框架對於老的雲服務容器是有統一管理的,老的雲服務容器會針對不同的場景能夠自適應,而融合方案中的Angular專案則不能;每次啟動整個專案時,必須要預先編譯好裡面的Angular專案,再去啟動外層的底層框架,開發效率比較低。因此,後續GeminiDB服務應該在底層框架升級後,儘快適應到新的底層框架體系中,提高服務的可用性和穩定性。

 

點選關注,第一時間瞭解華為雲新鮮技術~

相關文章