摘要: 面对如何在现有的低版本的框架服务上,运行新版本的前端服务问题,华为云前端推出了一种融合方案,该方案能让独立的 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 服务应该在底层框架升级后,尽快适应到新的底层框架体系中,提高服务的可用性和稳定性。
点击关注,第一时间了解华为云新鲜技术~