基于AngularJS和Angular的混合应用基础(AngularJS+ui-router+Angular+Angular Router+ngUpgrade+Lazy Load)
我想介绍一下如何快速使用ngUpgrade,因为我认为在2018年10月发布了Angular7之后,有些人可能还不太了解ngUpgrade的用法,并且可能仍然有一些AngularJS的项目。为了获得可运行的代码,我想提供一些使用ngUpgrade的指南。
只需要一个选项:适用于目标读者
-
- AngularJSもAngularも知ってるけど、ngUpgradeの使い方がよくわからない人
- AngularJS+Angularのハイブリッドアプリになかなか踏み込めない人
准备
§1 准备
可以假设AngularJS、Angular和Angular CLI等必要的框架/库已经预先通过npm安装好。
Angular和Angular CLI都是最新版本,没有问题。
※作者在Angular v7.0.2上进行了确认。
§1.1 将URL切换到HTML5模式
我们设定$locationProvider.html5Mode(true),将URL设置为HTML5模式。
將HTML源碼中的ng-app刪除。
删除HTML源代码中的ng-app。
如果正在使用ng-strict-di,也将其删除。
设定AngularJS的根组件
如果在AngularJS中没有根组件,请创建一个。
angular.module('app')
.component('appRoot', {
templateUrl: 'path/to/html' // or template: ``
controller: function () {}
});
创建一个用于Angular的目录。
我认为可以使用src/ng2等。
我们可以从您平时使用的项目中借用angular.json、tsconfig.json、polyfills.ts和main.ts等文件。
将angular.json中的入口点设置为创建的main.ts文件。
{
...省略
"sourceRoot": "src",
"projectType": "application",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "public/ng2",
"index": "src/index.html",
"main": "src/ng2/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"assets": [
"src/assets",
],
"styles": [
"src/styles.scss"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/js/tooltip.js",
"node_modules/bootstrap/js/popover.js",
"node_modules/bootstrap/js/dropdown.js",
"node_modules/bootstrap/js/tab.js",
"node_modules/bootstrap/js/modal.js"
]
},
...省略
§1.4 任务管理器
§1.4.1 使用除了webpack之外的构建工具(gulp/ grunt)作为任务执行器的情况
我认为应将应用程序文件生成为一个最终文件。
将生成文件位置更改为src内。
我把 src/ng2/ng1/application.min.js 放在了这里。
从main.ts中导入上述文件(在示例中为src/ng2/ng1/application.min.js)。
§1.4.2 使用webpack作为任务运行器的模式
从main.ts导入ng1的入口文件。
第二部分的Angular设置
请把以后的文件视为符合Angular CLI的规范。
修正 main.ts 文件的 §2.1 部分。
修改main.ts文件。
import 'ng2/ng1/application.min'; // webpackの場合はng1のエントリーファイルを指定
import 'ng2/ng1/downgrade'; // AngularのルートコンポーネントとなるMainComponentをAngularJSに登録しておく
import 'reflect-metadata';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { setAngularLib } from '@angular/upgrade/static';
import * as angular from 'angular';
import { enableProdMode } from '@angular/core';
import { environment } from 'environments/environment';
import { AppModule } from 'ng2/app.module';
if (environment.production) {
enableProdMode();
}
setAngularLib(angular);
platformBrowserDynamic().bootstrapModule(AppModule);
修改AppModule模块的第2.2节。
我将修改AppModule。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule, UrlHandlingStrategy, Router } from '@angular/router';
import { setUpLocationSync } from '@angular/router/upgrade';
import { UpgradeModule } from '@angular/upgrade/static';
import { AppRoutes } from './app.routing';
import { Ng1Ng2UrlHandlingStrategy } from './routing-strategy';
import { MainComponent } from './main/main.component';
@NgModule({
imports: [
BrowserModule,
UpgradeModule,
RouterModule.forRoot(AppRoutes)
],
declarations: [
MainComponent
],
providers: [
{ provide: UrlHandlingStrategy, useClass: Ng1Ng2UrlHandlingStrategy },
],
entryComponents: [ MainComponent ]
})
export class AppModule {
constructor(
private upgrade: UpgradeModule,
private router: Router
) {}
ngDoBootstrap() {
// 'app'はng1でbootstrapに利用していたトップモジュール名に適宜変更しましょう
this.upgrade.bootstrap(document.body, ['app'], { strictDi: true });
setUpLocationSync(this.upgrade);
this.router.initialNavigation(); // これがないと初期表示がされないので注意
}
}
§2.3 Angular 路由器的路由配置
我們會設定 Angular Router 的路由配置。
因為每個 Module1Module 的定義都是在 Angular 的範疇內,所以在這篇文章中將不進行介紹。
你可以按照一般 Angular 的感覺來創建,這是完全沒問題的。
請注意,請暫時不要實現 redirectTo 功能。
import { Routes } from '@angular/router';
export const AppRoutes: Routes = [
{
path: '',
children: [
{
path: '',
loadChildren: 'ng2/modules/dashboard/dashboard.module#DashboardModule'
},
{
path: 'module1',
loadChildren: 'ng2/modules/module1/module1.module#Module1Module'
},
{
path: 'module2',
loadChildren: 'ng2/modules/module2/module2.module#Module2Module'
}
]
}
];
§2.4 Aunglar路由器的路由策略
设置Angular Router的路由策略。
import { UrlHandlingStrategy, UrlTree } from "@angular/router";
export class Ng1Ng2UrlHandlingStrategy implements UrlHandlingStrategy {
shouldProcessUrl(url: UrlTree) {
const str = url.toString();
// 以下にAngular化が終わったモジュールのURLを追記していきます
return str === '/' || // ダッシュボードのURL ※startsWithでやると全てがハンドリングされてしまうので注意
str.startsWith('/module1') || // URLが/module1で始まるモジュールはAngular化完了
str.startsWith('/module2'); // // URLが/module2で始まるモジュールはAngular化完了
}
extract(url) { return url; }
merge(url, whole) { return url; }
}
§2.5 Angular的根组件设置
定义Angular的根组件。
※没有特别需要的内容。
import { Component, OnInit } from "@angular/core";
@Component({
selector: 'app-main',
template: `<router-outlet></router-outlet>`
})
export class MainComponent implements OnInit {
constructor(
) { }
ngOnInit() {
}
}
§2.6 将Angular根组件注册到AngularJS中
将 MainComponent 注册到 AngularJS 中。
在下面的代码中,我们创建了一个新文件 ng2/ng1/downgrade.ts,但如果已经将 AngularJS 转换为 TypeScript,也可以在 AngularJS 中进行配置。
import * as angular from 'angular';
import { downgradeComponent } from '@angular/upgrade/static';
import { MainComponent } from 'ng2/main/main.component';
// AngularJSからもMainComponentを利用できるようにする
angular.module('app')
.directive('appMain', downgradeComponent({ component: MainComponent }));
Angular的设置已经完成。
第3节AngularJS的修复
§3.1 设定转换为Angular的路由设置。
我们将设置AngularJS,以便它可以识别经过Angular化的路由。
angular.module('upgraded.route', ['ui-router'])
.config([
'$stateProvider',
function ($stateProvider) {
$stateProvider
.state({ name: 'dashboard', url: '/', template: '' }) // Angular化したルーティングはAngularJSでは何も表示しないようにする
.state({ name: 'module1', abstract: true })
.state({ name: 'module1.list', url: '/module1/list', template: '' })
.state({ name: 'module1.edit', url: '/module1/edit/:id', template: '' })
... 以後、Angular化完了したルーティングの分だけ追記していきます。
}
]);
设置Angular的根组件§3.2
在HTML中,将(如果使用ngRoute,则为)之后添加。
注意:app-root是AngularJS的根组件,请根据需要进行调整。
...省略
<app-root>
<ui-view></ui-view>
<app-main></app-main>
</app-root>
...省略
以上是AngularJS配置的完成。
如果使用ng build –watch或类似的命令,应该可以成功构建。
如果无法成功,请联系我。
§4 迁移到Angular
一同努力前进吧。
完成Angular化的代码请务必从AngularJS中删除,并不要忘记进行路由设置。
随着Angular化的进展,通过延迟加载带来的初始加载文件大小逐渐减小,感觉很不错。
从看起来简单的部分开始迁移,以掌握感觉的方式可以顺利进行。
第五节 总结
app-root是AngularJS的领域,app-main是Angular的领域。
在ui-view中处理AngularJS的URL,如果是经过Angular化的URL,则不显示任何内容。
在router-outlet中处理经过Angular化的URL,其他情况下不显示任何内容。
通过这样的处理,可以完全将AngularJS的世界和Angular的世界分隔开来。
如果你想在Angular中使用AngularJS的依赖注入,可以参考”Inject angularjs service into Angular”的答案。
如果你想在AngularJS中使用Angular的服务,可以考虑使用downgradeInjectable。
(我都没有使用过其中任何一个)
然而,升级或降级仅限于自身制作的服务或提供者,对于库中已准备好的功能,我们应该直接迁移。
第六节 附录
以下这张幻灯片在使用ngUpgrade时非常有参考价值。
- ngUpgradeと移植戦略