🐕

ゼロランタイムCSSとランタイムCSSって実際どのくらいパフォーマンスに差があるのか[styled-component][Tailwind]

2023/07/18に公開

はじめに

こんにちは、白色です。現在、ベンチャーでフロントエンドエンジニアとして活動しています。
今回が6回目の投稿です。
※今回の記事は特定の状況下での結果を示しているため、異なる条件や環境では結果が異なる場合があります。

課題

  • 社内の技術選定の際にゼロランタイムCSSとランタイムCSSどっちの方がいいのか話題になった。
  • 実際に使用した際に明確に差があるのかを知りたい

ソリューション

  1. ライブラリの選定:
    今回は社内で使用しているstyled-componentと代替候補Tailwind CSSで計測していきたいと思います。

  2. 計測方法:
    Viteを用いて要素を大量に画面に表示し、パフォーマンスを計測しました。

  3. 測定結果の取得方法:
    React Profilerを使用して各ライブラリのを検証しました。

使用コード

https://github.com/fuuki12/zero-vs-runtime-cssinjs-benchmark

App.tsx
// Reactに必要な関数をインポート
import { useState, useCallback, Profiler } from "react";

// カスタムReactコンポーネントのインポート
import { StyledComponent } from "../src/runtime/StyledComponent";
import { TailwindComponent } from "./zeroruntime/TailwindComponent";

// コンポーネントがレンダリングされる度に実行されるコールバック関数
const onRenderCallback: (
  id: string,
  phase: "mount" | "update",
  actualDuration: number
) => void = (id, phase, actualDuration) => {
  console.log(id, phase, actualDuration);
};

export default function App() {

  // 'styled'または'tailwind'ライブラリを記録するためのStateフック
  const [lib, setLib] = useState<"styled" | "tailwind" | null>(null);

  // key値の更新用の状態管理フック(再レンダリングをトリガーする)
  const [key, setKey] = useState(0);

  // StyledComponentを有効化するための関数
  const activateStyled = useCallback(() => {
    setLib("styled");
    setKey((prevKey) => prevKey + 1);
  }, []);

  // TailwindComponentを有効化するための関数
  const activateTailwind = useCallback(() => {
    setLib("tailwind");
    setKey((prevKey) => prevKey + 1);
  }, []);

  return (
    <div>
      {/* ボタンクリックでそれぞれのコンポーネントをアクティヴェイト */}
      <button onClick={activateStyled}>Activate StyledComponent</button>
      <button onClick={activateTailwind}>Activate TailwindComponent</button>

      {/* libの状態に応じて各コンポーネントをレンダリングし、パフォーマンスデータをログに出力 */}
      {lib === "styled" && (
        <Profiler key={key} id="StyledComponent" onRender={onRenderCallback}>
          <StyledComponent />
        </Profiler>
      )}

      {lib === "tailwind" && (
        <Profiler key={key} id="TailwindComponent" onRender={onRenderCallback}>
          <TailwindComponent />
        </Profiler>
      )}
    </div>
  );
}
StyledComponent.tsx
// styled-componentsライブラリのインポート
import styled from "styled-components";

// StyledDivというスタイル付きのdiv要素を作成します。CSSプロパティはバックティック内に直接記述します。
const StyledDiv = styled.div`
  padding: 24px;
  margin: auto;
  max-width: 24rem;
  background-color: white;
  border-radius: 16px;
  box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1);
  display: flex;
  align-items: center;
  justify-content: space-between;
`;

// StyledComponentはReactコンポーネントで、これは大量の段落を持つスタイル化されたdivをレンダリングします
export const StyledComponent = () => {
  return (
    <StyledDiv>
      <div>
        <div style={{ fontSize: "1.25rem", fontWeight: "500" }}>
          Styled Component
        </div>

        {/* Array(100000).mapを使って大量の<p>要素を生成します。 これら各々の要素は固有のキーを持っており、
        各々のテキストは"You are using Styled Components for styling this component."となります。*/}
        {[...Array(100000)].map((_, i) => (
          <p style={{ color: "#71717A" }} key={i}>
            You are using Styled Components for styling this component.
          </p>
        ))}
      </div>
    </StyledDiv>
  );
};

※TailWind CSSも同様のコードで検証を行います。

手順

  • 以下のボタンを押下して、検証を開始する
    ボタンを押下して検証を開始する

  • デベロッパーツール -> consoleを確認して、レンダリング時間を検証する
    Activate StyledComponent押下

Activate TailwindComponentを押下

ベンチマーク結果

上記のボタンの押下した際にレンダリングされた際のStyled-Components と Tailwind CSS のパフォーマンスを比較したベンチマーク結果です。

  • Styled-Components (RRC)

平均実行時間
10,000 要素: 126.85 ms
100,000 要素: 1,332.97 ms

測定結果

10,000 要素:   161.49, 132.69, 118.30, 116.00, 123.09,
                140.99, 107.19, 112.90, 132.39, 135.69

100,000 要素:  1364.29, 1308.90, 1114.29, 1763.89, 1355.69,
               1140.99, 1480.80, 1466.29, 1340.79, 1124.99
  • Tailwind CSS (ZRC)

平均実行時間
10,000 要素: 113.54 ms
100,000 要素: 1,184.39 ms

詳細な測定結果

10,000 要素:  147.00, 96.60, 125.29, 100.50, 102.80,
              121.69, 123.49, 102.00, 121.89, 122.80

100,000 要素: 1026.89, 1041.19, 1220.10, 1204.99, 1339.80,
              1256.10, 1334.49, 1410.60, 1066.19, 1014.69

ベンチマーク結果の考察

  • 上記の結果から、Tailwind CSS が全体的により高速でした。
  • 白色としては、プロジェクトが大きくなるほどこの差が顕著になると感じています。

まとめ

  • パフォーマンスだけをみるとTailwind CSSの方がより良いということがわかりました。
  • 他にも可読性やキャッチアップの難しさ、(Tailwind CSSは書き方が特殊)等あるので他の面でもアプローチしつつ技術選定をしていきたいと思っています。

Discussion