실무 프로덕트의 프론트엔드는 Ruby on Rails 환경에서 Webpacker 를 통해, webpack 4 을 이용한 asset 번들링을 하고 있어요.
동적 import 사용해서 작업해주신 팀원 분과 논의하던 중 webpack code-splitting 과 동적 import 개념을 다시 살펴보았습니다.
웹팩은 모던 자바스크립트 앱을 위한 정적 번들러입니다.
Entry Point 를 통해 의존성을 추적하고, 모듈들을 Chunk로 그룹화해서 Bundle 파일로 만들어줘요.
모듈은 import 가능한 모든 파일이며, Chunk는 번들링 과정의 중간 산출물, Bundle은 브라우저에서 로드되는 실제 파일이라고 보시면 됩니다.
중간 산출물인 Chunk는 두 가지의 생성 방식이 있어요.
1.Initial: Entry Point 기반, 페이지 로드 시 즉시 다운로드 되는 HTML에 직접 포함되는 번들.
Initial chunks contain all modules and dependencies specified for an entry point.
2.Non-Initial: 동적 로드를 위한 번들
Non-initial chunks are lazy-loaded separately, typically created through dynamic imports or code-splitting strategies.
아래 문서에도 적혀있지만, initial인 경우 이름을 따라 생성되지만, non-initial 인 경우는 중복되지 않는 id 값으로 자동 생성돼요.
By default, there is no name for non-initial chunks so that a unique ID is used instead of a name.
https://webpack.js.org/concepts/
https://webpack.js.org/concepts/under-the-hood/#chunks
code splitting을 사용하면 코드를 여러 번들로 분할하여 필요에 따라 또는 병렬로 로드할 수 있습니다.
더 작은 번들로 쪼개서 활용할 수 있는 기능이라고 보시면 됩니다.
다음 세 가지 접근 방법으로 code splitting 기능을 구현할 수 있는데요,
- Entry Points: Manually split code using entry configuration.
- Prevent Duplication: Use the SplitChunksPlugin to dedupe and split chunks.
- Dynamic Imports: Split code via inline function calls within modules.
이번에는 동적 import 를 통해 code splitting 을 구현했습니다.
splitChunks: {
chunks: 'all',
name: true,
},
environment 에 name 값을 설정해서 chunks를 분리하도록 합니다.
https://v4.webpack.js.org/guides/code-splitting/
https://v4.webpack.js.org/plugins/split-chunks-plugin/#splitchunksname
non-initial chunk인 경우는 중복되지 않는 id 값으로 자동 생성된다고 했습니다.
그 전에 output은 어떤식으로 설정되는지 짚고 넘어갑시다.
public/packs/js/page/MainPage-eea4ad22932cbfe2c26a.chunk.js
└─┬──┘ └─┬─┘└┬┘ └─────┬─────┘ └────────┬─────────┘└───┬───┘
│ │ │ │ │ │
① ② ③ ④ ⑤ ⑥
① public/ : Rails Public Root
설정 위치: config/webpacker.yml
public_root_path: public
② packs/ : Webpacker Output Path
설정 위치: config/webpacker.yml
public_output_path: packs
③ js/ : Chunk Filename Prefix
④ page/MainPage : Chunk Name
⑤ -eea4ad22932cbfe2c26a : 해시
⑥ .chunk.js : File 확장자
설정 위치: config/webpack/environment.js
chunkFilename: 'js/[name]-[contenthash].chunk.js',
Webpacker 설정 기준으로 정리한 점 참고 부탁드립니다.
그러면 non-initial인 경우, name이 id 로 들어오지 않고 모듈의 이름으로 들어오게 하려면 어떻게 해야할까요?
그럴 때 주석으로 Magic Comment를 설정하면 됩니다.
const MainPage = React.lazy(() =>
import(/* webpackChunkName: "page/MainPage" */ './Page/MainPage')
// ^^^^^^^^^^^^^^^
// [name]에 들어갈 값
);
생성 과정:
chunkFilename 패턴: js/[name]-[contenthash].chunk.js
^^^^^^
"page/MainPage" 대입
결과: js/page/MainPage-eea4ad22932cbfe2c26a.chunk.js

const MainPage = React.lazy(() =>
import('./Page/MainPage')
// webpackChunkName이 없음!
);
생성 과정:
chunkFilename 패턴: js/[name]-[contenthash].chunk.js
^^^^^^
Webpack이 자동으로 숫자 ID 할당 (1, 2, 3, ...)
결과: js/1-eea4ad22932cbfe2c26a.chunk.js
js/2-f1b52411c84c06b72.chunk.js
js/3-a2b3d6a34331c201b.chunk.js

https://v4.webpack.js.org/api/module-methods/#magic-comments
Magic Comment 를 설정하면 동적 import 시 여러 유용한 설정을 할 수 있으나, 필수는 아닙니다.
webpackChunkName 을 설정하지 않는 경우 위 처럼 숫자 id 가 할당 되니 에러가 발생할 일도 없어요.
그러나 번들 출력물을 명시적으로 확인하거나 기타 설정을 위해서 사용하는 것이라고 봐야할 것 같습니다.
(설정하는 것이 다소 귀찮으나...)
동적 import 와 함께 React.lazy()를 사용하면 SPA 에서 컴포넌트가 필요할 때 필요한 번들을 로딩하여 Code Splitting 을 구현할 수 있습니다.