[Webpack] Code Splitting

2021. 6. 17. 09:07Frontend

 

 

위 포스팅은 이전 포스트의 내용을 이어서 진행합니다.

[Webpack] Config file & Asset Modules
[Webpack] Introduction & Setup
[Webpack] Loaders

[Webpack] Plugins

 

 

Code Splitting

애플리케이션을 번들링 할 때, 적절한 단위로 번들을 쪼개는 것은 애플리케이션 성능에 있어서 중요한 요소 중 하나입니다. 규모가 크고 많은 페이지를 가지고 있는 애플리케이션이더라도 사용자의 화면에 보이는 페이지는 하나이기 때문에 사용자가 보지 않을 수도 있는 페이지까지 함께 가져오는 것은 잠재적인 대역폭 낭비이고, 초기 렌더링 시간을 잡아먹게 됩니다. 따라서 적절한 단위로 번들을 나누어서(Code Splitting) 빌드하는 것이 중요합니다.

 

이전에 진행했던 예시를 조금 변경해서 2개의 페이지를 갖는 애플리케이션을 만들어 보도록 하겠습니다. 전체 디렉토리 구조가 아래와 같이 변경되었습니다. 

 

 

 

common/index.js

class Common {
  render() {
    const h1 = document.createElement("h1");
    h1.innerHTML = "hello-world";

    const body = document.querySelector("body");
    body.appendChild(h1);
  }
}

export default Common;

 

page1/page1.js

import page1 from "./page1.png";
import "./page1.scss";

class Page1 {
  render() {
    const img = document.createElement("img");
    img.src = page1;
    img.alt = "page1";
    img.classList.add("page1");

    const body = document.querySelector("body");
    body.appendChild(img);
  }
}

export default Page1;

 

page1/page1.scss

.page1 {
  display: block;
  width: 100px;
}

 

index1.js 

import Common from "./components/common/index";
import Page1 from "./components/page1/page1";

const common = new Common();
common.render();

const page1 = new Page1();
page1.render();

(page1, page2는 포맷이 동일합니다. index1, index2도 마찬가지입니다)

 

 

JSFile Bundling

 

웹팩 설정 파일인 webpack.config.js의 엔트리 파일(entry)은 객체 형식을 취급합니다. 이전 예시에서는 스트링(Single Entry)으로 엔트리 파일을 명시해주었지만, 웹팩 공식 문서에 따르면 엔트리 파일은 기본적인 스트링 타입 이외에도 Object Syntax를 지원하여 여러 개의 Entry파일을 명시할 수 있도록 도와줍니다. 

 

 

 

따라서 다음과 같이 설정해 줄 수 있으며, 엔트리 파일을 2개로 명시해주었으므로 webpack build를 통해 빌드해보면 2개의 번들을 가지는 파일이 나오는 것을 확인할 수 있습니다.

 

webpack.config.js 일부

 entry: {
    index1: "./src/index1.js",
    index2: "./src/index2.js",
  },
  output: {
    filename: "[name].[contenthash].js",
    path: path.resolve(__dirname, "./dist"),
  },

 

위의 config파일을 보시면 output의 filename 속성에 [name].[contenthash].js 라고 명시해주었는데 이는 빌드된 파일의 이름이 어떻게 보일 지를 결정합니다.

 

 

[name]: entry 속성에 지정해준 key 값이 적용됩니다.

[contenthash]: 지난 포스팅에서 살펴보았듯, 번들링 된 컨텐츠의 값을 unique하게 가리키는 해시값이 적용됩니다. 번들링된 파일의 내용물이 바뀌게 되면 해당 해시 값도 달라집니다.

 

 

따라서 [name].[contenthash].js 라고 output filename을 명시하게 되면 아래와 같이 파일 이름이 번들링 되어 나오게 됩니다. 

 

CSSFile Bundling

 

