자바스크립트 개발 환경: 웹팩과 바벨

Dodam·2024년 1월 25일
0
post-thumbnail

웹팩이란?

웹팩이란 최신 프론트엔드 프레임워크에서 가장 많이 사용되는 모듈 번들러로, 웹 애플리케이션을 구성하는 자원(HTML, CSS, JavaScript)을 모두 각각의 모듈로 보고 이를 조합해서 병합된 하나의 결과물을 만드는 도구이다.

의존성을 분석해 모듈을 번들시켜주는 역할을 하며, 프로젝트를 개발할 때 사용하는 수많은 라이브러리들을 빌드(build) 과정을 통해 하나의 파일로 만들어준다.

웹팩이 등장한 이유

  • 파일 단위의 자바스크립트 모듈 관리의 필요성
  • 웹 개발 작업 자동화 도구 (Web Task Manager)
  • 웹 애플리케이션의 빠른 로딩 속도와 높은 성능

바벨이란?

바벨은 기본적으로 자바스크립트의 최신 문법 및 사양을 지원하지 않는 브라우저에서도 쓸 수 있게끔 변환해주는 트랜스파일러이다.

트랜스파일러 : 한 언어로 작성된 소스 코드를 비슷한 수준의 추상화를 가진 언어로 변환하는 것을 말하며, 컴파일러의 일종이다.


바벨을 사용하는 이유는?
자바스크립트는 웹 브라우저, NodeJS 등 수많은 환경에서 실행되며, 실행되는 환경의 버전에 따라서도 영향을 받는다. 특정 버전 이상에서만 실행되는 코드가 있고, 특정 브라우저에서는 실행되지 않는 코드도 있다. 그렇기 때문에 모든 자바스크립트 실행 환경에서 정상적으로 동작할 수 있도록 하려면 바벨이 필요하다.

예) ES6 이후 버전의 자바스크립트를 대부분의 브라우저에 호환시키기 위해서 바벨을 이용해 호환 가능한 ES5 버전으로 낮춘 다음 사용하는 경우

변환 전

// 화살표 함수 (ES6)
// 지수 연산자 (ES7)
[1, 2, 3].map(n => n ** n);

변환 후

// ES5
"use strict";

[1, 2, 3].map(function (n) {
  	return Math.pow(n, n);
});

바벨 설치

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

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

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

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

이제 추가적으로 내가 사용하고자 하는 최신 문법 플러그인을 설치해야 한다.

예를 들어 옵셔널 체이닝이라는 문법을 사용하고자 할 경우, 바벨 공식문서의 플러그인 메뉴로 이동하면 해당 플러그인을 설치하는 방법과 바벨에 적용하는 방법 등이 자세히 나와있다.

공식 문서를 따라 플러그인을 설치하고 설정을 적용시킨다.

@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파일을 읽을 수 있도록 도와줌

웹팩 설정

public/index.html
웹팩에서 기준으로 사용할 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>

src/index.js
웹팩에서 기준으로 사용할 js 파일도 생성해준다.

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

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, css, image 등)을 처리하는 방법 결정
  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, node 세 가지 옵션을 사용할 수 있는데, 사용한 옵션에 따라 웹팩에서 내부적으로 최적화를 해준다. 보통 개발시에는 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
다음과 같이 개발서버를 실행하기 위한 dev 명령어와 빌드를 위한 build 명령어를 설정해준다.

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

style.scss
설정한 이미지, sass가 모두 동작하는지 확인하기 위해 이미지 파일과 sass 파일을 추가한다.

// 배경색을 민트색으로 지정
body {
	background-color: #b2dfdb;
}

src/index.js
scss 파일과 이미지 파일이 적용되는지 확인하기 위해 사진을 하나 넣어준다.

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);
profile
Good things take time

0개의 댓글