目次
1. はじめに
この記事はクライアントサイド(React)とバックエンド(Express)を利用してパフォーマンスチューニング前後をします。
対象読者はReactとExpressがある程度知ってる前提で話しています。
パフォーマンスチューニング前はあまりにも酷かったのでこれ試行錯誤しながら記事にしたら良い記事になりそうと思って試行錯誤しながら改善を取り組んでみました。なるべく手間を掛けず少し手を加えるだけで改善できる方法を紹介します。
正しくない内容がありましたらコメントなどお願いします。
2. 筆者の環境
- react@^16.5.2
- typescript@^4.1.3
- webpack@^5.52.1
- express@^4.16.3
- docker
- nginx-proxy
- WebARENA Indigo(VPC)
2. パフォーマンスチューニング方法
大雑把に言うと下記の3つです。
- ファイルのサイズ削減
- ネットワーク層の改善
- 必要になったときのロード(動的ロード)
3. パフォーマンスチューニング前
まずパフォーマンスチューニング前のひどい状況を説明します。
PageSpeed Insights
ChromeのデベロッパーツールのNetworkタブ
main.bundle.jsファイルのダウンロードだけで6.60s!?
WebARENAのIndigoだから遅いのもあるけど、全てダウンロードされるまで8秒くらいかかった。。。
Webpackのプロファイル
{ "hash": "9db856a5fe922c949b8b", "version": "5.52.1", "time": 31284, "builtAt": 1635433028355, "publicPath": "auto", "outputPath": "/Users/LeeJunHo/dev/react/medical-information/dist", "assetsByChunkName": { "main": [ "main.css", "./js/main.bundle.js" ] }, "assets": [ { "type": "asset", "name": "./js/main.bundle.js", "size": 2353031, "emitted": true, "comparedForEmit": false, "cached": false, "info": { "javascriptModule": false, "minimized": true, "related": { "license": "./js/main.bundle.js.LICENSE.txt" }, "size": 2353031 }, "chunkNames": [ "main" ], "chunkIdHints": [], "auxiliaryChunkNames": [], "auxiliaryChunkIdHints": [], "filteredRelated": 0, "related": [ { "type": "license", "name": "./js/main.bundle.js.LICENSE.txt", "size": 23963, "emitted": true, "comparedForEmit": false, "cached": false, "info": { "extractedComments": true, "size": 23963 }, "chunkNames": [], "chunkIdHints": [], "auxiliaryChunkNames": [], "auxiliaryChunkIdHints": [], "related": {}, "chunks": [], "auxiliaryChunks": [], "isOverSizeLimit": false } ], "chunks": [ 179 ], "auxiliaryChunks": [], "isOverSizeLimit": true }, ... ... ... ] }
main.bundle.jsのファイルサイズが2353031(2.3mb)
なんでこんなに大きい??
原因分析のためwebpackのプロファイル実行
$ webpack-cli --profile --json > compilation-stats.json
mapbox-gl.jsが一番大きくて外部JSとして扱えないか色々調査してみたけど無理だった。。
他はmaterial-tableに依存していて様子見することにした
3. パフォーマンスチューニング後
PageSpeed Insights
ChromeのデベロッパーツールのNetworkタブ
webpack-bundle-analyzerの結果
4. 改善内容
webpackのパフォーマンスチューニング
/* eslint-disable @typescript-eslint/no-var-requires */ const { merge } = require('webpack-merge'); const common = require('./webpack.common.js'); const webpack = require("webpack") const TerserPlugin = require("terser-webpack-plugin"); const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); const moduleList = ["mapbox-gl", "material-table"]; module.exports = merge(common, { mode: 'production', optimization: { minimize: true, minimizer: [ new TerserPlugin(), new CssMinimizerPlugin(), ], runtimeChunk: 'single', splitChunks: { chunks: 'all', maxInitialRequests: Infinity, minSize: 0, cacheGroups: { vendor: { test: new RegExp( `[\\/]node_modules[\\/](${moduleList.join("|")})[\\/]` ), name: 'vendor', chunks: 'initial', } } }, } });
TerserPlugin: javascriptを最小化するwebpackのプラグイン
CssMinimizerPlugin: cssを最小化するwebpackのプラグイン
splitChunks: ファイルのチャンクを作成する
Loadable Components
一番大きいファイル(mapbox-gl.js)を静的Importしていたのを動的Importに変更することで最初のロード時間を削減