[자바스크립트] Babel과 Webpack

효효·2024년 10월 11일

자바스크립트

목록 보기
5/6

Babel

Babel이란?

  • 추상화 수준을 유지한 채로 코드를 변화시키는 트랜스파일러이다
  • 바벨을 통해 ES6+의 자바스크립트 코드는 하위 버전으로 변환되고, 그로 인해 IE나 다른 브라우저에서 동작할 수 있게 만든다

설치 방법

# 프로젝트 폴더 생성
$ mkdir esnext-project && cd esnext-project
# package.json 생성
$ npm init -y
# bable-core, babel-cli 설치
$ npm install --save-dev @babel/core @babel/cli

프리셋 설치와 babel.config.json 설정 파일 작성

  • Babel을 사용하려면 @babel/preset-env를 설치해야 한다
  • 프리셋은 @babel/preset-env과 함께 사용되어야 하는 Babel 플러그인을 모아둔 것이다
  • @babel/preset-env는 필요한 플러그인들을 프로젝트 지원 환경에 맞춰 동적으로 결정해 준다. 프로젝트 지원 환경은 Browserslist 형식으로 .browerslistrc 파일에 상세히 설정할 수 있다.
# @babel/preset-env 설치
$ npm install --save-dev @babel/preset-env
  • 설치가 완료되면 프로젝트 루트 폴더에 babel.config.json 설정 파일을 생성하고 아래와 같이 작성한다
{
  "presets":["@babel/preset-env"]
}

트랜스파일링

  • Babel CLI 명령어도 있지만 npm scripts에 Babel CLI 명령어를 등록해서 사용할 수 있다
  • package.json 파일에 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",
  }
}
  • -w는 타깃 폴더에 있는 모든 자바스크립트 파일들의 변경을 감지하여 자동으로 트랜스파일한다
  • -d는 트랜스파일링된 결과물이 저장될 폴더를 지정한다. 만약 지정된 폴더가 존재하지 않으면 자동 생성한다
  • 이제 트랜스파일링을 테스트하기 위해 ES6+/ES.NEXT 사양의 자바스크립트 파일을 작성해보자. 프로젝트 루프 폴더에 src/js 폴더를 생성한 후 lib.js와 main.js를 추가한다
// src/js/lib.js
export const pi = Math.PI; // ES6 모듈

export function power(x,y) {
  return x ** y;
}

// ES6 클래스
export class Foo {
  #private = 10; 
  
  foo() {
    const {a,b, ...x} = {...{a:1,b:2},c:3,d:4};
    return {a,b,x};
  }

  bar() {
  	return this.#private;
  }
}
// src/js/main.js
import * from './lib';

console.log(pi);
console.log(power(pi,pi));

const f = new Foo();
console.log(f.foo());
console.log(f.bar());
  • 터미널에서 아래와 같이 명령어를 입력하여 트랜스파일링을 실행한다
npm run build
  • 명령어를 실행하면 에러가 발생한다. @babel/preset-env가 현재 제안 단계에 있는 사양에 대한 플러그인을 지원하지 않기 때문에 별도의 플러그인을 설치해야 한다

플러그인 설치

  • Babel 공식사이트에서 원하는 플러그인을 검색할 수 있다
  • 검색된 플러그인 중에서 public/private 클래스 필드를 지원하는 @babel/plugin-proposal-class-properties를 설치하자
$ npm install --save-dev @babel/plugin-proposal-class-properties
  • 설치한 플러그인은 babel.config.json 설정 파일에 추가해야 한다. babel.config.json 설정 파일을 아래와 같이 수정한다
{
  "presets":["@babel/preset-env"],
  "plugins":["@babel/plugin-proposal-class-properties"]
}
  • 다시 npm run build를 입력하여 트랜스파일링을 실행하면 성공할 수 있다.

브라우저에서 모듈 로딩 테스트

  • 지금까지 예제의 모듈 기능은 Node.js 환경에서 동작한 것이고 Babel이 모듈을 트랜스파일링한 것도 Node.js가 기본 지원하는 CommonJS 방식의 모듈 로딩 시스템에 따른 것이다.
  • 브라우저는 CommonJS 방식의 require 함수를 지원하지 않으므로 위 예제로 트랜스파일링된 파일을 브라우저에서 실행하면 에러가 발생한다.
  • 브라우저의 ESM을 사용하도록 Babel을 설정할 수도 있으나 앞서 설명한 바와 같이 ESM을 사용하는 것은 문제가 있고, 이러한 문제를 Webpack에서 해결할 수 있다

Webpack

Webpack이란?

  • 의존 관계에 있는 자바스크립트, CSS, 이미지 등의 리소스들을 하나의 파일로 번들링하는 모듈 번들러다.
  • 의존 모듈이 파일로 번들링되므로 별도의 모듈 로더가 필요 없다.
  • 여러 개의 자바스크립트 파일을 하나로 번들링하므로 HTML 파일에서 script 태그로 여러 개의 자바스크립트 파일을 로드해야 하는 번거로움도 사라진다

