본문 바로가기

React/실험실

[React] Code Splitting

0. 들어가면서

webpack과 babel을 통해서 만든 프로젝트에 Code Splitting을 공부하기 위해서 추가로 작업한 것이다. 

 

1. Code Splitting?

우리가 일반적으로 yarn build을 사용하면 하나의 번들 파일이 만들어진다. 

 

프로젝트의 규모가 커지면서 번들 파일도 같이 점점 커지게 된다. 

크기가 커진 번들 파일을 화면에 로드하는 경우 시간이 걸어지는 결과가 발생한다. 

 

즉, 사용자가 느끼는 서비스의 만족도가 낮아지게 된다

 

이때, 하나의 번들 파일을 여러 개의 번들 파일로 나누는 것이 Code Splitting이다. 

 

여러 개의 번들 파일로 나누어서 실제 로드가 될 화면에 필요한 번들 파일만 불러오고 나머지 번들 파일은 호출하지 

않고 필요할 때 호출하면서 더 빠른 속도로 화면에 보이게 된다. 

 

2. Code Splitting 적용하기 

Dynamic import 

React.lazy를 이용하여서 Code Spliiting이 가능하다. 

 

import React from "react";
import { Route, Routes, Link } from "react-router-dom";
import FirstComponent from "./components/FirstComponent";
import SecondComponent from "./components/SecondComponent";

const App = ({}) => {
  return (
    <>
      <div>
        <p>
          <Link to="/">Go First</Link>
        </p>
        <p>
          <Link to="/Second">Go Second</Link>
        </p>
      </div>

      <Routes>
        <Route exact path="/" element={<FirstComponent />} />
        <Route exact path="/Second" element={<SecondComponent />} />
      </Routes>
    </>
  );
};

export default App;

간단하게 Router를 이용해서 Url에 따라서 경로가 나타나게 설정하였다. 

build를 할 경우 하나의 main.js가 만들어진다. 

 

1. 번들 파일 분리시키기 

import React, { lazy, Suspense } from "react";
import { Route, Routes, Link } from "react-router-dom";
const FirstComponent = lazy(() => import("./components/FirstComponent"));
const SecondComponent = lazy(() => import("./components/SecondComponent"));

const App = ({}) => {
  return (
    <>
      <div>
        <p>
          <Link to="/">Go First</Link>
        </p>
        <p>
          <Link to="/Second">Go Second</Link>
        </p>
      </div>

      <Suspense fallback={<div>Loading...!</div>}>
        <Routes>
          <Route exact path="/" element={<FirstComponent />} />
          <Route exact path="/Second" element={<SecondComponent />} />
        </Routes>
      </Suspense>
    </>
  );
};

export default App;

 

 

lazy를 사용해서 Dynamic import를 구현할 수 있다. 

const FirstComponent = lazy(() => import("./components/FirstComponent"));
const SecondComponent = lazy(() => import("./components/SecondComponent"));

 

lazy를 사용할 땐 Suspense를 무조건 같이 사용해야 하는데, 

<Suspense fallback={<div>Loading...!</div>}>
   <Routes> 
      <Route exact path="/" element={<FirstComponent />} />
      <Route exact path="/Second" element={<SecondComponent />} />
   </Routes>
</Suspense>

fallback 안에 있는 컴포넌트가 Dynamic import를 통해 컴포넌트를 불러오기 전까지 화면에 대신 나타날 화면이다. 

 

즉, Danamic import이기 때문에 불러오기까지 loading 시간이 필요한데, 그 시간 동안 화면에 나타날 페이지라고 

생각하면 된다. 

 

lazy를 사용하고 하시 build를 사용하면 번들파일이 분할된 것을 확인할 수 있다. 

 

2. 번들 파일 이름 지정하기 

import React, { lazy, Suspense } from "react";
import { Route, Routes, Link } from "react-router-dom";
const FirstComponent = lazy(() =>
  import(/*webpackChunkName: "firstComponent"*/ "./components/FirstComponent")
);
const SecondComponent = lazy(() =>
  import(/*webpackChunkName: "secondComponent"*/ "./components/SecondComponent")
);

...

export default App;

import 안에 /*webpackChunkName: " 이름 " */ 을 지정해준다. 

 

...

  output: {
    path: path.join(__dirname, "/dist"),
    filename: "[name].bundle.js",
  },

...

그리고 webpack.config.js에서 output의 filname에 [name]을 추가하고 build를 한다. 

 

지정한 이름으로 번들파일이 만들어지는 것을 확인할 수 있다. 

 

html-webpack-plugin

예를 들어, 프로젝트를 만들 때, 자주 쓰는 Util 폴더가 있을 것이다. 

하나의 프로젝트는 맞지만, 자주 사용되는 부분은 아니고 필요할때만 나오면 되는 그런 류의 코드들 말이다. 

이때 index.js 파일과 분리시켜 다른 js 파일로 만들어낼 수 있다. 

webpack 설정

webpack의 entry는 기본적으로 스트링형식으로 많이 사용한다. 

하지만 스트링 타입 외에도 Object Systax를 지원하여, 여러 개의 entry 파일을 명시할 수 있다. 

 

※ 나중에 entry, output 등 각각 개별적으로 정리를 해볼 예정! 

...

  entry: { index: "./src/index.js", sub: "./src/Sub/anything.js" },
  
...

설정을 완료하고 build를 해보면 sub와 index로 나뉜 것을 확인할 수 있다. 

하지만 index.js에서 sub의 내용을 가져오는 작업은 무리없이 가능하다. 

 

이때, 한가지 문제가 발생한다. 

 

예를 들어, index.js에서 특정 라이브러리를 사용하고, sub.js에서도 같은 라이브러리가 있다고 생각하자.

그러면 index.js와 sub.js에 라이브러리가 한 번씩 추가되어 코드 중복이 발생한다. 

 

  ...
  
  entry: { index: "./src/index.js", sub: "./src/Sub/anything.js" },

  optimization: {
    splitChunks: {
      chunks: "all",
    },
  },
  
  ...

이렇게 옵션을 준다면, 중복되는 라이브러리를 index와 sub에서 제거하고 다른 하나의 번들로 만들어 준다

 

근데 또 index.js와 sub.js는 같은 index.html에서 로딩이 되고 있다. 이것을 별도의 html에서 로딩시키는 방법은 없을까?

이때 html-webpack-plugin을 사용해서 index.html 파일을 여러 개 만들어줄 것이다. 

...

  plugins: [
    new HtmlWebpackPlugin({
      template: "./public/index.html",
      filename: "index.html",
      chunks: ["index"],
    }),
    new HtmlWebpackPlugin({
      template: "./public/index.html",
      filename: "sub.html",
      chunks: ["sub"],
    }),
  ],

...

사용된 옵션을 살펴보자면, 

filename : 생성하려는 html 파일 이름을 결정한다. 

chunks : 결과물들 중 어떤 번들을 import 할 것인지 결정한다. 

            chunk의 이름은 entry 옵션에서 정했던 key와 동일하다. 

 

3. 깃허브 살펴보기 

https://github.com/SeoJaeWan/webpack-codesplitting

반응형