変更前
ディレクトリ構成
~/work/portfolio ├── README.md ├── angular.json ├── deploy.sh ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json ├── firebase.json ├── icon_512.png ├── install.sh ├── package-lock.json ├── package.json ├── renovate.json ├── sass-lint.yml ├── src │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── component │ │ │ ├── card │ │ │ │ ├── card.component.html │ │ │ │ ├── card.component.scss │ │ │ │ ├── card.component.spec.ts │ │ │ │ ├── card.component.ts │ │ │ │ ├── card.module.ts │ │ │ │ └── card.ts │ │ │ ├── footer │ │ │ │ ├── footer.component.html │ │ │ │ ├── footer.component.scss │ │ │ │ ├── footer.component.spec.ts │ │ │ │ ├── footer.component.ts │ │ │ │ └── footer.module.ts │ │ │ └── header │ │ │ ├── header.component.html │ │ │ ├── header.component.scss │ │ │ ├── header.component.spec.ts │ │ │ ├── header.component.ts │ │ │ └── header.module.ts │ │ ├── pages │ │ │ ├── about │ │ │ │ ├── about-routing.module.ts │ │ │ │ ├── about.component.html │ │ │ │ ├── about.component.scss │ │ │ │ ├── about.component.spec.ts │ │ │ │ ├── about.component.ts │ │ │ │ ├── about.module.ts │ │ │ │ ├── about.service.spec.ts │ │ │ │ └── about.service.ts │ │ │ ├── community │ │ │ │ ├── community-routing.module.ts │ │ │ │ ├── community.component.html │ │ │ │ ├── community.component.scss │ │ │ │ ├── community.component.spec.ts │ │ │ │ ├── community.component.ts │ │ │ │ └── community.module.ts │ │ │ ├── home │ │ │ │ ├── home-routing.module.ts │ │ │ │ ├── home.component.html │ │ │ │ ├── home.component.scss │ │ │ │ ├── home.component.spec.ts │ │ │ │ ├── home.component.ts │ │ │ │ └── home.module.ts │ │ │ └── page-not-found │ │ │ ├── page-not-found-routing.module.ts │ │ │ ├── page-not-found.component.html │ │ │ ├── page-not-found.component.scss │ │ │ ├── page-not-found.component.spec.ts │ │ │ ├── page-not-found.component.ts │ │ │ └── page-not-found.module.ts │ │ └── shared │ │ └── service │ │ ├── card.service.spec.ts │ │ └── card.service.ts │ ├── assets │ │ ├── i18n │ │ │ ├── en-us.json │ │ │ └── ja.json │ │ ├── imgaes │ │ │ ├── chirimen.png │ │ │ ├── conference.png │ │ │ ├── docswell.png │ │ │ ├── edit.png │ │ │ ├── facebook.png │ │ │ ├── github-logo.png │ │ │ ├── hatenablog-logo.svg │ │ │ ├── icon_128.png │ │ │ ├── mdn.png │ │ │ ├── ng-gunma-logo-plan2.png │ │ │ ├── ng-japan2_full.png │ │ │ ├── slideshare.png │ │ │ └── twitter.png │ │ └── json │ │ ├── card.json │ │ └── community.json │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tips.md ├── tree.txt ├── tsconfig.json └── tslint.json 21 directories, 97 files
pagespeedでのスコア確認
webpack analyzer でのスコア確認
■ 圧縮なし
- All (2.77 MB)
- common.983dfccb34602eca.js (4.34 KB)
- main.182c9c5090b94872.js (2.64 MB)
- polyfills.66c4a90d2e8bcb8c.js (106.28 KB)
- runtime.457c635ab68bf03a.js(2.82 KB)
- 105.4d94d273aa012b92.js(6.81 KB)
- 561.131088f5a5389c24.js (3.29 KB)
- 698.5cdd0d659f30baa9.js (3.06 KB)
- 784.b57f8729eea41541.js (2.2 KB)
■ 圧縮あり
- All (143.03 KB)
- common.983dfccb34602eca.js (1.11 KB)
- main.182c9c5090b94872.js (125.45 KB)
- polyfills.66c4a90d2e8bcb8c.js (11.69 KB)
- runtime.457c635ab68bf03a.js (1.53 KB)
- 105.4d94d273aa012b92.js(1.4 KB)
- 561.131088f5a5389c24.js (723 B)
- 698.5cdd0d659f30baa9.js (703 B)
- 784.b57f8729eea41541.js (478 B)
ビルド時間の確認
$ npm run build > portfolio@0.0.0 build > ng build --configuration production ✔ Browser application bundle generation complete. ✔ Copying assets complete. ✔ Index html generation complete. Initial Chunk Files | Names | Raw Size | Estimated Transfer Size main.182c9c5090b94872.js | main | 425.18 kB | 110.18 kB styles.28eec00e2cd6ca69.css | styles | 126.62 kB | 12.07 kB polyfills.66c4a90d2e8bcb8c.js | polyfills | 33.02 kB | 10.63 kB runtime.457c635ab68bf03a.js | runtime | 2.82 kB | 1.36 kB | Initial Total | 587.64 kB | 134.23 kB Lazy Chunk Files | Names | Raw Size | Estimated Transfer Size 105.4d94d273aa012b92.js | pages-about-about-module | 3.33 kB | 1.21 kB common.983dfccb34602eca.js | common | 2.29 kB | 1003 bytes 561.131088f5a5389c24.js | pages-community-community-module | 1.29 kB | 630 bytes 698.5cdd0d659f30baa9.js | pages-home-home-module | 1.24 kB | 620 bytes 784.b57f8729eea41541.js | pages-page-not-found-page-not-found-module | 865 bytes | 415 bytes Build at: 2023-05-13T07:33:33.584Z - Hash: 044de2ded241b95a - Time: 2461ms $
Standalone Components マイグレーション実行
Standalone Components マイグレーションコマンドを実行
■ 参考記事
Angular アプリケーションを standalone にマイグレーションする - とんかつ時々あんどーなつ
■ ①Convert all components, directives and pipes to standalone
# マイグレーションコマンド $ npx ng generate @angular/core:standalone # マイグレーションモードの選択:Convert all components, directives and pipes to standalone ? Choose the type of migration: Convert all components, directives and pipes to standalone ? Which path in your project should be migrated? ./ 🎉 Automated migration step has finished! 🎉 IMPORTANT! Please verify manually that your application builds and behaves as expected. See https://angular.io/guide/standalone-migration for more information. UPDATE src/app/component/card/card.component.ts (498 bytes) UPDATE src/app/pages/home/home.component.ts (724 bytes) UPDATE src/app/pages/about/about.component.ts (368 bytes) UPDATE src/app/pages/community/community.component.ts (749 bytes) UPDATE src/app/pages/page-not-found/page-not-found.component.ts (327 bytes) UPDATE src/app/component/header/header.component.ts (507 bytes) UPDATE src/app/component/footer/footer.component.ts (297 bytes) UPDATE src/app/component/card/card.module.ts (320 bytes) UPDATE src/app/pages/home/home.module.ts (467 bytes) UPDATE src/app/pages/about/about.module.ts (391 bytes) UPDATE src/app/pages/community/community.module.ts (502 bytes) UPDATE src/app/pages/page-not-found/page-not-found.module.ts (364 bytes) UPDATE src/app/component/header/header.module.ts (520 bytes) UPDATE src/app/component/footer/footer.module.ts (269 bytes) UPDATE src/app/app.component.spec.ts (588 bytes) UPDATE src/app/component/card/card.component.spec.ts (601 bytes) UPDATE src/app/component/footer/footer.component.spec.ts (615 bytes) UPDATE src/app/component/header/header.component.spec.ts (615 bytes) UPDATE src/app/pages/about/about.component.spec.ts (608 bytes) UPDATE src/app/pages/community/community.component.spec.ts (636 bytes) UPDATE src/app/pages/home/home.component.spec.ts (601 bytes) UPDATE src/app/pages/page-not-found/page-not-found.component.spec.ts (659 bytes) $
■ ②Remove unnecessary NgModule classes
# マイグレーションコマンド $ npx ng generate @angular/core:standalone # マイグレーションモードの選択:Remove unnecessary NgModule classes ? Choose the type of migration: Remove unnecessary NgModule classes ? Which path in your project should be migrated? ./ 🎉 Automated migration step has finished! 🎉 IMPORTANT! Please verify manually that your application builds and behaves as expected. See https://angular.io/guide/standalone-migration for more information. DELETE src/app/component/card/card.module.ts DELETE src/app/component/header/header.module.ts DELETE src/app/component/footer/footer.module.ts UPDATE src/app/pages/home/home.module.ts (398 bytes) UPDATE src/app/pages/community/community.module.ts (433 bytes) UPDATE src/app/app.module.ts (645 bytes) $
■ ③Bootstrap the application using standalone APIs
# マイグレーションコマンド $ npx ng generate @angular/core:standalone # マイグレーションモードの選択:Bootstrap the application using standalone APIs ? Choose the type of migration: Bootstrap the application using standalone APIs ? Which path in your project should be migrated? ./ 🎉 Automated migration step has finished! 🎉 IMPORTANT! Please verify manually that your application builds and behaves as expected. See https://angular.io/guide/standalone-migration for more information. DELETE src/app/app.module.ts UPDATE src/main.ts (919 bytes) UPDATE src/app/app.component.ts (318 bytes) UPDATE src/app/app.component.spec.ts (576 bytes) $
■ ④ビルドして、エラー箇所確認
$ npm run build > portfolio@0.0.0 build > ng build --configuration production ✔ Browser application bundle generation complete. Error: src/app/app.component.html:1:1 - error NG8001: 'lw-header' is not a known element: 1. If 'lw-header' is an Angular component, then verify that it is included in the '@Component.imports' of this component. 2. If 'lw-header' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@Component.schemas' of this component to suppress this message. 1 <lw-header></lw-header> ~~~~~~~~~~~ src/app/app.component.ts:6:18 6 templateUrl: './app.component.html', ~~~~~~~~~~~~~~~~~~~~~~ Error occurs in the template of component AppComponent. Error: src/app/app.component.html:3:1 - error NG8001: 'lw-footer' is not a known element: 1. If 'lw-footer' is an Angular component, then verify that it is included in the '@Component.imports' of this component. 2. If 'lw-footer' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@Component.schemas' of this component to suppress this message. 3 <lw-footer></lw-footer> ~~~~~~~~~~~ src/app/app.component.ts:6:18 6 templateUrl: './app.component.html', ~~~~~~~~~~~~~~~~~~~~~~ Error occurs in the template of component AppComponent. $
HeaderComponent, FooterComponent を AppComponent にインポートして修正完了
■ ⑤エラー箇所を修正後、再ビルド
$ npm run build > portfolio@0.0.0 build > ng build --configuration production ✔ Browser application bundle generation complete. ✔ Copying assets complete. ✔ Index html generation complete. Initial Chunk Files | Names | Raw Size | Estimated Transfer Size main.cf3355b77227c992.js | main | 422.79 kB | 109.77 kB styles.28eec00e2cd6ca69.css | styles | 126.62 kB | 12.07 kB polyfills.66c4a90d2e8bcb8c.js | polyfills | 33.02 kB | 10.63 kB runtime.c44cd13664e05a20.js | runtime | 2.82 kB | 1.35 kB | Initial Total | 585.24 kB | 133.82 kB Lazy Chunk Files | Names | Raw Size | Estimated Transfer Size 105.163cd318093059b1.js | pages-about-about-module | 3.36 kB | 1.21 kB common.f2d02f200b7b8184.js | common | 2.10 kB | 945 bytes 561.5cac99a41495d522.js | pages-community-community-module | 1.30 kB | 649 bytes 698.d7ae0864dbc82789.js | pages-home-home-module | 1.25 kB | 628 bytes 784.57c81b8e75c4007d.js | pages-page-not-found-page-not-found-module | 896 bytes | 430 bytes Build at: 2023-05-13T09:15:04.219Z - Hash: a1f6ba84e01aeaf5 - Time: 2449ms $
■ ⑥ローカルで挙動確認
変更後
ディレクトリ構成
~/work/portfolio ├── README.md ├── angular.json ├── deploy.sh ├── e2e │ ├── protractor.conf.js │ ├── src │ │ ├── app.e2e-spec.ts │ │ └── app.po.ts │ └── tsconfig.e2e.json ├── firebase.json ├── icon_512.png ├── install.sh ├── package-lock.json ├── package.json ├── renovate.json ├── sass-lint.yml ├── src │ ├── app │ │ ├── app-routing.module.ts # 要手動修正 │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── component │ │ │ ├── card │ │ │ │ ├── card.component.html │ │ │ │ ├── card.component.scss │ │ │ │ ├── card.component.spec.ts │ │ │ │ ├── card.component.ts │ │ │ │ └── card.ts │ │ │ ├── footer │ │ │ │ ├── footer.component.html │ │ │ │ ├── footer.component.scss │ │ │ │ ├── footer.component.spec.ts │ │ │ │ └── footer.component.ts │ │ │ └── header │ │ │ ├── header.component.html │ │ │ ├── header.component.scss │ │ │ ├── header.component.spec.ts │ │ │ └── header.component.ts │ │ ├── pages │ │ │ ├── about │ │ │ │ ├── about-routing.module.ts # 要手動修正 │ │ │ │ ├── about.component.html │ │ │ │ ├── about.component.scss │ │ │ │ ├── about.component.spec.ts │ │ │ │ ├── about.component.ts │ │ │ │ ├── about.module.ts # 要手動修正 │ │ │ │ ├── about.service.spec.ts │ │ │ │ └── about.service.ts │ │ │ ├── community │ │ │ │ ├── community-routing.module.ts # 要手動修正 │ │ │ │ ├── community.component.html │ │ │ │ ├── community.component.scss │ │ │ │ ├── community.component.spec.ts │ │ │ │ ├── community.component.ts │ │ │ │ └── community.module.ts # 要手動修正 │ │ │ ├── home │ │ │ │ ├── home-routing.module.ts # 要手動修正 │ │ │ │ ├── home.component.html │ │ │ │ ├── home.component.scss │ │ │ │ ├── home.component.spec.ts │ │ │ │ ├── home.component.ts │ │ │ │ └── home.module.ts # 要手動修正 │ │ │ └── page-not-found │ │ │ ├── page-not-found-routing.module.ts # 要手動修正 │ │ │ ├── page-not-found.component.html │ │ │ ├── page-not-found.component.scss │ │ │ ├── page-not-found.component.spec.ts │ │ │ ├── page-not-found.component.ts │ │ │ └── page-not-found.module.ts # 要手動修正 │ │ └── shared │ │ └── service │ │ ├── card.service.spec.ts │ │ └── card.service.ts │ ├── assets │ │ ├── i18n │ │ │ ├── en-us.json │ │ │ └── ja.json │ │ ├── imgaes │ │ │ ├── chirimen.png │ │ │ ├── conference.png │ │ │ ├── docswell.png │ │ │ ├── edit.png │ │ │ ├── facebook.png │ │ │ ├── github-logo.png │ │ │ ├── hatenablog-logo.svg │ │ │ ├── icon_128.png │ │ │ ├── mdn.png │ │ │ ├── ng-gunma-logo-plan2.png │ │ │ ├── ng-japan2_full.png │ │ │ ├── slideshare.png │ │ │ └── twitter.png │ │ └── json │ │ ├── card.json │ │ └── community.json │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tips.md ├── tree.txt ├── tsconfig.json └── tslint.json 14969 directories, 140600 files
pagespeedでのスコア確認
webpack analyzer でのスコア確認
■ 圧縮なし
- All (2.76 MB)
- common.f2d02f200b7b8184.js (3.89 KB)
- main.cf3355b77227c992.js (2.64 MB)
- polyfills.66c4a90d2e8bcb8c.js (106.28 KB)
- runtime.c44cd13664e05a20.js(2.82 KB)
- 105.163cd318093059b1.js (6.88 KB)
- 561.5cac99a41495d522.js (3.3 KB)
- 698.d7ae0864dbc82789.js (3.06 KB)
- 784.57c81b8e75c4007d.js (2.26 KB)
■ 圧縮あり
- All (142.56 KB)
- common.f2d02f200b7b8184.js (1.05 KB)
- main.cf3355b77227c992.js (124.96 KB)
- polyfills.66c4a90d2e8bcb8c.js (11.69 KB)
- runtime.c44cd13664e05a20.js(1.53 KB)
- 105.163cd318093059b1.js (1.43 KB)
- 561.5cac99a41495d522.js (740 B)
- 698.d7ae0864dbc82789.js (716 B)
- 784.57c81b8e75c4007d.js (499 B)
ビルド時間の確認
$ npm run build > portfolio@0.0.0 build > ng build --configuration production ✔ Browser application bundle generation complete. ✔ Copying assets complete. ✔ Index html generation complete. Initial Chunk Files | Names | Raw Size | Estimated Transfer Size main.cf3355b77227c992.js | main | 422.79 kB | 109.77 kB styles.28eec00e2cd6ca69.css | styles | 126.62 kB | 12.07 kB polyfills.66c4a90d2e8bcb8c.js | polyfills | 33.02 kB | 10.63 kB runtime.c44cd13664e05a20.js | runtime | 2.82 kB | 1.35 kB | Initial Total | 585.24 kB | 133.82 kB Lazy Chunk Files | Names | Raw Size | Estimated Transfer Size 105.163cd318093059b1.js | pages-about-about-module | 3.36 kB | 1.21 kB common.f2d02f200b7b8184.js | common | 2.10 kB | 945 bytes 561.5cac99a41495d522.js | pages-community-community-module | 1.30 kB | 649 bytes 698.d7ae0864dbc82789.js | pages-home-home-module | 1.25 kB | 628 bytes 784.57c81b8e75c4007d.js | pages-page-not-found-page-not-found-module | 896 bytes | 430 bytes Build at: 2023-05-13T09:15:04.219Z - Hash: a1f6ba84e01aeaf5 - Time: 2449ms $
比較
■ 圧縮なし
ファイル名 | 変更前 | 変更後 | 差分 | 単位 |
---|---|---|---|---|
All | 2.77 | 2.76 | 0.01 | MB |
common.*****.js | 4.34 | 3.89 | 0.45 | KB |
main.******.js | 2.64 | 2.64 | 0 | MB |
polyfills.*****.js | 106.28 | 106.28 | 0 | KB |
runtime.****.js | 2.82 | 2.82 | 0 | KB |
105.*****.js | 6.81 | 6.88 | -0.07 | KB |
561.*****.js | 3.29 | 3.3 | -0.01 | KB |
698.*****.js | 3.06 | 3.06 | 0 | KB |
784.*****.js | 2.2 | 2.26 | -0.06 | KB |
■ 圧縮あり
ファイル名 | 変更前 | 変更後 | 差分 | 単位 |
---|---|---|---|---|
All | 143.03 | 142.56 | 0.47 | KB |
common.*****.js | 1.11 | 1.05 | 0.06 | KB |
main.******.js | 125.45 | 124.96 | 0.49 | KB |
polyfills.*****.js | 11.69 | 11.69 | 0 | KB |
runtime.****.js | 1.53 | 1.53 | 0 | KB |
105.*****.js | 1.4 | 1.43 | -0.03 | KB |
561.*****.js | 723 | 740 | -17 | B |
698.*****.js | 703 | 716 | -13 | B |
784.*****.js | 478 | 499 | -21 | B |
■ ビルド時間
変更前(ms) | 変更後(ms) | 差(ms) |
---|---|---|
2461 | 2449 | 12 |
まとめ
- 小規模アプリケーションなら、Standalone Components へのマイグレーションなら比較的容易です。
- 小規模なので、パフォーマンスで劇的な差を確認できませんでした。
- バンドルサイズも誤差の範疇でした。
- ビルド時間はごく僅かですが、早くなりました。
- xxxxx.module.ts や xxxxx-routing.module.ts は、
個別に
修正する必要があります。 - ブランチを作成して、早めに Standalone Components へのマイグレーションをしてみる事をお勧めします。
- ただ闇雲に実施するのではなく、計画や範囲を決めて着手すると良いと思います。
謝辞
@kasaharu さんの下記記事のおかげで、困ることなくマイグレーション出来ました。
有難うございました。