こんにちは。ぬこすけ です。
随分前なのですが、 React で手軽にサイトを高速化できるライブラリ react-dom-lazyload-component
を作って公開しました。
ふと、「本当に サイト高速化の効果があるのか? 」と思い、自作サイトに react-dom-lazyload-component
を使ってみました。
自作ライブラリが本当にサイト高速化に役立つのか、検証したいと思います。
react-dom-lazyload-component
ってどんなライブラリ?
ブラウザの決まった枠内に入るまで DOM を非表示にするライブラリです 。
IntersectionObserver
というブラウザ API をご存知の方はピンと来るかもしれません。
上の画像のように、 Viewport という領域があります。
Viewport という領域は自分で調整できますが、一旦、ユーザーが開いているブラウザの表示領域だと思ってください。
ユーザーがブラウザをスクロールしていき、赤い四角の「 Visible!! 」のように対象の DOM が Viewport に入ると DOM が描画されます。
一方で Viewport 外の DOM はグレー四角の「 Invisible 」のように DOM は描画されません。
こうすることで 必要なタイミングで必要な UI だけ描画 されるようになり、 サイトの表示高速化 が期待されます。
特に、 必要なタイミングで UI 描画に必要なリソース( JavaScript など)を取得 するようにすれば 初期描画の高速化 もできます。
自作したサイトってどんなサイト?
この react-dom-lazyload-component
の実験台の対象となるのは「 Instagram Hashtag Translator 」 というサイトです。
どんなサイトかいうと、 インスタグラムの投稿で外国語でハッシュタグをつけたい時に、インスタグラム向けにハッシュタグを翻訳し、コピペして投稿できるようにするツール です。
例えば、「猫 カフェ」で英語も含めてハッシュタグを用意したい場合は、「#猫 #カフェ #cat #cafe」という形でアウトプットを出してくれます。
企画の背景や技術スタックなど、詳しい話は Qiita の記事 でまとめているので、ご興味あればご覧ください。
いざ、検証!の前に
自作ライブラリを使ってどのくらいサイト高速化できるか検証する前に、Instagram Hashtag Translator の簡単な前提条件を確認しておきましょう。
- 使っている主なライブラリとバージョン
- React v18.2.0
- Next.js v13.0.3
-
app
Directory といった v13 の最新機能は使っていません。
-
- インフラ
- Vercel
また、 react-dom-lazyload-component
の導入前の PageSpeed Insights の実行結果は次の通りです。
遅い!笑
ここからどのくらい高速化するのか、見ていきましょう!
react-dom-lazyload-component
を使った実装
どのように実装していくかも触れておきます。
次のような react-dom-lazyload-component
をラップしたコンポーネントを用意します。
import { FC, ReactNode } from 'react';
import LazyLoad, { LazyLoadProps } from 'react-dom-lazyload-component';
import LoadingIcon from '~/components/atoms/icons/LoadingIcon';
type LazyProps = Pick<LazyLoadProps, 'as' | 'suspense'> & {
readonly className?: string;
readonly children: ReactNode;
readonly id?: string;
};
const Lazy: FC<LazyProps> = ({ className, children, as, suspense, id }) => (
<LazyLoad
className={className}
as={as} // div や span など使いたいタグ名。
fallback={<LoadingIcon />} // Viewport 外で表示する UI と React.Suspense の fallback
suspense={suspense} // React.Suspense を使うかどうか
id={id} // DOM の id
>
{children}
</LazyLoad>
);
export default Lazy;
この Lazy
コンポーネントはブラウザの表示領域に入るまで LoadingIcon
という読み込み中の UI を表示し、表示領域に入ると children
を表示させます。
Lazy
を使う側として、ユーザーのファーストビューで表示されないフッターのコンポーネント例をあげます。
import dynamic from 'next/dynamic';
import { FC } from 'react';
import Lazy from '~/components/atoms/Lazy';
const Copyright = dynamic(() => import('~/components/atoms/Copyright'), {
suspense: true,
});
const Footer: FC = (): JSX.Element => (
<Lazy
className='クラス名入れる'
as='footer'
suspense
>
<Copyright />
</Lazy>
);
export default Footer;
この Footer
コンポーネントはブラウザの表示領域に入った瞬間に表示されます。
1つポイントとしては next/dynamic を使ってコンポーネントの遅延読み込み をしている点です。
このようにすることで、Footer
コンポーネントがブラウザの表示領域に入った時に初めて Copyright
コンポーネントが読み込まれるため、 初期描画が早くなるメリット があります。
next/dynamic
を使った例ですが、 React.lazy
を使っても良いでしょう。
このフッターのようにユーザーのファーストビューで表示されないコンポーネントを react-dom-lazyload-component
と next/dynamic
を組み合わせて修正をしていきます。
react-dom-lazyload-component
を使った結果
PageSpeed Insights の結果はこうなりました!
PC は 39 → 70 に爆上がりしました 。良さげです🥳。
「読み込み中」の UI ( LoadingIcon
) で高さを指定をしていないので、「 Cumulative Layout Shift 」 は上がっちゃいました😜。
モバイルは 34 → 45 なのでスコア的にはそこまでアップしていませんが、 「 First Contenful Paint 」 や 「 Speed Index 」などの各指標が 4 ~ 5 倍ほど改善 されています。
これもまた良さげです🥳。
まとめ
自分で作ったサイト「 Instagram Hashtag Translator 」 を、これもまた自分で作ったライブラリ「 react-dom-lazyload-component 」を使ってサイトを高速化するお話でした。
ぜひ react-dom-lazyload-component
を使ってみてください!
もしバグや使い方がわからない場合は日本語でも OK なので、 Github の issue なりにコメントいただければと思います!
今回は React のパフォーマンス改善例でしたが、フロントエンド全般のパフォーマンス改善のハウツーをまとめた記事もあるので、こちらもご参考にしていただければと思います!
最後に Twitter もやっているのでぜひフォローください!
ここまでご覧いただきありがとうございました!