- 크롬, 사파리, 파이어폭스, 엣지와 같은 에버그린 브라우저의 ES6 지원율은 약 98%로 거의 대부분의 ES6 사양을 지원한다.
- 그러나 매년 새롭게 도입되는 ES6 이상의 버전과 제안 단계에 있는 ES 제안 사양(ES.NEXT)은 브라우저에 따라 지원율이 제각각이다.
📍에버그린 브라우저(evergreen browser)
웹 표준을 준수하기 위해 지속적으로 자동 업데이트를 지원하는 모던 브라우저
- 따라서 최신 사양으로 작성된 코드를 경우에 따라 IE를 포함한 구형 브라우저에서 문제없이 동작시키기 위한 개발환경을 구축하는 것이 필요하다.
- 트랜스파일러인 Babel과 모듈 번들러인 WebPack을 이용하여 ES6+/ES.NEXT 개발환경을 구축할 수 있다.
Babel
- 구형 브라우저에서는 ES6의 화살표 함수와 ES7의 지수 연산자를 지원하지 않을 수 있는데 Babel을 사용하면 아래와 같이 ES5 사양으로 변환(트랜스파일링)할 수 있다.
"use strict";
[1, 2, 3].map(function (n) {
return Math.pow(n, n);
});
1️⃣ Babel 설치
# 프로젝트 폴더 생성
$ mkdir esnext-project && cd esnext-project
# package.json 생성
$ npm init -y
# babel-core, babel-cli 설치
$ npm install --save-dev @babel/core @babel/cli
📍설치 완료 후 package.json 파일
{
"name" : "esnext-project",
"version": "1.0.0",
"devDependencies" : {
"@babeL/cli": "^7.10.3",
"@babel/core": "^7.10.3"
}
}
- npm install은 언제나 최신 버전의 패키지를 설치하므로 위의 버전을 설치하고 싶다면 아래와 같이 패키지 이름 뒤에 @과 설치하고 싶은 버전을 지정한다.
# 버전 지정 설치
npm install --save-dev @babel/core@7.10.3 @babel/cli@7.10.3
2️⃣ Babel 프리셋 설치와 babel.config.json 설정 파일 작성
- Babel을 사용하려면 @babel/preset-env를 설치해야 한다.
- @babel/preset-env는 함께 사용되어야 하는 Babel 플러그인을 모아 둔 것으로 Babel 프리셋이라고 부른다.
- Babel이 제공하는 공식 Babel 프리셋은 아래와 같다.
- @babel/preset-env
- @babel/preset-flow
- @babel/preset-react
- @babel/preset-typescript
- @babel/preset-env는 필요한 플러그인들을 프로젝트 지원 환경에 맞추어 동적으로 결정해준다.
- 프로젝트 지원 환경은 Browserslist 형식으로 .browserslistrc 파일에 상세하게 설정할 수 있다.
# @babel/preset-env 설치
$ npm install --save-dev @babel/preset-env
📍설치 완료 후 package.json 파일
{
"name" : "esnext-project",
"version": "1.0.0",
"devDependencies" : {
"@babeL/cli": "^7.10.3",
"@babel/core": "^7.10.3",
"@babel/preset-env": "^7.10.3"
}
}
- 설치가 완료 후 프로젝트 루트 폴더에 babel.config.json 설정 파일을 생성하고 아래와 같이 작성한다.
- 지금 설치한 @babel/preset-env를 사용하겠다는 의미이다.
{
"presets": ["@babel/preset-env"]
}
3️⃣ 트랜스파일링
- Babel을 사용하여 ES6+/ES.NEXT 사양의 소스코드를 ES5 사양의 소스코드로 트랜스파일링할 때 Babel CLI 명령어를 사용할 수도 있으나 트랜스파일링할 때마다 매번 Babel CLI 명령어를 입력하는 것은 버거우므로 npm scripts에 Babel CLI 명령어를 등록하여 사용하는 것이 좋다.
📍scripts 추가 후 package.json 파일
{
"name" : "esnext-project",
"version": "1.0.0",
"scripts": {
"build": "babel src/js -w -d dist/js"
},
"devDependencies" : {
"@babeL/cli": "^7.10.3",
"@babel/core": "^7.10.3",
"@babel/preset-env": "^7.10.3"
}
}
- 위 scripts의 build는 scr/js 폴더(타깃 폴더)에 있는 모든 자바스크립트 파일들을 트랜스파일링한 후 그 결과물을 dist/js 폴더에 저장한다.
- 사용한 옵션의 의미는 아래와 같다.
- -w: 타깃 폴더에 있는 모든 자바스크립트 파일들의 변경을 감지하여 자동으로 트랜스파일한다. (--watch 옵션의 축약형)
- -d: 트랜스파일링된 결과물이 저장될 폴더를 지정한다. 만약 지정된 폴더가 존재하지 않으면 자동 생성한다. (--out-dir 옵션의 축약형)
- 터미널에서 명령어를 입력하여 트랜스파일링을 실행하면 @babel/preset-env가 현재 제안 단계에 있는 사양에 대한 플러그인을 지웒지 않아 에러가 발생한다.
- 이를 해결하기 위해서 별도의 플러그인을 설치해야 한다.
4️⃣ Babel 플러그인 설치
- 설치가 필요한 Babel 플러그인은 Babel 홈페이지에서 검색할 수 있다.
- 클래스 필드 정의 제안 플러그인이 필요하므로 "class field"를 검색한다.
- 검색된 Babel 플러그인 중에서 public/private 클래스 필드를 지원하는 @babel/plugin-proposal-class-properties를 설치한다.
$ npm install --save-dev @babel/plugin-proposal-class-properties
📍설치 완료 후 package.json 파일
{
"name" : "esnext-project",
"version": "1.0.0",
"scripts": {
"build": "babel src/js -w -d dist/js"
},
"devDependencies" : {
"@babeL/cli": "^7.10.3",
"@babel/core": "^7.10.3",
"@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/preset-env": "^7.10.3"
}
}
- 설치한 플러그인은 babel.config.json 설정파일에 추가한다.
{
"presets": ["@babel/preset-env"]
"plugins": ["@babel/plugin-proposal-class-properties"]
}
- 다시 터미널에 명령어를 입력하여 트랜스파일링을 실행한다.
$ npm run build
- 트랜스파일링에 성공하면 프로젝트 루트 폴더에 dist/js 폴더가 자동으로 생성되고 트랜스파일링된 js파일이 저장된다.
5️⃣ 브라우저에서 모듈 로딩 테스트
- 위 모듈 기능은 Node.js 환경에서 동작한 것이고 Babel이 모듈을 트랜스파일링한 것도 Node.js가 기본 지원하는 CommonJS 방식의 모듈 로딩 시스템에 따른 것이다.
- 브라우저는 CommonJS 방식의 require 함수를 지원하지 않으므로 트랜스파일링된 결과를 그대로 브라우저에서 실행하면 에러가 발생한다.
- 브라우저의 ES6 모듈(ESM)을 사용하도록 Babel을 설정할 수도 있으나 ESM을 사용하는 것은 문제가 있기 때문에 Webpack을 통해 문제를 해결하는 것이 좋다.
Webpack
의존 관계에 있는 자바스크립트, CSS, 이미지 등의 리소스들을 하나(또는 여러 개)의 파일로 번들링하는 모듈 번들러
- Webpack을 사용하면 의존 모듈이 하나의 파일로 번들링되므로 별도의 모듈 로더가 필요없다.
- 여러 개의 파일을 하나로 번들링하므로 HTML 파일에서 script 태그로 여러 개의 자바스크립트 파일을 로드해야 하는 번거로움도 사라진다.
1️⃣ Webpack 설치
- 터미널에서 다음과 같이 명령어를 입력하여 Webpack을 설치한다.
$ npm install --save-dev webpack webpack-cli
📍설치 완료 후 package.json 파일
{
"name" : "esnext-project",
"version": "1.0.0",
"scripts": {
"build": "babel src/js -w -d dist/js"
},
"devDependencies" : {
"@babeL/cli": "^7.10.3",
"@babel/core": "^7.10.3",
"@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/preset-env": "^7.10.3"
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
}
}
2️⃣ babel-loader 설치
$ npm install --save-dev babel-loader
- npm scripts를 변경하여 Babel 대신 Webpack을 실행하도록 수정한다.
📍scripts 수정 후 package.json 파일
{
"name" : "esnext-project",
"version": "1.0.0",
"scripts": {
"build": "webpack -w"
},
"devDependencies" : {
"@babeL/cli": "^7.10.3",
"@babel/core": "^7.10.3",
"@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/preset-env": "^7.10.3",
"babel-loader": " ^8.1.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
}
}
3️⃣ webpack.config.js 설정 파일 작성
- webpack.config.js는 Webpack이 실행될 때 참조하는 설정 파일이다.
- 루트 폴더에 webpack.config,js 파일을 생성하고 아래와 같이 작성한다.
const path = require('path');
module.exports = {
// entry file
// https://webpack.js.org/configuration/entry-context/#entry
entry: './src/js/main.js',
// 번들링된 js 파일의 이름(filename)과 저장될 경로(path)를 지정
// https://webpack.js.org/configuration/output/#outputpath
// https://webpack.js.org/configuration/output/#outputfilename
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js'
},
// https://webpack.js.org/configuration/module
module: {
rules: [
{
test: ∧.js$/,
include: [
path.resolve(__dirname, 'src/js')
],
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-class-properties' ]
}
}
]
},
devtool: 'source-map',
// https://webpack.js.org/configuration/mode
mode: 'development'
};
- Webpack을 실행하면 트랜스파일링은 Babel이 수행하고 번들링은 Webpack이 수행한다.
- 이전에 실행시킨 빌드 명령이 실행중인 상태라면 주지시키고 다시 다음 명령을 실행한다.
$ npm run build
- 성공적으로 실행하면 dist/js 폴더에 자바스크립트 모듈을 하나로 번들링한 bundle.js가 생성된다.
4️⃣ babel-polyfill 설치
- Babel을 사용하여 ES6+/ES.NEXT 사양의 소스코드를 ES5 사양의 소스코드로 트랜스파일링해도 브라우저가 지원하지 않는 코드가 남아 있을 수 있다.
- Promise, Object.assign, Array.from등과 같이 ES5 사양으로 대체할 수 없는 기능은 트랜스파일링되지 않는다.
- 따라서 구형브라우저에서 위와 같은 객체나 메서드를 사용하기 위해서는 @babel/polyfill을 설치해야 한다.
$ npm install @babel/polyfill
📍설치 완료 후 package.json 파일
{
"name" : "esnext-project",
"version": "1.0.0",
"scripts": {
"build": "webpack -w"
},
"devDependencies" : {
"@babeL/cli": "^7.10.3",
"@babel/core": "^7.10.3",
"@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/preset-env": "^7.10.3",
"babel-loader": " ^8.1.0",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"@babel/polyfill": "^7.10.1"
}
}
- @babel/polyfill은 개발환경에서만 사용하는 것이 아니라 실제 운영환경에서도 사용해야하므로 개발용 의존성으로 설치하는 --save-dev 옵션을 지정하지 않는다.
- ES6의 import를 사용하는 경우에는 진입점의 선두에서 먼저 폴리필을 로드하도록 한다.
- Webpack을 사용하는 경우에는 위 방법 대신 webpack.config.js 파일의 entry 배열에 폴리필을 추가한다.
'Web > JS' 카테고리의 다른 글
[JS] 모던 자바스크립트 Deep Dive - 48. 모듈 (1) | 2024.10.12 |
---|---|
[JS] 모던 자바스크립트 Deep Dive - 47. 에러처리 (0) | 2024.10.11 |
[JS] 모던 자바스크립트 Deep Dive - 46. 제너레이터와 async/await (0) | 2024.10.04 |
[JS] 모던 자바스크립트 Deep Dive - 45. 프로미스 (0) | 2024.10.04 |
[JS] 모던 자바스크립트 Deep Dive - 44. REST API (0) | 2024.09.28 |