🐟

esbuildからUpgradeModuleを起動する

2021/10/11に公開

背景

AngularJSというJavaScriptフレームワークがあります。最新バージョンは1.8です。
Long Term Supportが今年中に切れます[1]

後継フレームワークにAngularがあります。
TypeScriptでの記述、コンポーネント指向の記述など、AngularJSとの相違点は名前が違う程度にはあります。移行パスとして、AngularからAngularJSのngモジュールを使う為の、UpgradeModuleが提供されています[2]

しかし、PhoneCat Upgrade Tutorialに含まれる環境設定手順が不明瞭です。とくにSystemJSに関わる設定ファイルの全文が記載されておりません。環境設定でつまずくことが多いです。

そこで本文ではesbuildを使ってUpgradeModuleを起動する手順を記載します。

本文

AngularJSでの起動を確認

まず最初にAngularJSのまま起動できるか確認してみましょう。

git clone git@github.com:angular/angular-phonecat.git
cd angular-phonecat
npm start

ブラウザが http://localhost:8000 を開くと次のようなページが表示されます。

Angular 12のインストール

Zone.jsのコピー

AngularはZone.jsに依存しています。
ビルド時に結合せずにHTMLファイルから読み込みます。
HTMLファイルで読み込めるディレクトリにコピーを配置しておきます。

npm set-script copy-libs "cpx \"node_modules/{angular,angular-*,bootstrap/dist,jquery/dist,zone.js/bundles}/**/*\" app/lib -C"

Ivy形式への変換

If you are a library author, you should keep using the View Engine compiler as of version 9. [3]

AngularではAngular 9でコンパイラがViewEngineからIvyに変更されました。
後方互換性を考慮して、Angular用のライブラリはView Enigne向けに作り、使う人がngccコマンドを使って、Ivy形式に変換し、使います。
Angular 12もこのルールに従ってView Enigne向けのngモジュールを配布しています。

ngcc用の設定ファイルを追加

tsconfig.json
{
  "compilerOptions": {
    "experimentalDecorators": true
  }
}

postinstallスクリプトでngccを実行

ライブラリーをnpm installしたときに一度だけngccでIvy形式に変更すればよいです。
postinstallスクリプトで変換します。

npm set-script postinstall "npm run copy-libs && ngcc --tsconfig tsconfig.json"

インストール

最新のAngularをインストールします。
執筆時点ではAngular 12がインストールされます。

npm install --save @angular/core @angular/platform-browser @angular/upgrade rxjs tslib typescript zone.js

Angularアプリケーションの追加

srcディレクトリを作成し、その中にAngularアプリケーションを追加します。

app.module.ts

src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

@NgModule({
  imports: [
    BrowserModule,
  ],
})
export class AppModule {
}

app.ts

src/app.ts
import { platformBrowser } from '@angular/platform-browser';
import { AppModule } from './app/app.module';

platformBrowser().bootstrapModule(AppModule);

ビルド

ビルドツールのインストール

npm install -D @angular-devkit/schematics @angular/compiler-cli esbuild tslib typescript

設定ファイルの作成

tsconfig.app.json
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
    "extends": "./tsconfig.base.json",
    "compilerOptions": {
        "outDir": "./out-tsc/app",
        "types": []
    },
    "files": [
        "src/app.ts"
    ],
    "include": [
        "src/**/*.d.ts"
    ]
}
tsconfigbase.json
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
    "compileOnSave": false,
    "compilerOptions": {
        "baseUrl": "./",
        "outDir": "./dist/out-tsc",
        "sourceMap": true,
        "declaration": false,
        "downlevelIteration": true,
        "experimentalDecorators": true,
        "moduleResolution": "node",
        "importHelpers": true,
        "target": "es2015",
        "module": "es2020",
        "lib": [
            "es2018",
            "dom"
        ]
    }
}

ビルドして生成するスクリプトをgitignoreに追加

echo app/app.js >> .gitignore
echo out-tsc >> .gitignore

ビルドスクリプトを追加

npm set-script build "ngc --project tsconfig.app.json && esbuild out-tsc/app/app.js --bundle --outfile=app/app.js"
npm set-script prestart "npm install && npm run build"

npm startを実行すれば、ビルドが成功するはずです。

UpgradeModuleを使ってAngularJSアプリケーションを起動

@angular/upgradeをインストール

npm install -D @angular/upgrade

AngularアプリケーションからAngularJSアプリケーションを起動

app/app.modules.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { UpgradeModule } from '@angular/upgrade/static';

@NgModule({
  imports: [
    BrowserModule,
    UpgradeModule
  ],
})
export class AppModule {
  constructor(private upgrade: UpgradeModule) { }
  ngDoBootstrap() {
    this.upgrade.bootstrap(document.documentElement, ['phonecatApp']);
  }
}

AngularJSの起動をやめる

app/index.htmlからAngularJSを起動するためのキーワードng-app="phonecatApp"を削除します。

zone.jsapp.jsの読込を追加します。
DOMの読込完了後に実行するためにdefer属性をつけることに気をつけて下さい。
defer属性をつけないと、エラーは起きませんが、何も表示されません。

app/index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Google Phone Gallery</title>
    <link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="app.animations.css" />

    <script src="lib/jquery/dist/jquery.js"></script>
    <script src="lib/angular/angular.js"></script>
    <script src="lib/angular-animate/angular-animate.js"></script>
    <script src="lib/angular-resource/angular-resource.js"></script>
    <script src="lib/angular-route/angular-route.js"></script>
    <script src="app.module.js"></script>
    <script src="app.config.js"></script>
    <script src="app.animations.js"></script>
    <script src="core/core.module.js"></script>
    <script src="core/checkmark/checkmark.filter.js"></script>
    <script src="core/phone/phone.module.js"></script>
    <script src="core/phone/phone.service.js"></script>
    <script src="phone-list/phone-list.module.js"></script>
    <script src="phone-list/phone-list.component.js"></script>
    <script src="phone-detail/phone-detail.module.js"></script>
    <script src="phone-detail/phone-detail.component.js"></script>
    <script defer src="lib/zone.js/bundles/zone.umd.js"></script>
    <script defer src="app.js"></script>
  </head>
  <body>

    <div class="view-container">
      <div ng-view class="view-frame"></div>
    </div>

  </body>
</html>

npm startを実行すれば、ハイブリッドアプリケーションの起動が成功します。
ブラウザで http://localhost:8000 を開くと、変更前と全く同じページが表示されます。

ここから先はPhoneCat Upgrade Tutorialの手順に従えば、AngularJSからAngularへのアップグレードを体験できます。

参考資料

https://speakerdeck.com/okunokentaro/ngupgradetoyi-zhi-zhan-lue

https://www.kabuku.co.jp/developers/angularjs-to-angular-ng-upgrade

https://qiita.com/magnet163/items/ff510081e0ffb450b405

https://blog.thoughtram.io/angular/2015/10/24/upgrading-apps-to-angular-2-using-ngupgrade.html

https://github.com/bourey/ngupgrade-example

https://www.digitalocean.com/community/tutorials/how-to-upgrade-from-angularjs-to-angular-with-ngupgrade

https://www.youtube.com/watch?v=anphffaCZrQ

脚注
  1. https://docs.angularjs.org/misc/version-support-status ↩︎

  2. https://angular.io/guide/upgrade ↩︎

  3. https://github.com/angular/angular/blob/master/aio/content/guide/ivy.md#maintaining-library-compatibility ↩︎

Discussion