TypeScript 개발환경설정 2탄 (Webpack + Babel + ESLint + Prettier)- 바벨 설정, 웹팩 통합하기

허상범·2022년 9월 16일
2
post-thumbnail

타입스크립트 보일러플레이트 바로가기
https://github.com/sangbeomheo/typescript-boilerplate


2탄: 바벨, 폴리필을 설정하고 웹팩으로 통합해서 빌드해보기(babel7, preset, polyfill, babel-loader)


1. 바벨 간단 정리

1.1 바벨의 역할

Babel is a JavaScript compiler

Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.

Babel은 자바스크립트 컴파일러입니다
Babel은 현재 및 이전 브라우저 또는 환경에서 ECMAScript 2015+ 코드를 이전 버전의 JavaScript로 변환하는 데 주로 사용되는 도구 체인입니다.

https://babeljs.io/docs/en/#es2015-and-beyond

  • 프론트엔드 어플리케이션은 실행되는 브라우저가 다양하기 때문에 크로스 브라우징 이슈가 있다.
  • 바벨은 ECMAScript2015+로 작성한 코드를 다양한 브라우저에서 동작할 수 있도록 해준다.

1.2 바벨의 기본 동작

바벨의 빌드 과정
파싱(Parsing) => 변환(Transforming) => 코드생성(Generating)


  1. 파싱(Parsing)
  • 문자열로 입력되는 코드를 AST(추상화구문트리) 변환한다.
  • AST는 바벨의 플러그인 중 하나인 babel-parser에 의해 작성된다.
  • babel-parserbabylon이라고도 불린다.

  1. 변환(Transforming)
  • 이 과정이 핵심이다.
  • 파싱한 추상구문트리를 받아와 원하는 브라우저 환경에 맞는 결과로 코드를 변환한다.
  • 변환 과정은 preset/plugin이 담당한다. 그래서 프리셋 플러그인을 설정하지 않으면 바벨을 실행해도 변환이 이루어지지 않는다.
  • 이 단계에서 생성되는 새로운 추상구문트리는 각 브라우저에서 코드 구문이 어떻게 변환되야하는지 담겨있다.

  1. 코드생성(Generating) :
  • 변환 단계에서 생성된 새로운 추상구문트리를 바탕으로 브라우저 환경에 맞는 소스코드로 변환하는 과정이다.

2. 바벨 설치하기

2.1 바벨 설치

  • 바벨과 커맨드라인 도구를 설치
npm install -D @babel/core@7.19.0  @babel/cli@7.18.10

  • 이제 터미널에서 명령어로 바벨을 동작할 수 있다.
npx babel app.js

2.2 잘 동작하는지 확인해보자!!

  • 빌드 결과
    • 명령어를 입력하면 터미널 창에 변환된 코드를 확인할 수 있다.
    • 아직 플러그인 설정을 하지 않았기 때문에 기존 코드와 동일한 코드가 반환된다.


3. 프리셋(Preset)

https://babeljs.io/docs/en/presets

3.1 프리셋

  • 바벨이 지원하는 플러그인은 매우 많다. 목적에 맞게 플러그인을 일일이 설정하는 것은 굉장히 번거롭다. 그래서 목적에 맞게 플러그인들을 모아놓은 '프리셋'이 있다.
  • ES2015+ 구문 컴파일을 위한 @babel/preset-env
  • TypeScript를 위한 @babel/preset-typescript
  • React를 위한 @babel/preset-react
  • Flow를 위한 @babel/preset-flow

3.2 프리셋 설치

  • 타입스크립트 보일러플레이트이기 때문에 @babel/preset-env, @babel/preset-typescript 두 가지 프리셋을 설치해야 한다.
npm install -D @babel.preset-env@7.19.0 @babel/preset-typescript@7.18.6

  • 바벨 설정 파일을 생성한다. ./babelrc.json
{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-typescript"
  ]
}

3.3 잘 동작하는지 확인해보자!!

  • ECMAScript2015+로 작성한 코드가 ES5문법으로 변환됐다.

3.4 프리셋 Targets 설정

구체적인 targets 설정은 공식문서를 확인해보자.
https://babeljs.io/docs/en/options#targets

  • env 프리셋은 원하는 타겟 브라우저 환경을 입력하면 해당 환경에 맞춰 최신 EcmaScript를 사용할 수 있게 해준다.
  • 아래는 두 가지 타겟 환경 설정 예시이다. (참고 링크)
  • 브라우저 점유율 또는 명시적인 버전으로 설정할 수 있다.
//browserslist-compatible query
{
  "presets": [
    ["@babel/preset-env", {
      "targets": "> 0.25%, not dead"
    }],
  ]
}

//mininum version
{
  "presets": [
    ["@babel/preset-env", {
      "targets": {"chrome": "58", "ie": "11"}
    }],
  ]
}

4. 폴리필(Polyfill)

https://babeljs.io/docs/en/babel-polyfill

4.1 바벨에게 닥친 문제

