크로스 브라우징의 혼란을 해결해 줄 수 있는 것은 바벨이다.
모든 브라우저에서 동작하도록 호환성을 지켜준다.
크로스 브라우징이란?
간단하게, 웹 페이지의 상호 호환성 === 서로 다른 브라우저들끼리 서로 호환이 가능하도록 하는 것을 의미한다.
그래서 우리는 각 다른 브라우저 IE, Edge, Chrome, Sfari 들의 호환성을 가능하도록 개발해야한다.
ex) IE는 CSS 속성중 grid가 적용되지 않아 혼란을 줬다. 하지만 IE는 서비스를 종료했다...좋을지도
바벨은 ES6 이상의 코드를 적당한 하위 버전으로 바꾼다.
바뀐 코드는 IE와 같은 구버전 브라우저처럼 최신 자바스크립트 문법을 이해하지 못하는 환경에서
ES6 -> ES5 문법으로 변환하여 이해할 수 있도록 도움을 준다.
바벨을 세 단계를 걸쳐 빌드한다.
src/app.js
const alert = msg => window.alert(msg); // ES6 문법.. IE는 이해 하지 못한다..
바벨을 설치해준다.
npm install -D @babel/core @babel/cli
아래의 바벨 명령어를 사용하면 바벨이 빌드하게 된다.
빌트후 변경된 결과물을 출력한다. (변경되지 않았으면 출력 X)
npx babel app.js
하지만 콘솔에 출력된 결과는? "const alert = msg => window.alert(msg);"
ES6 문법이 ES5 문법으로 변환될 줄 알았지만 변환되지 않은채 콘솔에 찍혔다!
이유를 알아보자...
바벨이 파싱과 변환과 출력 모두를 처리하는 줄 알았는데,
바벨은 파싱과 출력의 역할만 진행하지 변환하는 작업은 하지 못한다.
그래서 바벨을 도와주는 플러그인이 필요하다!
플러그인을 사용하지 않아서 위에서 콘솔이 ES6 문법을 그대로 출력한 이유이다.
커스텀 플러그인을 통해 어떻게 동작되는지 증명을 해보자.
myPlugin.js
module.exports = function myPlugin() {
return {
visitor: {
Identifier(path) {
const name = path.node.name
// 바벨이 만든 AST 노드를 출력한다
console.log("Identifier() name:", name)
// 변환작업: 코드 문자열을 역순으로 변환한다
path.node.name = name.split("").reverse().join("")
},
},
}
}
AST = 추상 구문 트리(abstract syntax tree, AST) | 구문 트리(syntax tree)
플러그인 사용법
npx babel --help
--plugins [list]
npx babel app.js --plugins ./myPlugin.js
// alert AST 노드들이 출력된다.
Identifier() name:
Identifier() name: msg
Identifier() name: window
Identifier() name: alert
Identifier() name: msg
// 코드 문자열을 역순으로 변환한 결과과 출력된다.
const trela = gsm => wodniw.trela(gsm);
const 코드를 var로 변경하는 플러그인을 만들어보자..!
ES6ToES5VariableTransformInPlugin.js
module.exports = function myPlugin() {
return {
visitor: {
// https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-block-scoping/src/index.js#L26
VariableDeclaration(path) {
console.log("VariableDeclaration() kind:", path.node.kind) // const
// const 선언 되어 있는 것을 var로 변환해준다.
if (path.node.kind === "const") {
path.node.kind = "var"
}
},
},
}
}
바벨 빌드
npx babel --plugins ES6ToES5VariableTransformInPlugin.js
VariableDeclaration() kind: const
var alert = msg => window.alert(msg);
const -> var로 변경된걸 확인할 수 있다.
const, let처럼 블록 스코핑을 따르는 예약어를 함수 스코핑으로 사용하는 var로 변환해주는 바벨
여기에서 js 배울 자격이 있는지 검증을 위해 var, let, const 차이점을 나에게 질문해보자.
block-scoping 설치
npm install -D @babel/plugin-transform-block-scoping
바벨 빌드
npx babel --plugins @babel/plugin-transform-block-scoping
var alert = msg => window.alert(msg); // var로 변환된 걸 볼 수 있다.
화살표 함수를 일반 함수로 변환해주는 바벨
arrow-functions 바벨 설치
npm install -D @babel/plugin-transform-arrow-functions
바벨 빌드
npx babel --plugins 1)@babel/plugin-transform-block-scoping --plugins 2)@babel/plugin-transform-arrow-functions
// 1)var로 변환되고 2)화살표 함수에서 일반 함수로 변경되었다.
var alert = function(msg) {
return window.alert(msg);
}
ES6부터 지원하는 엄격 모드를 적용하는 것이 좋다!
엄격 모드 바벨 설치
npm i -D @babel/plugin-transform-strict-mode
바벨 빌드
npx babel --plugins 1)@babel/plugin-transform-block-scoping
--plugins 2)@babel/plugin-transform-arrow-functions
--plugins 3)@babel/plugin-transform-strict-mode
// 3) 엄격 모드 변환
"use strict";
// 1) var로 변환되고
// 2) 화살표 함수에서 일반 함수로 변경되었다.
var alert = function(msg) {
return window.alert(msg);
}
여러 바벨 플러그인을 config 파일로 합쳐보다
babel.config.js
module.exports = {
plugins: [
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-strict-mode"
],
}
이렇게 한땀한땀 플러그인을 설치하는건 비현실적이다.
그래서 목적에 맞게 여러가지 플러그인을 세트로 모아 놓을 것을 프리셋이라고 한다.
목적에 맞게 여러가지 플러그인을 세트로 모아 놓을 것
my-babel-preset.js
위에서 사용한 플러그인을 작성해준다.
module.exports = function myBabelPreset() {
return {
plugins: [
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-strict-mode"
],
}
}
babel.config.js
module.exports = {
presets: [
'./my-babel-config.js',
],
}
바벨 빌드, 동일한 결과가 출력된다.
npx babel app.js
"use strict";
var alert = function(msg) {
return window.alert(msg);
}
바벨을 목적에 따라 프리셋을 제공한다.
ES6를 변환할 때 사용
바벨 7 이전 버전에는 연도별로 각 프리셋을 제공했지만 지금은 env 하나로 합쳐졌다.
flow, 리액트, 타임스크립트를 변환하기 위한 프리셋이다.
preset-env 설치
npm install -D @babel/preset-env
babel.config.js
module.exports = {
presets: ["@babel/preset-env"],
}
바벨 빌드
npx babel app.js
"use strict";
var alert = function alert(msg) {
return window.alert(msg);
};
my-babel-preset.js과 같은 결과 출력하는 것을 볼 수 있다.
preset-env가 ES5로 변환시켜준걸 확인 할 수 있다.
Can I use 에서 브라우저마다 ES6를 이해하는지 확인해보자.
babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env",
{
targets: {
chrome: "79", // 크롬 79까지 지원하는 코드를 만든다
},
},
],
],
}
바벨 빌드
npx babel app.js
"use strict";
const alert = msg => window.alert(msg);
크롬은 ES6 문법을 이해하기 때문에 굳이 변환 해줄 필요가 없다.
ES6 Promise를 사용한다
IE는 Promise를 이해하지 못한다.
플로그인이 Promise를 ES5 문법으로 변환 할 것으로 예상했는데,
어라..? 플러그인은 ES6 -> ES5 로 변환 할 수 있는 것만 변환한다.
이렇게 대체할 수 없게 생기는 것들을 폴리필이라고 명칭한다.
블록 스코핑 -> 함수 스코핑
화살표 함수 -> 일반 함수
변환이 되지만 Promise는 무엇으로 변환 할 건가??
하지만 core-js 를 사용하여 구현은 할 수 있다.
babel.config.js:
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage", // 폴리필 사용 방식 지정 , "usage" , "entry", false 타입 존재, default : false
corejs: {
// 폴리필 버전 지정
version: 2,
},
},
],
],
}
useBuiltIns 를 "usage" , "entry" 값으로 지정하게 되면 core-js를 모듈로 가져온다.
바벨 빌드
npx babel src/app.js
"use strict";
require("core-js/modules/es6.promise");
require("core-js/modules/es6.object.to-string");
new Promise();
이렇게 해주어야 우리 IE가 안전하게 돌아간다.
하지만 이제 IE가 사라져서 useBuiltIns
를 사용할 이유가 사라졌다.
실무에서는 바벨을 직접 사용하는 것보다는 웹팩으로 통합해서 사용한다.
로더 형태로 제공이 되는데 babel-loader 이다.
babel-loader 설치
npm install -D babel-loader
webpack.config.js:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/, // 하위에 있는 것들은 바벨로 변환하지 않도록 제외
},
],
},
}
core-js 설치
npm i core-js@2
웹팩 빌드
npm run build
바벨은 다양한 브라우저에서 크로스브라우징 혼란을 해결해 줄 수 있는 것이다.
모든 브라우저에서 잘 동작하도록 호환성을 지켜준다.
바벨은 파싱과 출력만 하고, 제일 중요한 코드 변환은 플러그인이 처리한다.
여러개의 플러그인들을 모아둔 것을 프리셋이라고 한다. preset-env를 사용하여 ES6 -> ES5으로 변환한다.
바벨이 변환하지 못하는 코드는 폴리필이라 부르는 코드조각을 불러와 로딩한다.
보통을 바벨을 웹팩으로 통합하여 사용한다. 훨씬 단순하고 자동화 된 프론트엔드 개발환경이 될 수 있다!
바벨은 웹팩으로 통합하자~!