Intro.
프로그래밍 하면서 하위 호환성(Backward Compatibility)라는 단어를 들어 보셨나요? 쉽게 말해, 특정 피쳐가 하위 호환을 지원한다는 뜻은 곧, 하위 버전에서 해당 피쳐를 사용할 수 있다는 뜻입니다.
JS로 프로그래밍 할 때도 해당 개념을 신경 써야합니다. 왜냐하면, 스크립트를 실행하는 브라우저가 굉장히 다양하고 또 어떤 브라우저(IE)는 더 이상 업데이트를 안하기 때문이지요.
그래서 최신 피쳐를 사용하려 하니 어떤 브라우저에선 되는데, 어떤 브라우저에선 에러를 던지는 현상을 간간이 보실 수 있습니다.
그리고 이러한 문제는 트랜스파일러(Transpiler)를 이용하여, 최신 코드를 특정 브라우저가 이해할 수 있는 코드로 바꾸는 방법이 있습니다.
이번 글에선, babel이란 트랜스파일러를 이용하여 해당 문제를 해결해보겠습니다.
Goal
Method
1. babel 관련 모듈을 설치합니다.
yarn add -D @babel/core @babel/preset-env babel-loader
2. babel 설정파일을 만듭니다.
babel이 트랜스파일링을 결정하는 방법은 해당 프로젝트가 어떤 브라우저를 지원하느냐에 따라 달립니다.
따라서 먼저 .browserslistrc 를 만들어 해당 프로젝트가 어떤 브라우저를 지원할지 명시해줍니다.
저 같은 경우, 전체 시장 중 1%이상의 점유율을 갖는 브라우저 및 버전을 지원하겠습니다.
(** 중요 **) 무턱대고 모든 브라우저를 지원하겠다는 마음에 0% 로 설정하면 그만큼 번들 사이즈가 커집니다. 따라서 지원하고자 하는 타겟을 명확히 지정하고 진행합시다.
//.browserlistsrc
> 1%
이제 .bablerc 파일을 만들어 트랜스파일링 설정을 진행합니다.
//.babelrc
{
"presets": [
[
"@babel/preset-env"
]
]
}
3. webpack이 babel을 핸들링할 수 있도록 설정을 추가합니다.
결국 babel의 역할은 모든 js파일을 브라우저가 지원하도록 트랜스파일링 하는 것이기에, 모든 js파일에 대해 babel-loader를 적용합니다.
단, 모든 js파일들에 대해 진행하기 때문에, node_modules도 기본적으로 포함됩니다. 따라서 exclude 프로퍼티를 추가하여 node_modules는 트랜스파일링 대상에서 제외합시다.
//webpack.common.config.js
module.exports = {
..., // input output plugins etc...
module: {
rules: [
..., // other rules etc..
{
test: /\.js$/,
exclude: /node_moduels/,
use: ['babel-loader']
}
]
},
}
4. Polyfill(폴리필) 진행하기
대표적으로 Promise api의 경우가 ES6에서 추가된 피쳐이지요, 이 경우, ES5 이하 버전에선 지원이 안되기에, 이전 버전에서, 해당 기능을 쓸 수 있게 해주는 요소들을 추가해줘야합니다. 일종의 충전재(polyfill)이지요.
babel 7.4버전 이후부터 사용 가능합니다. @babel/preset-env의 "useBuiltIns" 옵션을 추가해, 지원안하는 피쳐들에 대해 자동으로 polyfill 가능합니다.
해당 방식은 corejs 패키지에 의존하므로 해당 패키지 설치 후 진행합니다.
corejs 버전의 경우, 설치 되어 있는 모듈 버전을 명시하면 됩니다. 공식 문서상으론 3.0 이상을 권장합니다.
debug 프로퍼티 설정을 통해 어떤 피쳐가 폴리필 되었는지 확인 가능합니다
yarn add -D corejs
//.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": {
"version": 3.8,
"proposals": true
},
"debug": true
}
]
]
}
5. babel에 환경 변수 넣기
당연하지만, 폴리필의 경우 개발 환경에서 사용하면 오히려 빌드 타임 퍼포먼스만 악화시키기에, 개발 환경에선 사용하지 않는것이 권장됩니다. 따라서, production / dev 환경에 따라 폴리필 실행 여부를 나누고 싶습니다.
babel에선 package.json파일에 환경 변수를 명시함으로써, babelrc에 환경 변수를 넘겨 줄 수 있습니다.
BABEL_ENV -> NODE_ENV -> "dev"
BABEL_ENV가 존재하지 않을 시, 실행 스크립트는 NODE_ENV의 유무를 찾게 되고 이것마저 없을 시, "dev" 즉, 개발 환경으로 인식합니다.
따라서, 다음과 같이 스크립트를 짜 줍시다.
"scripts": {
"build": "NODE_ENV=production webpack --config webpack/webpack.prod.config.js",
"dev": "NODE_ENV=dev webpack serve --config webpack/webpack.dev.config.js --hot"
},
다만, 위의 방식은 Linux & OSX 체제에서만 사용하는 환경 변수 셋팅 방식으로, Window의 경우 다음의 형식으로 셋팅하여야합니다.
set (환경변수)=(값)&&
이는 , cross-env 라는 모듈을 통해 손 쉽게 해결 가능합니다.
먼저 cross-env 모듈을 설치합니다.
yarn add -D cross-env
그리고 package.json 스크립트에 cross-env를 명시해주면 끝입니다.
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config webpack/webpack.prod.config.js",
"dev": "cross-env NODE_ENV=dev webpack serve --config webpack/webpack.dev.config.js --hot"
},
이제 .babelrc파일에서 각 환경별 설정만 다시해주면 됩니다.
저는 production 환경에서만 폴리필을 원하므로, dev환경에선 폴리필을 빼주겠습니다.
{
"env": {
"production": {
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": {
"version": 3.8,
"proposals": true
},
"debug": true
}
]
]
},
"dev": {
"presets": [["@babel/preset-env"]]
}
}
}
6. 실험적 요소 추가하기
개발하다가 정말 실험적인 피쳐를 사용할 수 도 있을것 같습니다. 오픈소스에서 말 그대로 자바스크립트에 proposal 단계로 제시되어 있는 피쳐가 있겠군요. 이런 요소들은 당연하지만 공식적으로 제공되는 기능들이 아니기에, corejs를 통한 폴리필도 기대할 수 없습니다.
따라서 직접 해당 플러그인을 babel 설정에 주입시켜야합니다.
예시로 pipeline-operator을 들어보겠습니다.
https://github.com/tc39/proposal-pipeline-operator
GitHub - tc39/proposal-pipeline-operator: A proposal for adding a useful pipe operator to JavaScript.
A proposal for adding a useful pipe operator to JavaScript. - GitHub - tc39/proposal-pipeline-operator: A proposal for adding a useful pipe operator to JavaScript.
github.com
말 그대로 해당 피쳐용 플러그인 설치 후, babel 설정 객체의 플러그인 프로퍼티에 추가만 하면 됩니다.
먼저 플러그인을 설치합니다.
yarn add -D @babel/plugin-proposal-pipeline-operator
그리고 plugins 프로퍼티에 추가합니다.
당연하지만, 개발 / 배포 환경과 관련없이 공통적으로 적용되어야하기에, 탑레벨에다 선언해놓겠습니다.
만약 특정 환경에다만 적용하고 싶다면, 해당 환경 내에 plugins에 적용하면 됩니다.
{
"plugins": [
[
"@babel/plugin-proposal-pipeline-operator",
{
"proposal": "minimal"
}
]
],
"env": {
"production": {
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": {
"version": 3.8,
"proposals": true
},
"debug": true
}
]
]
},
"dev": {
"presets": [["@babel/preset-env"]]
}
}
}
'Bundler' 카테고리의 다른 글
[Webpack] babel + Typescript 구성하기 (0) | 2023.05.01 |
---|---|
[Webpack] 동적으로 참조되는 애셋 번들링 하기 (copy-webpack-plugin) (0) | 2023.04.27 |
[Webpack + opt] 이미지 파일들 webp로 변환하기 (imagemin-webp) (0) | 2023.04.27 |
[Webpack] 전처리기 사용하기 + vendor prefix ( scss, less ,postCSS ) (0) | 2023.04.25 |
[Webpack] CSS Module 번들링 (0) | 2023.04.24 |