바벨과 웹팩은 웹 어플리케이션을 제작할 때 필수적인 기술이다.
create-react-app, next.js 등 프로젝트를 구축해주는 라이브러리, 프레임워크는 바벨과 웹팩을 기본적으로 포함한다.
바벨과 웹팩을 자세히 모르더라도 내장된 기본 설정으로 간단한 프로젝트를 제작할 수는 있지만,
프로젝트의 규모가 점점 커지면 바벨과 웹팩을 알아야 할 순간이 찾아온다.
바벨(Babel)
바벨은 입력과 출력이 모두 자바스크립트 코드인 컴파일러다.
하이 레벨의 언어를 로우 레벨 언어로 변환하는 보통의 컴파일러와는 비교된다.
바벨은 JSX, ES6 등 최신 문법을 브라우저에서 이해할 수 있는 코드로 변환시켜준다.
바벨을 이용하면 오래된 브라우저도 최신 자바스크립트 코드를 이해할 수 있게 된다.
먼저 바벨을 실행할 프로젝트를 만들자.
$ npm init -y
$ npm install @babel/core @babel/cli
@babel/plugin-transform-arrow-functions
@babel/plugin-transform-template-literals
@babel/preset-react
필요한 패키지들을 설치한다.
// package.json
{
"name": "7-1",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@babel/cli": "^7.18.10",
"@babel/core": "^7.18.10",
"@babel/plugin-transform-arrow-functions": "^7.18.6",
"@babel/plugin-transform-template-literals": "^7.18.9",
"@babel/preset-react": "^7.18.6"
}
}
package.json을 보면 패키지가 잘 설치된 것을 볼 수 있다.
이제 바벨로 컴파일할 코드를 만들자.
// code.js
const element = <div>babel test</div>;
const text = `element type is ${element.type}`;
const add = (a, b) => a + b;
이 코드를 바로 실행하면 오류가 발생한다.
node.js는 이 코드를 아직 이해할 수 없기 때문이다.
코드를 실행하기 위해선 바벨로 컴파일해야 한다.
첫번째줄 JSX 문법은 @babel/preset-react로 변환할 것이다.
두번째줄 템플릿 리터럴 코드는 @babel/plugin-transform-template-literals,
세번째줄 화살표 함수는 @babel/plugin-transform-arrow-functions로 변환 할 것이다.
바벨을 실행하는 방법은 여러가지가 있다.
먼저 @babel/cli로 실행해보자.
@babel.cli
다음 명령어를 실행하면
$ npx babel src/code.js
--presets=@babel/preset-react
--plugins=@babel/plugin-transform-template-literals
,@babel/plugin-transform-arrow-functions
콘솔창에 실행 결과가 출력된다.
// 콘솔창
const element = /*#__PURE__*/React.createElement("div", null, "babel test");
const text = "element type is ".concat(element.type);
const add = function (a, b) {
return a + b;
};
JSX문법은 createElement 함수로 변환되었다.
템플릿 리터은 concat 메서드로, 화살표 함수는 일반 함수로 변환되었다.
@babel/cli를 이용하면 위에 명령어의 --presets처럼 대부분의 설정값을 표현할 수 있지만,
편의를 위해 설정 파일을 따로 만들자.
파일명은 babel.config.js로 하자.
// babel.config.js
const presets = ["@babel/preset-react"];
const plugins = [
"@babel/plugin-transform-template-literals",
"@babel/plugin-transform-arrow-functions",
];
module.exports = { presets, plugins };
이제 cli에서 --presets들을 일일이 쓰지 않아도 된다.
$ npx babel src/code.js
바벨이 잘 실행된 것을 확인할 수 있다.
컴파일 결과를 파일로 따로 저장하고 싶다면, 아래 명령어를 실행하면 된다.
$ npx babel src/code.js --out-file dist.js
$ npx babel src --out-dir dist
첫번째는 파일만 변환하고, 두번째는 폴더 전체를 변환해준다.
웹팩의 babel-loader
이번엔 웹팩의 babel-loader로 바벨을 실행해보자.
필요한 웹팩과 패키지를 설치하자.
$ npm install webpack webpack-cli babel-loader
그리고 config 파일을 만들어 웹팩 설정을 하자.
// webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/code.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "code.bundle.js",
},
module: {
rules: [{ test: /\.js$/, use: "babel-loader" }],
},
optimization: { minimizer: [] },
};
babel-loader는 바벨의 설정 파일 babel.config.js를 이용한다.
babel-loader로 변환된 code.bundle.js 파일을 확인할 수 있다.
@babel/core
앞서 본 @babel/cli와 babel-loader 모두 @babel/core을 이용해서 바벨을 실행한다.
이번엔 직접 @babel/core로 바벨을 실행해보자.
// runBabelCore.js
const babel = require("@babel/core");
const fs = require("fs");
const filename = "./src/code.js";
const source = fs.readFileSync(filename, "utf8");
const presets = ["@babel/preset-react"];
const plugins = [
"@babel/plugin-transform-template-literals",
"@babel/plugin-transform-arrow-functions",
];
const { code } = babel.transformSync(source, {
filename,
presets,
plugins,
configFile: false,
});
console.log(code);
@babel/core 모듈을 가져온 뒤 플러그인과 프리셋을 설정한 후 변환하였다.
"node runBabelCore"로 파일을 실행하면 바벨로 변환된 코드가 콘솔창에 출력된다.
바벨의 컴파일은 세 단계를 거친다.
1. 파싱 단계: 입력된 코드로부터 AST(abstract syntax tree)를 생성한다.
2. 변환 단계: AST를 원하는 형태로 변환한다.
3. 생성 단계: AST를 코드로 출력한다.
@babel/core을 이용하면 변환 단계에서 하나의 AST로부터 여러 설정으로 변환할 수 있기 때문에 자유도가 높다.
똑같은 코드를 다른 플러그인을 적용해서 각각 변환해보자.
const babel = require("@babel/core");
const fs = require("fs");
const filename = "./src/code.js";
const source = fs.readFileSync(filename, "utf8");
const presets = ["@babel/preset-react"];
const { ast } = babel.transformSync(source, {
filename,
ast: true,
code: false,
presets,
configFile: false,
});
const { code: code1 } = babel.transformFromAstSync(ast, source, {
filename,
plugins: ["@babel/plugin-transform-template-literals"],
configFile: false,
});
const { code: code2 } = babel.transformFromAstSync(ast, source, {
filename,
plugins: ["@babel/plugin-transform-arrow-functions"],
configFile: false,
});
console.log(code1);
console.log("\n");
console.log(code2);
같은 프리셋으로 먼저 AST를 생성하고,
code1은 plugin-transform-template-literals을, code2는 plugin-transform-arrow-functions을 적용했다.
바벨을 실행하니 적용한 플러그인에 따라 다르게 변환된 것을 확인할 수 있다.
// code1
const element = /*#__PURE__*/React.createElement("div", null, "babel test");
const text = "element type is ".concat(element.type);
const add = (a, b) => a + b;
// code 2
const element = /*#__PURE__*/React.createElement("div", null, "babel test");
const text = `element type is ${element.type}`;
const add = function (a, b) {
return a + b;
};
env
바벨 설정 파일에는 사용할 수 있는 다양한 속성이 있다.
extends 속성으로 다른 설정 파일을 가져오거나, overrides 속성으로 파일별로 설정할 수도 있다.
그 중 env 속성은 환경별로 설정할 수 있게 해준다.
프로덕션 환경 설정을 추가해보자.
// babel.config.js
const presets = ["@babel/preset-react"];
const plugins = [
"@babel/plugin-transform-template-literals",
"@babel/plugin-transform-arrow-functions",
];
const env = {
production: {
presets: ["minify"],
},
};
module.exports = { presets, plugins, env };
env 속성을 이용해 프로덕션 환경에 minify 프리셋을 추가했다.
이제 프로덕션 환경으로 바벨을 실행해보자.
// 명령어
$ NODE_ENV=production npx babel ./src/code.js
// 실행 결과
const element=/*#__PURE__*/React.createElement("div",null,"babel test"),
text="element type is ".concat(element.type),add=function(c,a){return c+a};
minify가 적용되어 코드가 압축되었다.
NODE_ENV 환경 변수를 설정하지 않으면 기본값은 development이다.
폴리필(polyfill)
바벨을 사용하더라도 최신 기능을 모두 사용할 수 있는 것은 아니다.
만약 바벨로 최신 코드를 변환했더라도 브라우저가 오래되었다면 코드가 오류날 수 있기 때문이다.
이 때는 폴리필로 런타임에 기능을 주입해야한다.
즉 바벨 뿐만 아니라 폴리필에 대한 별도 설정도 해야 한다.
core-js는 바벨에서 폴리필을 위해 공식적으로 지원하는 패키지다.
core-js는 사용법이 간단하지만 필요하지 않은 플로필까지 추가함으로 번들 파일의 크기가 커진다.
필요한 플로필만 추가하기 위해서 core-js로부터 특정 플로필만 추가하는 방법도 있고,
@babel/preset-env로 실행 환경에 맞는 플로필을 자동으로 추가해줄 수도 있다.
당연히 최신 실행 환경으로 갈수록 추가되는 플로필이 적어진다.
코드
'프론트엔드 > 실전 리액트 프로그래밍' 카테고리의 다른 글
[스터디 with 실전 리액트 프로그래밍] 18편 - Next.js (0) | 2022.08.28 |
---|---|
[스터디 with 실전 리액트 프로그래밍] 17편 - 웹팩 (0) | 2022.08.22 |
[스터디 with 실전 리액트 프로그래밍] 15편 - 리덕스 (0) | 2022.08.21 |
[스터디 with 실전 리액트 프로그래밍] 14편 - 여러가지 훅(Hook) (0) | 2022.08.16 |
[스터디 with 실전 리액트 프로그래밍] 13편 - useRef (0) | 2022.08.16 |