基于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と移植戦略
广告
将在 10 秒后关闭
bannerAds