css file도 동일하게 위의 네이밍 포맷을 사용해서 번들링 할 수 있습니다. 이전 포스팅에서 MiniCssExtractPlugin을 통해 js파일이 import 하는 css파일을 js 번들에 포함시키는 것이 아닌 별도의 css 파일로 추출하는 것을 살펴보았습니다. 이 플러그인도 위의 webpack output filename과 동일한 네이밍 포맷을 지원하고 있기 때문에 아래와 같이 설정해주는 것 만으로 css file에도 동일한 파일 이름을 설정해줄 수 있습니다. 

 

webpack.config.js

 plugins: [
    new TerserPlugin(),
    new MiniCssExtractPlugin({
      filename: "[name].[contenthash].css",
    }),
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: [
        "**/*",
        path.join(process.cwd(), "build/**/*"),
      ],
    }),
    new HtmlWepbackPlugin(),
  ],
};

 

 

 

index.html을 통해 페이지가 제대로 렌더링 되는지, dependency를 제대로 로드해오는지를 확인해보면 제대로 페이지가 로딩되고 있음을 확인할 수 있습니다. 번들링 했던 파일들을 순서대로 잘 가지고 오는 것입니다.

 

 

 

 

Generate Multiple HTML Files

위의 예제에서는 index1, index2가 동일한 페이지에 로딩되고 있습니다. 만약에 이 index1, index2 컴포넌트를 별도의 페이지에 로딩하고 싶다면, 여러 가지 방법이 있겠지만, 가장 간단한 방법 중 하나는 index.html 파일을 여러 개 만드는 것입니다. 각각의 컴포넌트를 import 하는 index1.html, index2.html를 별도로 만들고, 원하는 페이지의 html 파일만 다운로드 하도록 하는 것입니다.

 

이전 포스팅에서 살펴보았던 HTMLWebpackPlugin을 사용하면 웹팩에서 빌드된 여러 번들들 중에 어떤 번들을 import하는 html 파일을 생성할 것인지를 결정할 수 있습니다.

 

webpack.config.js

plugins: [
    new TerserPlugin(),
    new MiniCssExtractPlugin({
      filename: "[name].[contenthash].css",
    }),
    new CleanWebpackPlugin({
      cleanOnceBeforeBuildPatterns: [
        "**/*",
        path.join(process.cwd(), "build/**/*"),
      ],
    }),
    new HtmlWepbackPlugin({
      filename: "index1.html",
      chunks: ["index1"],
      name: "index1",
      description: "index1",
    }),
    new HtmlWepbackPlugin({
      filename: "index2.html",
      chunks: ["index2"],
      name: "index2",
      description: "index2",
    }),
  ],

filename: 생성하고자 하는 html 파일의 이름을 명시해줍니다. 위의 예시에서는 각각 index1.html, index2.html로 설정하였습니다.

chunks: 가장 중요한 부분 중의 하나입니다. 번들된 결과물(chunk)들 중에서 어떤 번들을 import 할 것인지를 결정합니다. 이 chunk의 이름은 entry파일에서 설정했던 key ('index1', 'index2')와 동일합니다. 

 

이외에 name, description은 필수 사항은 아니며, 각각 html 문서의 메타데이터를 설정합니다.

위의 설정을 가지고 빌드하면 다음과 같은 결과가 나오게 됩니다.

 

 

index2.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Webpack App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script defer src="index2.b87fa62af20eabf43228.js"></script>
    <link href="index2.1d8dbe8e3d38a588ef19.css" rel="stylesheet" />
  </head>
  <body></body>
</html>

 index2에 관련된 chunk들만 import 하고 있는 것을 확인할 수 있습니다.

 

 

 

반응형

'Frontend' 카테고리의 다른 글

React Deep Dive - React Event System (1)  (0) 2021.07.19
Async / Await Under the Hood  (1) 2021.06.29
[Webpack] Plugins  (0) 2021.06.12
[Webpack] Loaders  (0) 2021.06.11
[Webpack] Config file & Asset Modules  (0) 2021.06.11