[webpack4] splitChunksPlugin 옵션 파헤치기

본 포스팅은

를 보고 좀 더 이해하기 쉽게 제식대로 다시 정리한 내용입니다. 웹팩의 코드 스플리팅을 좀 더 자세하게 이해하기 위해서 정리해봤습니다.

웹팩이 버전4가 되면서 파일 청크 플러그인으로 SpilitChunks를 사용하게끔 변경되었습니다. 이 플러그인은 3가지 중 하나의 옵션이 필수로 지정되어야 합니다.

initial, async, all

각 옵션이 어떤 역할을 하는지 예시를 통해서 알아봅시다. 예제 프로젝트에서는 a.js와 b.js가 존재합니다. 각 파일은 웹팩의 엔트리 파일이므로 두개의 번들 파일이 만들어질것입니다. 그것을 각각 번들 A, 번들 B라고 부르겠습니다.

react와 jquery가 정적으로

lodash만 동적으로 import되었습니다.

react와 lodash가 동적으로

jquery만 정적으로 import되었습니다.

웹팩 설정 파일

웹팩에는 optimization 옵션이 존재합니다.그 중 cacheGroups 옵션은 특정 조건에 따라서 청크파일을 생성하겠다는 의미입니다. 위 파일을 살펴보면node_vendors라는 청크 그룹을 생성했고, 이 청크 그룹에는 node_modules폴더 아래에 있는 파일중 비동기로 import된 파일들을 포함시켜라. 라는 옵션이 설정되어 있습니다.

만약 chuncks 옵션이 async가 아니고 all인 경우 비동기 import든 동기 import든 상관없이 node_modules아래에 있는 파일은 모두 node_vendors.js로 합쳐라 라는 의미가 됩니다.

async 옵션 — 비동기 모듈에 대한 최적화

위의 상황을 도식화 하면 다음과 같습니다.

chunks 옵션을 async로 주게 되면 비동기 모듈에 대해서 최적화를 진행합니다. lodash는 a.js와 b.js 모두에서 비동기로 import되었기 때문에 웹팩이 새로운 청크파일 (번들1)로 분리했습니다.

이 상황을 웹팩의 BundleAnalyzer 플러그인을 통해서 살펴보면 다음과 같습니다.

chunks가 async모드로 동작했기 때문에, a.jsb.js 모두에서 비동기로 import된 lodash는 새로운 번들(1.bundle.js)로 분리되었습니다.

두 파일(a.js, b.js)모두에서 비동기로 import되지 않았던 jquery는 최적화 되지 않은 상태로 번들A, 번들B에 그대로 포함되어 있는걸 볼 수 있고, b.js에서만 비동기 import된 react는 별도의 번들(0.bundle.js)로 분리되었습니다. a에서는 react가 정적 import되었기 때문에 번들A에 그대로 남아있습니다.

웹팩아! 번들 파일에서(번들A, 번들B)비동기로 import된 라이브러리들은 하나의 번들로 따로 분리해줘!
OK!
그럼 a.js와 b.js에서 비동기 import된모듈 lodash는 번들로 분리해줄게 그리고, b에서만 비동기로 import된 react도 따로 분리해줄게. 나머지 정적 import는 그대로 둘거야.

initial 옵션 — 정적 모듈에 대한 최적화

이 옵션은 정적으로 import된 모듈에 대해서 최적화를 진행합니다.

jquery는 a와 b에서 모두 정적으로 import 되었기 때문에 node_vendors~a~b번들이 만들어졌습니다 a와 b모듈에서 공통으로 사용되는 청크파일이라는 뜻으로 이름이 저렇게 지어집니다.

이 옵션은 정적 import된 모듈들을 무조건 청크로 만듭니다. 위 사진에서 react의 경우 a에서는 정적, b에서는 동적으로 import되었는데 청크 옵션이 initial이기 때문에 node_vendors~a번들에 react를 분리 했습니다.

정적 import에 대해서는 무조건 별도의 청크로 만들어버리고 남아있는 비동기 모듈들도 마찬가지로 분리해줍니다. (왜냐면 비동기 모듈은 따로 파일을 분리해야 동적으로 불러올 수 있어서 비동기로 import하는 순간 무조건 별도의 파일로 분리됩니다.)