설치 방법

$ npm insatll --save-dev webpack webpack-cli

babel-loader 설치

  • Webpack이 모듈을 번들링할 때 Babel을 사용하여 ES6+/ES.NEXT 사양의 소스코드를 ES5 사양의 소스코드로 트랜스파일링하도록 babel-loader를 설치한다
$ npm install --save-dev babel-loader
  • npm scripts를 변경하여 Babel 대신 Webpack을 실행하도록 수정한다
{
  "name":"esnext-project",
  "version":"1.0.0",
  "scripts":{
    "build": "webpack -w"
  },
  "devDependencies":{
    "@babel/cli": "^7.10.3",
    "@babel/core": "^7.10.3",
    "@babel/preset-env": "^7.10.3",
    "webpack":"^4.43.0",
    "webpack-cli":"^3.3.12"
  }
}

webpack.config.js 설정 파일 작성

  • webpack.config.js는 Webpack이 실행될 때까지 참조하는 설정파일이다. 프로젝트 루트 폴더에 webpack.config.js 파일을 생성하고 다음과 같이 작성한다
//webpack.config.js

const path = require("path");

module.exports = {
  entry: "./src/js/main.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "js/bundle.js",
  },
  module: {
    rule: [
      {
        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",
  mode: "development",
};
  • npm run build 명령어를 통해 Webpack을 실행하면 dist/js 폴더에 bundle.js가 생성되었다. 이 파일을 main.js, lib.js 모듈이 하나로 번들링된 결과물이다. index.html을 다음과 같이 수정하고 브라우저에서 실행해보자
<!DOCTYPE html>
<html>
<body>
	<script src="dist/js/bundle.js"></script>
</body>
</html>
  • main.js, lib.js 모듈이 하나로 번들링된 bundle.js가 브라우저에서 문제없이 실행된 것을 확인할 수 있다

babel-polyfill 설치

  • Babel을 사용하여 ES9+ES.NEXT의 사양의 소스코드를 ES5 사양의 소스코드로 트랜스파일링해도 브라우저가 지원하지 않는 코드가 남아 있을 수 있다.
  • src/js/main.js를 다음과 같이 수정하여 Promise, Object.assign, Array.from 등이 어떻게 트랜스파일링 되는지 확인해보자.
//src/js/main.js
import { pi, power, Foo } from "./lib";

console.log(pi);
console.log(power(pi, pi));

const f = new Foo();
console.log(f.foo());
console.log(f.bar());

// polyfill이 필요한 코드
console.log(
  new Promise((resolve, resject) => {
    setTimeout(() => resolve(1), 100);
  })
);

// polyfill이 필요한 코드
console.log(Object.assign({}, { x: 1 }, { y: 2 }));

// polyfill이 필요한 코드
console.log(Array.from([1, 2, 3], (v) => v + v));

다시 트랜스파일링과 번들링을 실행한 다음, dist/js/bundle.js를 확인해보자.

console.log(new Promise(function (resolve, reject) {
	setTimeout(function ()
		return resolve(1);
	}, 100);
})); // polyfill이 필요한 코드

// polyfill이 필요한 코드
console.log(Object.assign({}, {
 x: 1
}, {
 y: 2
}));

// polyfill이 필요한 코드
console.log(Array.from([1, 2, 3], function (v) {
	return v + v;
}));
  • 이처럼 Promise, Object.assign, Array.from 등과 같이 ES5 사양으로 대체할 수 없는 기능은 트랜스파일링 되지 않는다. 따라서 구형 브라우저에서도 Promise, Object.assign, Array.from 같은 객체나 메서드를 사용하기 위해서는 @babel/polyfill을 설치해야 한다.
$npm install @babel/polyfill
  • @babel/polyfill은 개발 환경에서만 사용해야하는 것이 아니라 실제 운영 환경에서도 사용해야한다. 따라서 —save-dev 옵션을 지정하지 않는다.

  • ES6의 import를 사용하는 경우에는 진입점의 선두에서 먼저 폴리필을 로드하도록 한다.

import "@babel/polyfill";
import { pi, power, Foo } from "./lib";
...
  • Webpack을 사용하는 경우에는 위 방법 대신 webpack.config.js 파일의 entry 배열에 폴리필을 추가한다.
const path = require('path');

module.exports = {
	...
	entry: ['@babel/polyfill', './src/js/main.js'],
	...
}
  • 위와 같이 폴리필을 반영한 뒤 Webpack을 실행한 후, dist/js/bundle.js를 확인해보면 폴리필이 추가된 것을 확인할 수 있다.

- 출처 : 모던 자바스크립트 딥다이브 책

profile
효효 개발공부로그

0개의 댓글