title.png

오늘은 자바스크립트 개발에서 중요한 내용인 웹팩과 바벨을 설정하는 방법에 대해 알아보려 한다. 알아보기 전에 웹팩과 바벨이 무었인지부터 짚어보자.

웹팩이란?

1.png

웹팩 공식문서에서는 웹팩을 자바스크립트 애플리케이션을 위한 정적 모듈 번들러라고 소개하고 있다. 그렇다면 번들러란 무었일까? 번들러는 의존성이 있는 모듈들을 하나의 파일로 통합시켜주는 도구이다. 그렇다면 왜 번들러를 사용할까?

  1. 한번에 많은 요청을 하지 않아도 된다.

    예를 들어 한 웹페이지에서 사용하는 자바스크립트 파일이 10개정도 된다고 가정해보자. 그렇다면 웹 페이지가 로드될 때 자바스크립트 파일 10개롤 모두 네트워크를 통해 요청해서 받아와야 해서 네트워크 병목현상이 발생할 수 있다. (물론 10개의 파일 정도로 병목현상이 발생하지는 않는다. 단순한 예시이다.)

  2. 모듈 단위로 개발하여 유지보수성을 높일 수 있다.

    하나의 파일에 모든 자바스크립트 코드가 있다고 할때 그 코드가 몇 천 라인, 몇 만 라인인지는 모르지만 우리가 수정해야 할 코드에 접근하는데 어려움을 느낄 수 있다. 그렇기 때문에 번들러를 사용하면 우리도 이해하기 쉽도록 코드를 모듈 단위로 구분해 가독성과 유지보수성을 효율적으로 개선할 수 있다.

이 외에도 여러 플러그인이나 트리 쉐이킹같은 기능을 사용해 코드를 압축, 최적화 할 수도 있다. 이만큼 번들러는 많은 기능을 제공한다. 번들러는 웹팩뿐만 아니라 rollup, parcel 등이 존재한다. 하지만 가장 대중적인 번들러가 웹팩이기 때문에 이번 포스트에서는 웹팩을 사용해보려고 한다.

바벨이란?

바벨 공식문서에서는 바벨을 자바스크립트 컴파일러라고 소개하며 최신 자바스크립트 문법을 사용할 수 있다고 나와있다. 더 정확하게 말하면 트랜스파일러라고 말할 수 있다. (트랜스파일러는 한 언어로 작성된 소스 코드를 비슷한 수준의 추상화를 가진 언어로 변환하는 것을 말하며 컴파일러의 일종이다) 그렇다면 왜 바벨이 필요하고 바벨이 있어야만 자바스크립트의 최신 문법을 사용할 수 있을까?

그 이유는 자바스크립트가 실행되는 환경때문이다. 다른 언어와 달리 자바스크립트는 정말 많은 환경에서 실행된다. 웹 브라우저, NodeJS, Deno 등에서 실행되는데 웹 브라우저 또한 각자 다른 자바스크립트 엔진을 통해 자바스크립트 코드를 읽게 된다. 게다가 이렇게 실행되는 환경의 버전에도 자바스크립트는 영향을 받는다. 특정 버전 이상에서만 실행되는 코드가 있고 특정 브라우저에서는 실행되지 않는 코드도 있다. 그렇기 때문에 모든 자바스크립트 실행 환경에서 정상적으로 동작할 수 있도록 하려면 바벨이 필요하다.

q.png

실제로 바벨 공식 페이지에 접속해 보면 바벨이 내 최신 코드들을 어떤식으로 변환해 주는지 쉽게 확인할 수 있다.

바벨 설치

다음과 같이 바벨의 기본 모듈들을 설치해준다.

$npm i -D @babel/core @babel/cli @babel/preset-env

각 모듈은 다음과 같은 역할을 한다.

  • @babel/core: 바벨의 핵심 기능들을 포함
  • @babel/cli: 터미널에서 바벨 명령어를 사용할 수 있게 도와줌
  • @babel/preset-env: 코드 구문 변환 설정을 도와줌 (지원 브라우저 점유율, 호환성 설정 등)