바벨은 최신 버전 문법의 자바스크립트 코드를 원하는 구형 자바스크립트 문법의 코드로 변환한다.
그렇다면 ES2015에서 아예 새롭게 등장한 Promise, Map, Set, Object.assign 등은 바벨이 처리할 수 있을까?

  • 바벨은 해당 코드를 처리하지 못한다. ES2015에서 등장한 문법을 사용하면 변환하지 않고 그대로 코드를 반환한다.
  • 그래서 ES2015 환경을 지원하지 않는 브라우저에서는 코드가 동작하지 않는다.

  • 아래는 ES2015에서 지원하는 신규 문법 코드를 바벨로 변환을 시도한 내용이다. 새로운 문법 코드가 그대로 다시 반환된 것을 확인할 수 있다.


4.2 폴리필

  • 폴리필은 솜이 꺼졌을 때 채워넣는 충전솜을 뜻한다.
  • 신규 문법을 구버전에서 동작할 수 있도록 기능을 추가해줘야 한다.
  • 폴리필은 브라우저에서 지원하지 않는 코드를 사용가능하게 기존 함수의 동작 방식을 수정하거나 새롭게 구현한 함수의 스크립트라고 할 수 있다.

4.3 core-js

core-js는 폴리필을 위한 자바스크립트 표준 모듈이다. 필요한 기능만 로드하거나 전역 네임스페이스 오염없이 사용할 수 있다.

https://github.com/zloirock/core-js (구체적인 사용 예시 참고)
https://babeljs.io/docs/en/babel-preset-env#corejs


  • @babel/preset-env 에서 폴리필을 처리하는 방법을 설정할 수 있다.
    • useBuiltIns : 폴리필 삽입에 대한 옵션.
      • usage : 실제 사용한 폴리필만 삽입
      • entry : 타깃 환경에 필요한 폴리필만 전역 스코프에 추가, core-js/stable과 regenerator-runtime/runtime 모듈을 전역 스코프에 직접 삽입한 경우에만 가능하다.
    • corejs : corejs 버전을 명시

  • corejs 설치하기
npm install core-js@3.25.1

  • 폴리필 설정하기
// .babelrc.json
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": ">= 0.25%, not dead",
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ]
}

4.4 잘 동작하는지 확인해보자!!

  • 폴리필 설정을 추가하고 다시 바벨을 실행해보자.
  • 코드에 사용된 내용들 중에 폴리필이 필요한 문법에 대한 모듈이 추가된 것을 확인할 수 있다.


5. 웹팩과 통합하기(babel-loader)

  • 바벨을 웹팩으로 통합헤서 사용할 수 있다. 로더 형태로 제공된다.

5.1 babel-loader

  • 바벨 로더를 설치한다.
npm install -D babel-loader
  • 웹팩에 바벨 로더를 추가한다.
// webpack.config.js:
module.exports = {
  module: {
    rules: [
      // ...
      {
        test: /\.ts$/,
        exclude: /node_modules/, // node_mudules를 제외한다.
        loader: "babel-loader",
      },
      // ...
    ],
  },
}

5.2 잘 동작하는지 확인해보자!!

  • 웹팩을 실행하면 필요한 모듈(폴리필)을 가져오는 걸 확인할 수 있다.

  • 번들링된 파일에서 바벨, 폴리필이 잘 동작하는 것을 확인할 수 있다.

6. 최종 파일

6.1 webpack.config.js

const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const mode = process.env.NODE_ENV || 'development';

module.exports = {
  mode,
  entry: {
    main: './src/app.ts',
  },
  output: {
    filename: '[name].js',
    path: path.resolve('./dist'),
    assetModuleFilename: 'assets/[name][ext]',
    clean: true,
  },
  module: {
    rules: [
      {
        test: /\.(scss|css)$/,
        use: [
          process.env.NODE_ENV === 'production'
            ? MiniCssExtractPlugin.loader
            : 'style-loader',
          'css-loader',
          'sass-loader',
        ],
      },
      {
        test: /\.(png|jpg|svg|gif)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 4 * 1024,
          },
        },
      },
      {
        test: /\.(ts|js)$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
      },
    ],
  },
  plugins: [
    new webpack.BannerPlugin({
      banner: `
        Build Date :: ${new Date().toLocaleString()}
        Author :: ${childProcess.execSync('git config user.name')}`,
    }),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      templateParameters: {
        env: process.env.NODE_ENV === 'development' ? '(개발용)' : '',
      },
      hash: true,
      minify:
        process.env.NODE_ENV === 'production'
          ? {
              collapseWhitespace: true,
              removeComments: true,
            }
          : false,
    }),
    ...(process.env.NODE_ENV === 'production'
      ? [new MiniCssExtractPlugin({ filename: `[name].css` })]
      : []),
  ],
};

6.2 .babelrc.json

{
  "presets": [
    [    
      "@babel/preset-env",
      {
        "targets": ">= 0.25%, not dead",
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ],
    "@babel/preset-typescript"
  ]
}


참고자료

https://babeljs.io/
https://mhk-bit.medium.com/babel-under-the-hood-63e3fb961243
https://tech.kakao.com/2020/12/01/frontend-growth-02/
https://jeonghwan-kim.github.io/series/2019/12/22/frontend-dev-env-babel.html
https://github.com/zloirock/core-js
https://babeljs.io/docs/en/babel-preset-env#corejs

0개의 댓글