a-blog cmsで使っているJavaScriptのファイルサイズを減量した話
a-blog cmsの主にフロントエンドを担当する堀です。今回はかなりニッチな話をします。a-blog cmsのJavaScriptのサイズを削減した話です。
経緯
a-blog cmsでは、Ver.2.8以降、モダンなフロントエンド開発環境にするべく、WebpackやBabel、Reactなどの整備をスタートしました。同時に独自のモジュールシステムでインポートしていたjsを一部、JavaScriptのimport
文に切り替えたりしました。
Webpackに切り替えたことによってnpmのエコシステムに乗っかり以下のようにフロントエンドの力が試されるリッチな機能を比較的短期間で作れるようになりました。
- 2.8の時は、LiteEditorやナビゲーションモジュール、SmartPhoto、クイックサーチ機能
- 2.9の時にはプレビュー機能、管理メニューのカスタマイズ機能
- 2.10ではメディア機能
ただ、2.10の時期になるとnpm、Webpackに頼りすぎたためその歪みもでてきました。
フロントで使うindex.jsのbundleサイズが52KB(非圧縮時95KB)、管理画面で使うadmin.jsが156KB(非圧縮時 269KB)なのに対し、フロントとindex.jsとadmin.jsが共通で使うvendor.chunk.jsも967KB(非圧縮時2.16MB)ありました。
そのため、CMSにログインしているユーザーの場合だと、画面が開いた時点でだいたい1MB近くのJavaScriptを読み込むことになってしまっていました。
これはパフォーマンス的にも非常によろしくないので、もう少しバンドルサイズを小さくしようという話になりました。
JavaScriptのファイルサイズ削減は画像などのファイルサイズ削減よりも重くパフォーマンスに影響します。ファイルサイズを減らすことによってページがロードされてから動作可能になるまでの時間が削減できます。
どのように削減したか
ではどのように削減したか紹介していきます。
- Webpack Bundle Analyzerの活用
- core-jsの見直し
- dynamic importの積極利用
- CacheGroupの利用
1. Webpack Bundle Analyzerの利用
まずはnpmから利用しているパッケージの何が大きな割合をしめているか把握したかったので WebpackBundleAnalyzerというWebpackのプラグインを利用しました。以下のような結果になりました。このようにvendor.chunk.jsが非圧縮時2MBという結果でした。これはa-blog cmsのフロント画面で、組み込みjsを利用する際、または管理者の場合は必ず読み込まれるJavaScriptなので、まずはこのvendor.chunk.jsで使わないであろうモジュールを削ぎ落として減量する作業が必要でした。
2. core-jsの見直し
まずはこの部分の対策からスタートしました。
core-jsというライブラリで、a-blog cmsはIE11まで対応しているのでこのライブラリの導入がマストでした。 core-jsは、モダンブラウザーでは実装されていて、古いブラウザーだと実装されていないJavaScriptの機能をpolyfillするためのJavaScriptです。
core-jsでは各機能ごとにpolyfillが提供されています。当初はどのpolyfillが使われるのか予想がつかなかったのでcore-jsのすべての機能を読み込んでいました。
ただそれだと必要のないpolyfillまで使われることになるので2.10でみなおしました。
具体的には以下のようにbabel
の設定をみなおし、ソースコード内で使われていて、ターゲットのブラウザにない機能をpolyfillするようにしました。
['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3, targets: { ie: 11, firefox: 30, chrome: 55 }, } ],
babelでは@babel/preset-env
というプリセットを利用すると、useBuiltIns: 'usage'とオプションを指定することで自動で使われている機能だけをPolyfillしてくれます。
useBuiltin: 'usage'は@babel/preset-env
を7.4以上で利用することができます。
その結果、core-js
が実際に必要なモジュール(js)に使用されるようになるので、vendor.chunk.js
からはcore-js
がほとんどなくなりました。
これで非圧縮時のバンドルサイズが1.96MBになりました。
3. dynamic-importの積極利用
dynamic-import
とはJavaScriptを必要なタイミングでJavaScriptから読み込む仕組みです。dynamic-import
を積極的に利用することによってBundleされるファイルにはロード時に本当に必要なモジュールしか読み込まれないためBundleサイズの削減が見込めます。
とくにa-blog cmsの場合は、vendor.chunk.js
に依存モジュールを大量に溜め込んでいたため特に効果がありました。これによりBundleサイズが一気に非圧縮時のバンドルサイズが581KBにまで削減されました。
4. Cache Groupの利用
最後に検討したのがWebpackのCache Group
の導入です。どのモジュールでも共通で使われているモジュールをグループ単位で別のモジュールとして吐き出しておく設定ができます。実際に以下のように、styled-component
prop-types
, react
react-dom`が共通で使われていたのでそれらを抜き出してCache Groupに設定しました。Webpack.config.jsでは以下のように記述しました。
optimization: { splitChunks: { name: 'vendor', chunks: 'initial', cacheGroups: { vendorAdmin: { test: /styled-component|prop-types|react|react-dom/, name: 'vendor-admin', chunks: 'initial', enforce: true } } } },
これでvendor.chunk.jsの中から、react
やreact-dom
、prop-types
などのモジュールを追い出すことができたので最終的にバンドルサイズは213KB(非圧縮時 385KB)になりました。先ほどの画像と見比べてみると、react
やprop-types
などのモジュールがなくなっているのが確認できると思います。
まとめ
今回は特に改善が必要だった vendor.chunk.js に焦点をあてて記事にしましたが、結果的にvendor.chunk.jsは213KBに、index.jsは58KBに、admin.jsも27KBになり、最初に最低限読み込まなければいけないjsが300KB以内に抑えられるようになりました。1MB超→から300kBということで今回の一連の改善はかなりの効果がありました。この改善は a-blog cmsのVer.2.10.18から適応されています。 新機能を開発するのも大事ですがパフォーマンスなどに目を配ることも大事ですね。
Ver.2.10をお使いの皆さんはJavaScriptの改善が見込めますのでぜひバージョンのアップデートをご検討いただけたらと思います。 最後までおつきあいいただきありがとうございました。