이제 추가적으로 내가 사용하고자 하는 최신 문법 플로그인을 설치해줘야 한다. 바벨 공식문서의 플러그인 메뉴로 이동하면 친절하게 문법마다 필요한 플러그인들을 설명해주고 있다.

2.png

나는 개인적으로 옵셔널체이닝이라는 문법을 아주 좋아하기 때문에 옵셔널 체이닝 플러그인을 찾아봤다. 해당 링크로 들어가보자.

3.png

$npm i -D @babel/plugin-proposal-optional-chaining

링크로 들어오면 다음과 같이 플러그인을 설치하는 방법과 어떤 식으로 바벨에 적용해야 하는지도 나와있다. 그럼 공식 문서대로 플러그인을 설치하고 설정을 적용시켜 보았다.

babel.config.json

{
  "presets": [
    [
      "@babel/env",
      {
        "targets": "> 2%, not dead"
      }
    ]
  ],
  "plugins": ["@babel/plugin-proposal-optional-chaining"]
}

다음과 같이 babel.config.json파일을 생성해 적용하면 된다. presets에는 바벨에 대한 설정을 넣을 수 있는데 다음 코드는 전세계 2%이상의 점유율을 가진 브라우저에서 동작 가능하도록 설정한 옵션이다. 이런식으로 브라우저 점유율을 통해 설정을 할 수도 있고 각 브라우저(크롬, 사파리 등)마다 버전을 지정해 설정해줄 수 도 있다.

웹팩 설치

이제 웹팩을 설치해 바벨과 연결할 것이다. 바벨만 따로 사용할 수도 있지만 웹팩과 연결하면 바벨이 코드들을 트랜스파일링 하면서 웹팩을 통해 모듈들을 번들링할 수 있기 때문에 굉장히 효율적이다.

다음과 같이 웹팩과 css나 이미지 등을 사용할 수 있게 도와주는 모듈들을 설치해준다.

$npm i -D webpack webpack-cli webpack-dev-server
$npm i -D babel-loader css-loader file-loader
$npm i -D html-webpack-plugin mini-css-extract-plugin
$npm i -D sass sass-loader

각 모듈은 다음과 같은 역할을 한다.

  • webpack: 웹팩 모듈
  • webpack-cli: 터미널에서 웹팩 명령어를 사용할 수 있게 도와줌
  • webpack-dev-server: nodemon과 같이 웹팩 환경에서 개발서버를 생성
  • babel-loader: 웹팩과 바벨을 연동
  • css-loader: 웹팩이 css파일을 읽을 수 있도록 도와줌
  • file-loader: 웹팩이 파일을 로딩할 수 있도록 도와줌 (이미지를 로딩하는데 사용)
  • html-webpack-plugin: 번들링된 html파일에 css와 js파일들을 추가해줌
  • mini-css-extract-plugin: style-loader를 대체하며 html내의 style태그 대신 별도의 css파일로 생성해줌
  • sass-loader: 웹팩이 sass파일을 읽을 수 있도록 도와줌

나는 sass도 사용하기 위해 sass-loader를 추가했다. 이제 본격적인 웹팩 설정을 하면 된다.

웹팩 설정

public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

웹팩에서 기준으로 사용할 html파일을 생성해준다.

src/index.js

const root = document.getElementById('root');
root.innerHTML = '웹팩 설정하기!';

웹팩에서 기준으로 사용할 js파일 또한 생성해준다.

webpack.config.js

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

const prod = process.env.NODE_ENV === 'production';