all 옵션

반면에 청크 옵션이 all인 경우 비동기로 import됬든 정적으로 import됬든 상관하지 않고 하나의 청크 파일로 만들어버립니다. 위 케이스와 비교해서 번들 파일이 하나 더 적은것을 볼 수 있죠.

여기 까지 정리했는데도 잘 이해가 안가서 직접 웹팩을 설정해서 해보기로 했습니다. 잘 이해가 안갈떈 직접 해보는게 최고죠.

옵션을 주지 않은 경우

A번들 B번들 0번들이 만들어짐.

엔트리가 a.js와 b.js로 두개이므로 기본적으로 번들도 A.js B.js가 생성되었습니다. 아무런 스플릿청크 옵션을 주지 않았기 때문에 번들 A, B 모두에 react-dom과 react가 들어있습니다. lodash의 경우에 최적화 옵션을 주지 않았음에도 불구하고 번들0로 분리되었습니다. 비동기로 import된 모듈은 따로 옵션을 주지 않아도 웹팩이 알아서 분리를 해줍니다.

a.js와 b.js에서 모두 lodash가 비동기로 import되었기 때문에 번들A와 번들B에는 lodash가 없습니다.

a.js에서만 비동기로 import된 lodash, 청크 옵션 x

우선 파란색을 먼저 봅시다. lodash는 a에서만 비동기로 import되었습니다. 비동기로 import되면 무조건 웹팩이 별도의 파일로 분리해줍니다.

보라색을 보면 react, react-dom이 번들 A에 포함되어있습니다.

노란색을 보면, 번들 B에는 react-dom, lodash, react 3개 모두 들어있습니다. 아무런 최적화 옵션을 주지 않았고 비동기로 import된것도 없으니까 당연하겠죠.

chunks = all

왼쪽 a.js 오른쪽 b.js 웹팩 옵션 chunks=all

잘 안보이시겠지만 밑에부분에 번들 A와 번들B가 아주 작게 존재합니다. 최적화 옵션을 주자 마자 번들 A와 번들 B의 크기가 매우 작게 줄어들었습니다.

react와 react-dom은 a.js와 b.js 모두에서 정적으로 import되었기 때문에 위와 같은 파일명으로 지어진 것 같습니다.

lodash의 경우 a.js에서는 동적 b.js에서는 정적으로 import되었는데, chunks옵션을 all로 줬기 때문에 동적이든 정적이든 상관없이 무조건 별도의 번들 파일로 분리해줍니다.

이 옵션은 한마디로, “import된 모든 파일을 별도의 파일로 분리”하는 옵션입니다.

chunks = async

chunks = async옵션은 비동기 import에 대해서만 최적화 해줍니다. a에서 비동기로 import된 lodash는 별도의 파일로 분리되었고 나머지는 번들에 그대로 둡니다. 그래서 lodash가 두 번들 (B, 2)에 중복으로 존재합니다.

lodash를 b.js에서도 비동기로 import하면 다음과 같이 변합니다.

a.js와 b.js에서 모두 비동기로 import된 lodash를 별도의 파일로 분리했습니다. 그리고 번들 A와 번들 B에서는 lodash가 빠진걸 볼 수 있죠.

chunks = initial — 정적 import에 대한 최적화

initial 옵션이 좀 헷갈려서 일부러 모든 케이스를 다 넣어봤습니다.

  1. 한쪽에서만 비동기 import — lodash
  2. 둘다 동기 import — react
  3. 둘다 비동기 import — react-dom

initial 옵션은 정적 import에 대해서 파일을 분리합니다.

react는 두 파일에서 모두 정적 import

lodash는 b에서만 정적 import입니다.

우선 react는 별도의 파일로 분리됩니다. 또한 lodash의 경우에도 b에서 정적으로 import되어서 별도의 파일로 분리됬습니다. 이 상황에서 lodash는 a에서 비동기로 import되었기 때문에 별도의 청크가 또 만들어집니다.

ssg.com Frontend Developer