【Node.js】bundleサイズは大事って話


サービスの動作が遅かった

最近,アーチャー伝説ってスマホアプリ専用の【マルチ募集掲示板サービス】をリリースしました.

技術としては,Node.js/React/TypeScript/Express/Webpackを使用しました.このサービス,募集スレッドのリアルタイム更新をアピールしてるんですが,その肝心のbundle.jsが動き出すのが遅いんですよね.

そこでSSR(Server Side Rendering)について調べてたらこんなサイトが出てきて,めっちゃわかりやすいやんけ!と.要するにNode.jsってすごいし早いけど,やっぱSSRしない方が動作は早いよねと.でもSEOの観点とUX考慮するとまあSSRした方がいいよねと.

そこで重要になるのがjsの読み込み速度.今回Webpackを使ってるのでここをなんとかせねば!Webpackってjs全部ひとまとめにしてくれてめちゃくちゃ便利な反面,そのbundleされたjsファイルに対して何もしなかったらかなり重いんです.

bundle.jsを小さくするために!

今回ReactのMaterial-UI使ってたり,Express.js使ってたりと,小さく出来そうなとこはいろいろありそうでした.サイズ小さくするために,ちょっとめんどくさい書き方になったりしますが,これはユーザビリティ考えると致し方ありませんね.ちなみに下の画像がなーんにも手を加えずbundleしてた時のサイズ.1.29Mbもあります.(BundleAnalyzerPluginって神様)ちなみにこれjs読み終わるのに10秒くらいかかってました....

で,この中でも,Material-UIが997Kb...これだけでbundle.js全体の8割弱占めてる...Material-UI使う時は必ず注意すべきですね

ささ,bundleサイズ小さくしていきましょうか.

Express.js

import compression from 'compression';
app.use(compression());

これだけでbundle.jsをgzipで圧縮してくれるんです.便利すぎて笑

Material-UI

//Good
import AppBar from '@material-ui/core/AppBar';
//Bad
import { AppBar } from '@material-ui/core';

上のように書き換えます.それだけです.僕の場合は多い時は1コンポーネントに10個ほどモジュールをimportしてたので,かなりめんどくさい...下の書き方だったら一行でほとんどimportできますから.
で,なぜ下はダメなのか.これ直接node_modulesディレクトリから探せば一目瞭然ですが,下の場合だと@material-ui/core全部インストールしてきてそっからAppBarを探すんですよね.そりゃ容量食いますね.

CSS

const sheets = new ServerStyleSheets();
renderToString(
  sheets.collect(
    React.createElement(component)
  )
);
const css = (sheets.toString()).replace(/\s+/g, "");

僕の場合はMaterial-UIで使われるcssもSSRでテンプレートエンジン(pug)に渡す必要があったので,cssを文字列で渡すんですよね.で,cssとかjsの読み込みに空白とか改行,コメントが入ってたらそれまた遅くなります.なのでここではスペースを全て削除することでcssを圧縮しました.

bundleサイズのビフォーアフター

bundleサイズ438Kb!

Material-UIも258Kbに!

結果,800Kb以上圧縮できましたね!6.5割程削減できたのかな?

【マルチ募集掲示板サービス】の読み込みもだいぶ早くなりました!ストレスは感じないですね!Lighthouseで測定したら,Performanceが60点台から96点になりました!!

アクセシビリティも改善したいのですが,サードパーティコードの影響を削減ってよくわからなくてわからないです....このサイトによるとNode.jsってサーバのメインループをブロックするらしくて,そのことかなと思うのですが...誰か教えていただけると幸いです!

まとめ

Webpackとかでbundleしたり,いろんなモジュール使うならサイズ小さくしようってことです!