Code-Splittingで初期ロード段階を最適

本記事ではコード分割（Code-Splitting）でフロントエンド最適とのことを説明させていただきます。


# 結論
Single Page Application（SPA）の仕組みとは、初めてWebAppにアクセスすると、重いJSファイルを読み込んでから、ユーザブラウザ自体でHTML生成したりDOMを作成したりする処理を行います。

___メリット___
____即時反映　（初期時点以外）____
画面遷移それともUI変更され場合は、API叩いて、（HTML,CSS,JSを含まない）最新なデータをUIに入れます。


__デメリット__
__初期時点アクセスでは所要時間がかかります__
TOPページにアクセスしますが、TOP以外のものを読み込んでからTOPページ表示します。


__実践でCode-Splitting応用__

+ Navigationケースであり、ルートコンポーネントに重い各ページを遅延読み込み
+ ページの内に一部重いUIがあって、読み込でいる時に一応「読み込み中のUI」表示


##### Code Splitting 利用しない

![Screenshot 2025-01-29 at 16.08.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/e31c8bce-fefd-cc02-69bf-df29c0bfe370.png)

___課題___
+ 重い```Base６４```で送信時間がかかる
+ ```RenderHeavyComponent```でUI生成時間がかかる
従って、お待ち時間がかかってユーザー体験が下がります


##### Code Splitting 利用
![Screenshot 2025-01-29 at 16.13.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/26d09397-85df-02f8-3529-6e6e0b00fba0.png)
 
___解決___
+ 軽いものを先に表示
+ 重いものに対して一応「読み込み中」を表示して、段々表示


# 深く理解

Vue, AngluarとのフロントエンドライブラにもCode-Spilitingがありますが、本記事では下記のReactで深く説明します。

### 利用しない
#### 模擬コード

```jsx
import React from "react";
import ComponentA from "./ComponentA";
import ComponentB from "./ComponentB";
import ComponentC from "./ComponentC";
import Base64 from "./Base64";
import RenderHeavyComponent from "./RenderHeavyComponent";
function App() {
  return (
    <>
      <ComponentA />
      <ComponentB />
      <ComponentC />
      <Base64 />
      <RenderHeavyComponent />
    </>
  );
}
export default App;
```
_```<Base64 />```と ```<RenderHeavyComponent />```は詳細が下の「その他」にあります。_

#### ビルド段階
```npm run build ```

##### 結果

![Screenshot 2025-01-29 at 16.33.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/6eb44d75-faed-9546-41f2-9c06d26899e6.png)
![Screenshot 2025-01-29 at 16.35.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/b4bf1fd5-2ddb-73cd-949b-0acd8a63b712.png)


```build/static/js/```配下にJSファイルが１つのみ出ました。サイズは4.63MBほどです。
#### 読み込み段階
```serve -s build```を行って、サーバー立ち上げます。

_ブラウザー制限_
+ Disable Cached
+ Network速度：Fast 4G

![ScreenRecording2025-01-29at16.40.55-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/22642ddf-fa51-aed9-16d3-bc2994b7c6b9.gif)


![Screenshot 2025-01-29 at 16.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/378267c4-57de-7ac6-4e1b-df2e9682e4f4.png)

```main.bbad9597.js```が4.6MBであり、ダウンロードとUI生成の時間が5秒ほどです。

→　ユーザが5秒を待たせます。

### 利用する

#### 模擬コード
__解説__
* ```const ComponentA = React.lazy(() => import("./ComponentA"));```とはReactの延長インポート
* ```<React.Suspense>```とはHOCです。こちらは重いコンポーネントを包み
    * ```fallback```とは、読み込み中の時に指摘されるコンポーネントを表示



__コード__
```jsx
import React from "react";
const ComponentA = React.lazy(() => import("./ComponentA"));
const ComponentB = React.lazy(() => import("./ComponentB"));
const ComponentC = React.lazy(() => import("./ComponentC"));
const RenderHeavyComponent = React.lazy(() => import("./RenderHeavyComponent"));
const Base64 = React.lazy(() => import("./Base64"));
function App() {
  return (
    <>
      <ComponentA />
      <ComponentB />
      <ComponentC />
      <React.Suspense
        fallback={
          <div>
            <h1> LOADING Base64............</h1>
          </div>
        }
      >
        <Base64 />
      </React.Suspense>
      <React.Suspense
        fallback={
          <div>
            <h1> LOADING.........</h1>
          </div>
        }
      >
        <RenderHeavyComponent />
      </React.Suspense>
    </>
  );
}
export default App;
```

#### ビルド段階
```npm run build ```

##### 結果
![Screenshot 2025-01-29 at 17.28.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/ef273824-e6da-4310-42c8-96318a3ceb24.png)
![Screenshot 2025-01-29 at 17.28.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/35781e39-15a4-24a1-ddda-272b2f29a886.png)


６ファイルに分けています
##### 読み込み段階
```serve -s build```を行って、サーバー立ち上げます。

_ブラウザー制限_
+ Disable Cached
+ Network速度：Fast 4G

![ScreenRecording2025-01-29at17.29.26-ezgif.com-video-to-gif-converter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/0922fca2-3e07-e512-ef5c-9188b95f802a.gif)
![Screenshot 2025-01-29 at 17.31.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/b2cd8b04-d86e-be2e-05e4-b23133c6049f.png)

+ 200msほぼ軽いUIを表示
+ ```RenderHeavyComponent```がUI生成中の時に、一応「 LOADING.........」を表示
+ 重い```Base64Component```が5秒ほどダウンロードとUI生成を完了して表示。そして、処理中の時に、「LOADING Base64............」を一旦表示します。



# 実践でCode-Splitingを利用

### おもいコンテンツを表示
![Screenshot 2025-01-29 at 17.42.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703979/690458b2-89d8-4021-90c1-bf75a3ad581f.png)
ヘッダーとメニューとフーターが軽いコンポーネントで表示します。重いコンテンツに読み込みの時に、スプリンターとか一旦表示して、処理が完了してからコンテンツを表示します。そのためUIUXが改善

### Navigation
Root.jsで以下のようにRouting設定します。

問題としては、```/home```に入る時には、```/users```そてとも```/about``` ページを表示しませんが、結構重くて、取得されます。したらがって、```home```ページ表示速度に悪い影響を与えます。Code Splitting でこちら問題を解決できます。

その他、最新なNavigating LibraryにもCode Splittingが既に対応しています。

```jsx
import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

export default function App() {
  return (
    <Router>
        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/users">
            <Users />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
    </Router>
  );
}
```





# その他

上記のコンポーネントがこちら

```jsx

//Divを10000個表示
function RenderHeavyComponent() {
  const [data] = useState(() => {
    const arrays = [];
    for (let index = 0; index < 10000; index++) {
      arrays.push(index);
    }
    return arrays;
  });
  return (
    <div styles={"background-color: green;"}>
      Render Heavy Component
      {data.map((dt, idx) => (
        <div key={idx}>{dt}</div>
      ))}
    </div>
  );
}


//４MBほどの重いコンポネート作成するため、Base64 source ImgにRawエンコードを入れる
function Base64() {
  return (
   <div>
    <h4>Base64</h4>
    <img height={500} width={500} src={`
    base 64 endcode here.. ~4MB
    `}/>
   </div>
  )
    }
```


# 参考
https://legacy.reactjs.org/docs/code-splitting.html
https://developer.mozilla.org/ja/docs/Glossary/Code_splitting
https://react.dev/reference/react/Suspense