dynamic importでのページ分割+CSSファイル分割したら読み込みパフォーマンスが3倍改善した話
かなり前のお話(2020年ほど)で初歩的な内容ですが、備忘録として残しておこうと思います。
経緯
アプリケーション開発においてパフォーマンスは切っても切れない関係です。
あるあるだと思いますが、開発が進んで機能が増えてくるとファイルサイズが増えてきませんか?
私のプロジェクトでは機能とページ数が増えてきた際に、お客様から「表示が遅い」「画面遷移が遅い」とクレームをいただくことがありました。
スタートアップのWEBアプリということもあり、これまでパフォーマンスに手をつけてこなかったことから、満足度低下を防ぐ意味でも改善に踏み切ることにしました。
環境
言語:javascript
ライブラリ:React、React Router
バンドラー:webpack5
ミニマイザー:Minimize Extra Css
...etc
原因
インフラは十分なスペックだったこと。
developerToolで確認したところjsの読み込みが遅いことからファイルサイズが重たいことが原因だと気づきました。
CSSファイル&ページファイルごとに分けずにまとめたものをコンパイルしていたので、まずはページごとにコンパイルを分けることを対策として進めることにしました。
ググってでてきたのが dynamic import(以下di) と CssMinimizerWebpackPlugin で、早速取り掛かりました。
構成
実際のファイル内は見せられないので、適当に作ったものです。
import Page1 from "./components/Page1"
import Page2 from "./components/Page2"
import Page3 from "./components/Page3"
const App = () => {
return (
<div className="App">
<BrowserRouter>
<CookiesProvider>
<Switch>
<Route exact path="/" component={Page1}/>
<Route path="/tekitou1" component={Page2}/>
<Route path="/tekitou2" component={Page3}/>
</Switch>
</CookiesProvider>
</BrowserRouter>
</div>
)
}
import Page1 from "./components/Page1"
const Page1 = React.lazy(() => import(/* webpackChunkName: "Page1" */ "./components/Page1"))
const Page2 = React.lazy(() => import(/* webpackChunkName: "Page2" */ "./components/Page2"))
const Page3 = React.lazy(() => import(/* webpackChunkName: "Page3" */ "./components/Page3"))
const App = () => {
return (
<div className="App">
<BrowserRouter>
<CookiesProvider>
<Switch>
<Route exact path="/">
<React.Suspense fallback="...">
<Page1 />
</React.Suspense>
</Route>
<Route exact path="/tekitou1">
<React.Suspense fallback="...">
<Page2 />
</React.Suspense>
</Route>
<Route exact path="/tekitou2">
<React.Suspense fallback="...">
<Page3 />
</React.Suspense>
</Route>
</Switch>
</CookiesProvider>
</BrowserRouter>
</div>
)
}
module.exports =
{
entry: {
compiledApp: './src/index.js',
},
output: {
filename: (chunkData) => { return 'js/[name].js';},
path: path.join(__dirname, 'public'),
publicPath: "/", // di導入前はなし
chunkFilename: 'js/chunk/[name].js' // di導入前はなし
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/XXXXX.css', // CSSのミニマイズ設定
}),
],
optimization: {
chunkIds: 'named',
minimize: true,
minimizer: [
new CssMinimizerWebpackPlugin(), // CSSのミニマイズ設定
],
}
// packge.jsonには "@babel/plugin-syntax-dynamic-import" を追加しました。
効果
これで何が変わったかは以下の通りになります。
アプリケーションの動きや構成
- コンパイルしたファイルサイズが分割されたため、1つ1つのサイズが小さくなった
- ページ単位で該当ページのファイルを読み込むようになった
- CSSが分割&小さくなった
パフォーマンス
Google Developper Toolsの中にあるNetworkタブや、LightHouseを持ちいて計測したところ
読み込み速度が 約3倍早く なりました
リリース前 リリース後
3秒 → 1秒
※当時測ったLightHouseのデータを載せれたら良かったのですが見つかりませんでした…
後書き
このリリース後にお客さまからは「早くなって大変助かりました」とフィードバックの声があり、改めてパフォーマンス改善の大切さに気付かされました。
やって当然でしょ!って思われる方は多いと思いますが、経験や知見がないと失念しがちですよね。
今後もパフォーマンスに気をつけながら開発していきます。(教訓)
もっといい方法あるよ!と知見をお持ちの方、教えていただけると全私が助かります。