module.exports = {
  // 모드에 따라 웹팩에서 내장 최적화 제공
  mode: prod ? 'production' : 'development',

  // 소스 맵 생성 여부 및 방법 설정
  devtool: prod ? 'hidden-soure-map' : 'eval',

  // 번들링을 시작할 파일
  entry: {
    index: './src/index.js',
  },

  // 다양한 모듈들(js, image, css 등)을 처리하는 방법 결정
  module: {
    rules: [
      {
        // 처리할 모듈 형식 결정
        test: /.js$/,
        // 이 모듈에 사용할 loader
        use: 'babel-loader',
        // 제외할 파일들
        exclude: /node_modules/,
      },
      {
        test: /\.(sc|c)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '/dist/static/style/',
            },
          },
          'css-loader',
          'sass-loader',
        ],
      },
      {
        test: /\.(png|jpg|svg)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              outputPath: 'static/images',
            },
          },
        ],
      },
    ],
  },

  // 빠르게 개발할 수 있도록 개발서버 제공
  devServer: {
    historyApiFallback: true,
    inline: true,
    port: 3000,
    hot: true,
    publicPath: '/',
  },

  // 번들링 된 파일이 생성될 위치 설정
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'static/js/bundle.js',
  },

  // 적용할 플러그인 목록
  plugins: [
    new HtmlWebpackPlugin({ template: `./public/index.html` }),
    new webpack.HotModuleReplacementPlugin(),
    new MiniCssExtractPlugin({ filename: 'static/style/main.css' }),
  ],
};
  • mode: production, development, none 세가지 옵션을 사용할 수 있는데 사용한 옵션에 따라 웹팩에서 내부적으로 최적화를 해준다. 보통 개발시에는 development, 배포시에는 production을 사용한다.
  • devtool: 소스맵 생성 스타일을 결정할 수 있다. 여러 옵션들이 있으며 배포시에는 소스맵을 숨기는게 좋으므로 hidden-soure-map을 사용했다.
  • entry: 번들링을 시작할 파일을 결정할 수 있다. 멀티 페이지 번들링시 여러 파일을 설정할 수도 있는데 그 부분은 추후에 포스팅할 예정이다.
  • module: 다양한 모듈들을 처리하는 방법들을 결정한다. js파일, ts파일을 포함한 이미지파일, 스타일 파일 등 웹팩을 통해 번들링 되는 모든 파일들의 처리 방법을 설정하며 좀전에 설정한 바벨 또한 이 곳에서 설정한다. module을 설정할 때 중요한 부분은 loader를 읽을때 오른쪽에서 왼쪽으로 loader가 실행되기 때문에 sass-loader의 경우 css-loader보다 오른쪽에 위치시켜야 한다. (typescript의 경우에는 babel-loader 오른쪽에 ts-loader를 위치시켜야 한다.)
  • devServer: 개발 서버에 대한 설정을 할 수 있다. 에러처리, 포트 설정, 기본 path 등 여러 옵션을 설정할 수 있으며 자세한 옵션은 다음 페이지를 참고하면 좋다.
  • output: 웹팩을 통해 최종적으로 번들링 된 파일을 저장할 위치를 설정한다.
  • plugins: 웹팩에 적용할 플러그인들을 설정한다.

이제 프로젝트에서 웹팩을 실행시키기 위한 명령어도 설정해야 한다.

package.json

"scripts": {
    "dev": "webpack-dev-server --open --hot",
    "build": "NODE_ENV=production webpack --mode production --env=build"
  }

다음과 같이 개발서버를 실행하기 위한 dev명령어와 빌드를 위한 build명령어를 설정해 줬다.

이제 설정한 이미지, sass가 모두 동작하는지 확인하기 위해 이미지 파일과 sass파일도 추가시켜 줬다.

style.scss

body {
  background-color: #b2dfdb;
}

배경색을 민트색으로 지정해줬다.

src/index.js

import './style.scss';
import cat from './cat.jpg';

const root = document.getElementById('root');

const img = document.createElement('img');
img.src = cat;
img.alt = 'cat';

root.appendChild(img);

그리고는 scss파일과 이미지파일이 적용되는지 확인해야 하기 때문에 고양이 사진을 하나 넣어줬다.

4.png

다행히 dev명령어와 build명령어가 정상적으로 동작하는것을 확인할 수 있었다.

결론

오늘은 바닐라 자바스크립트 + 웹팩 + 바벨의 간단한 설정에 대해 포스팅을 해봤다. 사실 평소에 웹팩과 바벨을 처음부터 커스텀 셋팅을 할 일이 많지 않았다. (대부분 React + Nextjs 조합을 통해 개발을 진행했기 때문이다...) 그래도 웹팩과 바벨에 대한 개념과 원리를 알게 되면 추후에 복잡한 개발환경 설정에도 도움이 될것 같다.