Webpack을 알아보기 전에 번들러 라는 것을 알 필요가 있다. 간단히 말해 여러개의 파일들을 하나의 파일로 묶어주는 것이다. 우리가 파일 1개를 HTTP 요청을 하고 응답하는데 서버가 1초가 걸린다고 가정하자. 100개면 100초, 10000개면 10000초다. 게다가 대량의 클라이언트가 사이트를 이용할 경우, 너무 많은 응답으로 인해 많은 비용과 네트워크 병목현상을 초래할 수 있다. 여러 파일들을 하나의 파일들에다 넣으면 문제는 해결 될 지도 모르지만, 코드의 유지보수면에서 수만 줄의 코드를 읽어야 하니 가독성이 매우 좋지 않다.
즉 이러한 문제를 해결하기 위해 Webpack과 같은 번들러들이 생기게 된 것이다. 번들러를 이용하여 JS, CSS, 이미지 파일 등을 각각 하나의 파일로 번들링하여 더 효율적으로 데이터를 주고 받게 되는 것이다. Webpack은 앱에 필요한 모든 모듈을 알아서 매핑해주며, 매핑된 결과를 가지고 하나 이상의 번들을 생성한다.
번들러를 사용하면 모듈 단위의 코딩이 가능하다. 모듈 단위 코딩을 하게 되면 각 모듈이 독립적이기 때문에 중복된 이름으로 인해 에러가 발생하는 것을 막을 수 있다.
모듈이란? 프로그램 내부를 기능별 단위로 분할한 부분
또한, 모듈 단위로 기능을 구분하기 때문에 코드의 가독성이나, 유지보수에 뛰어나다.
webpack은 로더(babel-loader)를 통해 바벨을 사용할 수 있습니다. 이를 통해 ES5만 지원하는 오래된 브라우저에서도 ES6 이상의 문법으로 이루어진 JS 파일을 작동할 수 있게 해준다.
Babel : ES6 이상의 자바스크립트 문법을 ES5 버전의 자바스크립트 문법으로 변환시켜주는 트랜스파일러
webpack은 style-loader와 css-loader, sass-loader라는 로더를 사용하여 SASS를 CSS로 컴파일하여 사용할 수 있게 만들어준다.
위에서도 언급된 바벨은 간단히 말해 버전이 낮아 사용하지 못하는 높은 버전의 문법을 낮은 버전으로 맞추어서 바꿔준다는 느낌이다. Babel의 공식 사이트에서는 이렇게 설명한다.
Babel is a JavaScript compiler.
자바스크립트는 인터프리터 언어가 아닌가? 왜 컴파일을 하는거지? 라는 생각을 가지게 된다. 정확히는 Babel 은 자바스크립트로 결과물을 만들어주는 컴파일러다. 소스 대 소스 컴파일러 (트랜스파일러)라고 불리며 컴파일러와는 조금 다른 방식인 것이다.
현재도 그렇지만 과거에도 급속하게 프론트엔드 생태계는 매우 빠르게 발전하고 새로운 기술들이 나오고 있기 때문이다. 최신 브라우저 조차도 지원하지 못하는 문법과 여러 기술들이 출연하고 있으므로 이것들을 호환해 주는 것이 필요하게 된 것이다.
크로스 브라우징(Cross Browsing) : 위의 문제들과 같이 여러 브라우저가 존재하며 버전도 유저마다 다르다. 이러한 환경에서는 모든 브라우저에서 그려지는 화면이 차이가 있을 수 밖에 없는데, 이러한 문제들을 최소화 하여 브라우저 환경에 영향을 최소한으로 하고 일관된 웹 서비스를 사용할 수 있게 최적화를 하는 작업을 말한다.
바벨 플러그인은 바벨이 어떤 코드를 어떻게 변환할 지에 대한 규칙을 나타낸다. 플러그인을 커스텀해서 사용해도 되고, 이미 만들어진 플러그인을 가져다가 써도 된다.
npm 패키지로 제공하는 플러그인을 설치하여 ES6의 const, let을 var로 바꾸고, 화살표 함수를 일반 함수로 바꾸고 엄격 모드를 적용하여 ES6+를 ES5로 변환하는 바벨 설정 파일은 다음과 같다.
module.exports = {
plugins: [
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-strict-mode",
]
}
이렇게 설정값을 세팅하고 다시 빌드를 하면 다음과 같이 코드가 변한다.
// before
const alert = msg => window.alert(msg);
// after
"use strict";
var alert = function (msg) {
return window.alert(msg);
};
플러그인을 매번 일일이 설정하는 건 정말 번거롭다. 그래서 이렇게 필요한 플러그인들을 목적에 따라 세트로 묶어놓는 경우가 많다. 이러한 세트를 프리셋(preset)이라고 한다. 대표적인 프리셋으로 ES6+를 변환하는 프리셋인 preset-env를 살펴보자. 프리셋 패키지를 설치하고 아래와 같이 바벨 설정 파일을 바꿔준다.
module.exports = {
presets: [
'@babel/preset-env'
]
}
개인 프로젝트의 경우 Next.js 기반으로 하였으며 버전 호환에 문제가 있었을 때, 무작정 검색해서 해결했지만 Babel에 대해 공부하고 왜 이렇게 넣는지 이유를 알게 되었다.
만약에 특정 브라우저 버전 이상을 지원해야 할 경우 바벨 설정파일에서 targets 속성 값으로 지정해 주면 된다. 예를 들어서 크롬 79 이상, IE 11 이상을 지원해 주는 코드로 변환하고 싶다면 아래와 같이 바벨 설정 파일을 바꾸어 주면 된다.
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
chrome: '79', // 크롬 79까지 지원하는 코드
ie: '11' // ie 11까지 지원하는 코드
}
}
]
]
}
폴리필(polyfill)은 최신 ECMAScript 환경을 만들기 위해 코드가 실행되는 환경에 존재하지 않는 빌트인, 메소드 등을 추가하는 역할을 한다.
ES6에서 비동기 처리를 위해 등장한 Promise 객체는 env 프리셋을 가지고 변환을 하려고 해도 ie에서 인식하지 못한다. 바벨의 경우는 ES6+를 ES5로 변환할 수 있는 것들만 변환을 하는데, Promise와 같이 ES5에서 변환할 수 있는 대상이 없는 경우는 에러가 발생한다. 이러한 경우 우리는 폴리필을 통해서 이슈를 해결할 수 있다. Promise를 ES5로 변환할 수는 없지만 ES5 방식으로 구현하여 해결하는 것이다.
아래와 같이 바벨 설정 파일에 폴리필을 추가한다. useBuiltIns는 어떤 방식으로 폴리필을 사용할지 설정하는 옵션이다.
module.exports = {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage', // 폴리필 사용 방식 지정
corejs: { // 폴리필 버전 지정
version: 2 // default version
}
},
],
],
};
그 후 빌드를 하게 되면 아래와 같은 결과물이 나온다.
// 폴리필을 추가하여 빌드
// npx babel app.js
// before
new Promise();
// after
"use strict";
require("core-js/modules/es6.promise");
require("core-js/modules/es6.object.to-string");
new Promise();
이렇게 한다면 IE에서도 호환이 가능하게 되는 것이다.
실무에서는 바벨을 직접 사용하는 경우보다는 웹팩으로 통합해서 사용하는 경우가 더 많다고 한다. 이 때, 로더 형태로 제공되는 babel-loader를 사용한다. babel-loader를 설치하고 웹팩 설정 파일을 다음과 같이 작성한다. 이로써 모든 js 파일을 바벨로 처리할 수 있게 되었다.
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
]
},
}
참고자료 :
https://devowen.com/293
https://velog.io/@ksung1889/%EB%B2%88%EB%93%A4%EB%9F%ACbundler%EB%9E%80
https://bravenamme.github.io/2020/02/12/what-is-babel/
https://medium.com/naver-place-dev/javascript-%EB%B2%88%EB%93%A4%EB%9F%AC%EC%9D%98-%EC%9D%B4%ED%95%B4-4-webpack-%EB%B0%8F-%EB%8B%A4%EB%A5%B8-%EB%B2%88%EB%93%A4%EB%9F%AC%EB%93%A4-e5158e94ef60