Webpack 코드 스플리팅

2022년 12월 13일, 01:18

더 작은 번들을 만들고 리소스 우선순위를 올바르게 제어하기 위해서 사용하며, 잘 활용하면 로드 시간에 영향을 크게 줄 수 있다.

코드 스플리팅은 세가지 방식으로 접근할 수 있다.

  • Entry Points: entry 설정을 사용하여 코드를 수동으로 분할
  • Prevent Duplication: Entry dependecies또는 SplitChunksPlugin을 사용하여 중복 청크를 제거하고 청크를 분할
  • Dynamic Imports: 모듈 내에서 인라인 함수 호출을 통해 코드를 분할

Entry Points

entry를 다르게 설정해서 번들 파일이 entry만큼 생기게 한다.

ex)

const path = require('path');

module.exports = {
  entry: './src/index.js',
  mode: 'development',
  entry: {
    index: './src/index.js',
    another: './src/another-module.js',
  },
  output: {
    filename: 'main.js',
    filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
  },
};

위의 방식에는 문제점이 있는데, entry chunk사이에 중복된 모듈은 두 번들에 모두 포함되는 것이다. 중복을 막기 위해서는 Prevent Duplication을 적용해야한다.

Prevent Duplication

dependOn 옵션을 통해서 청크간 공유할 모듈을 정해줄 수 있다. 값은 string 또는 string[]이 될 수 있다.

ex)

const path = require("path");

module.exports = {
  mode: "development",
  entry: {
    index: "./src/index.js",
    another: "./src/another-module.js",
    index: {
      import: "./src/index.js",
      dependOn: "shared",
    },
    another: {
      import: "./src/another-module.js",
      dependOn: "shared",
    },
    shared: "lodash",
  },
  output: {
    filename: "[name].bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
};

주의할 점은 단일 페이지에서 여러 엔트리를 사용하는 경우 optimization.runtimeChunk: 'single' 옵션을 꼭 넣어줘야한다.

그렇지 않으면, 아래와 같은 문제가 생길 수 있다. 참고

index.html

<!DOCTYPE html>
<script src="component-1.js"></script>
<script src="component-2.js"></script>

component-1.js

import obj from './obj.js';
obj.count++;
console.log('component-1', obj.count);

component-2.js

import obj from './obj.js';
obj.count++;
console.log('component-2', obj.count);

obj.js

export default { count: 0 };

결과

component-1 1 component-2 2

SplitChunksPlugin

해당 플러그인을 사용하면 기존 entry chunk 또는 완전히 새로운 chunk로 공통 의존성을 추출할 수 있다.

ex)

const path = require("path");

module.exports = {
  mode: "development",
  entry: {
    index: "./src/index.js",
    another: "./src/another-module.js",
  },
  output: {
    filename: "[name].bundle.js",
    path: path.resolve(__dirname, "dist"),
  },
  optimization: {
    splitChunks: {
      chunks: "all",
    },
  },
};

optimization.splitChunks설정을 적용하면 lodash가 분리되는 것을 볼 수 있다.

참고) mini-css-extract-plugin을 이용하면 css를 분리할 수 있다.

webpack v4이전에는 CommonChunkPlugin을 사용한 것 강튼데 v4부터는 SplitChunksPlugin을 사용한다.

SplitChunksPlugin에 대해서 조금 더 자세히 알아보자.

SplitChunksPlugin은 아래 조건에 따라 자동으로 청크를 분할한다.

  • 새 청크를 공유 할 수 있거나 모듈이 node_modules 폴더에 있는 경우
  • 새 청크가 20kb보다 클 경우(min+gz 이전에)
  • 요청 시 청크를 로드할 때 최대 병렬 요청 수가 30개 이하일 경우
  • 초기 페이지 로드 시 최대 병렬 요청 수가 30개 이하일 경우

마지막 두 개의 조건을 충족하려고 하는 경우에는 더 큰 청크가 선호된다고 한다.