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
webpack-bundle-analyzer結果

mapbox-gl.jsが一番大きくて外部JSとして扱えないか色々調査してみたけど無理だった。。

他はmaterial-tableに依存していて様子見することにした

 

3. パフォーマンスチューニング後

PageSpeed Insights

 

 

ChromeのデベロッパーツールのNetworkタブ

 

jsのファイルチャンクが並列ダウンロードされて8000ms → 1400msまで改善成功

webpack-bundle-analyzerの結果

main.bundle.jsをさらに分割してチャックファイルが増えたけど、これで並列ダウンロードが可能になった

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に変更することで最初のロード時間を削減