티스토리 뷰
웹팩 코드 스플리팅
우선 이해하기 쉽게 싱글페이지 어플리케이션(SPA)를 예로 들고자 한다.
SPA는 최초 웹사이트 페이지를 로딩할 때 특별한 설정을 하지 않은 이상 해당 웹앱의 모든 리소스를 다 불러온다.
이로 인해 웹사이트의 초기 로딩 시간이 오래 걸리며 유저가 모든 페이지를 이용하는 것도 아닌데 유저가 이용하는 페이지와 무관한 소스를 요청한다.
이것은 불필요한 로딩 시간을 기다려야 하기 때문에 사용자 경험(UX)을 나쁘게 하는 요인이 될 수 있다.
그래서 초기 로딩시간을 개선하기 위해 나온 것이 웹팩의 코드 스플리팅이다.
SPA라고 해도 해당 라우터를 방문했을 때 관련된 모듈들만을 로딩하는 것이다.
코드 스플리팅을 하는 방법 중 require.ensure와 dynamic import를 사용하여 웹사이트 최초 로드 시 정적으로 모든 리소스를 갖고 오는 것이 아닌 렌더링될 페이지에 필요한 코드만을 동적으로 갖고오는 방법이 있다.
필자는 require.ensure가 아닌 예외처리에 편리한 dynamic import를 프로젝트에 채택하여 사용했었고 해당 사용 방법을 소개하고자 한다!
먼저 @babel/plugin-syntax-dynamic-import라는 플러그인을 다음과 같이 설치 후, babel-loader의 plugins에 넣는다.
dynamic import는 es6문법이며 웹팩 번들 시 바벨이 해당 문법을 es6이하 버전 문법으로 트랜스파일링해 주도록 하기 위함이다.
npm install --save-dev @babel/plugin-syntax-dynamic-import
// webpack.config.js 혹은 webpack.common.js
// ...
{
loader: 'babel-loader',
options: {
plugins: ['@babel/plugin-syntax-dynamic-import']
}
}
// ...
그럼 도대체 dynamic import은 무엇인가?
이것은 런타임 시에 entry를 통해 여러 모듈이 합쳐진 큰 덩어리의 번들링파일에서 동적으로 import를 하여 필요할 때 필요한 모듈만 요청하는 역할을 한다.
이를 통해 큰 하나의 js파일을 여러 js로 쪼개어 화면이 바뀌거나 사용자가 이벤트 인터렉션을 할 때마다 필요한 모듈만을 import함으로써 모듈을 관리할 수 있는 장점이 있다.
문법은 간단하게 설명하면 import('모듈의 경로') 형태를 띠고 있으며 아래와 같이 구체적으로 표현할 수 있다.
import('모듈의 경로')
.then(function(file) {
return file.default
})
.catch(function(err) {
console.error('file error', err);
});
이때 모듈의 경로를 입력할 때 번들링된 모듈을 입력하면 무한루프로 동적 import를 하게되니 반드시 번들링하기 전의 모듈의 경로를 입력하도록 한다.
특정 모듈을 동적 import하면 promise를 반환하며 반환 시 에러가 생기면 브라우저 콘솔을 통해 에러도 확인할 수 있는 이점이 있고 ECMA도 준수하고 있어서 개인적으로 동적 모듈을 부르는 방법 중 require.ensure보다 dynamic import()를 더 선호된다.
또한 다음과 같이 dynamic import를 활용해서 필요할 때 필요한 모듈만을 요청할 수 있다.
if(location.href === "/index"){
import('./src/index.js')
.then(function(file) {
return file.default
})
.catch(function(err) {
console.error('file error', err);
});
} else if(location.href === "/login"){
import('./src/login.js')
.then(function(file) {
return const {module1} = file
})
.catch(function(err) {
console.error('file error', err);
});
} else{
// ...
}
이제 웹팩을 빌드하면 자동으로 큰 덩어리의 번들링 파일에서 여러 모듈로 분리되는 것을 확인할 수 있을 것이다.
한편 코드 최적화의 방법 중 다음과 같이 관리하는 방법도 있다.
entry에 있는 각 모듈들이 서로 같은 라이브러리나 모듈을 import하고 있을 경우 중복된 모듈이 두개의 번들링 파일에 모두 포함하는 문제가 있을 수 있다.
이러한 중복을 피하기 위해 아래와 같이 optimization의 SplitChunksPlugin이 중복문제를 해결해준다.
optimization은 웹팩의 성능 최적화를 위해 빌드 과정을 커스터마이징하는 기능이라고 보면 된다.
이후에 설명하겠지만 예를 들어 코드를 압축할 때도 optimization에서 다양한 옵션을 추가할 수 있다.
module.exports = {
// ...
entry: {
index: './src/index.js',
login: './src/login.js',
},
// ...
optimization: {
splitChunks: {
cacheGroups: {
commons : {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
},
},
},
},
// ...
};
cacheGroups
entry에서 서로 중복된 라이브러리나 모듈을 사용하고 있으면 cacheGroups에서 설정한 것을 통해 중복된 라이브러리나 모듈들을 따로 번들링된 새로운 chunk파일로 생성하라고 웹팩에게 명령한다고 보면 된다.
commons
chunk파일을 생성하는 그룹의 이름이며 임의로 이름을 바꿔도 된다.
test
해당 경로나 파일명을 포함하고 있는 라이브러리 혹은 모듈을 중복하여 import하고 있는 모듈들을 chunk파일에 포함시키라는 정규표현식을 의미한다.
name
chunk파일이 생성될 때 output에 filename :[name].js라는 코드가 있을 경우 [name]에 name에서 할당한 이름을 대입하라는 것을 의미한다.
chunks
옵션이 'async', 'initial', 'all'이 있는데 그중 'all'인 경우 entry의 각 모듈들이 중복으로 동적 혹은 정적으로 import한 모듈은 모두 chunk 파일로 만들어 버리는 기능을 한다.
'Front-End > Webpack' 카테고리의 다른 글
webpack-bundle-analyzer (0) | 2021.10.02 |
---|---|
배포모드 시 HTML, JS, CSS 코드 압축 (0) | 2021.10.02 |
dev-server란 무엇인가? (0) | 2021.10.02 |
mode란 무엇인가? (0) | 2021.10.02 |
plugin란 무엇인가? (0) | 2021.10.02 |