방구석에 놔둔 개발 노트

1년차 웹 / 앱 프론트엔드 엔지니어의 좌충우돌 얼렁뚱땅 앞뒤짱구 생존기

2023-10-28: Webpack으로 프로젝트 세팅하(배껴보)기 (1)

😂 프로젝트 세팅은 어떻게 하는거지?

얼마 전 친해지게 된 담 님을 통해서 이런저런 이야기를 하다가, 개발 환경 구축에 대해서 이해하고 싶다면 Webpack으로 환경 구축해볼 것을 권장하는 이야기를 해주셨다.

번들링, 소스맵 등 개발 환경 및 빌드 등을 할 때 알면 좋은 단어도 그렇고, 생각해보니 CRA, CNA 등을 프로젝트를 그냥 깔기만 했지 처음부터 끝까지 세팅해 본 경험은 없었구나.. 싶어서 이참에 Webpack으로 처음부터 끝까지 작업을 진행해보고자 했다.

이번에 적용한 내용들은 사실상 다른 분의 코드를 가져와서 거의 똑같이 쓰는 내용이긴 하지만, 그럼에도 잘 모르는 것에 대해선 각 설정이 어떻게 쓰이는지를 여러가지 검색하면서 알아보니 프로젝트 설정이 어떤 식으로 이루어지는지를 조금은 이해하게 된 것 같다.

본 글은 다른 분의 블로그를 많이 참고(…)하여 사실상 배낀 거지만 Webpack으로 package.json부터 생성하여 React를 개발 환경에 돌리는 것까지를 그려내는 과정, 그리고 그 과정 속에서 알게 된 것들을 추가적으로 정리한 글이다.

참고한 내용들은 맨 아래의 참고 자료들에서 다 모아뒀다.

📦 Webpack으로 프로젝트를 생성해보자!

  1. package.json을 생성하기

아래의 커맨드를 터미널에 입력해 package.json을 생성하자.

$ npm init -y

// 커맨드 입력 후, 아래와 같이 package.json이 생성됐다는 로그가 출력된다.
Wrote to D:\code\project\bundle-practice\webpack-setting\package.json:

{
  "name": "webpack-setting",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
  1. React를 사용하기 위한 필수 라이브러리 설치

다음의 커맨드들을 입력하여 라이브러리를 설치해보자.

// react 라이브러리 설치
$ npm install react react-dom

// typescript와 react type 라이브러리 설치
$ npm install -D typescript @types/react @types/react-dom

// tsconfig.json 파일 생성
$ tsc --init
  1. 본격적인 webpack 설정

기본 라이브러리 설치도 완료됐다면 이제 webpack도 아래와 같이 설치를 진행해주자.

// 웹팩 라이브러리 설치
$ npm install webpack

// 웹팩 command-line interface 설치
$ npm install webpack-cli

// 아래의 패키지 설치
// html-webpack-plugin: 웹팩에서 실행되어 나오는 결과물이 변경될 때마다
// html 파일을 자동으로 수정해주는 플러그인
// webpack-dev-server: 개발할 때 사용하는 웹 개발 서버
// ts-loader: ts 파일을 js로 변환해주는 웹팩 로더
$ npm install html-webpack-plugin webpack-dev-server ts-loader
  1. 개발 환경에 맞게 webpack 설정 적용

webpack 설정 파일을 통해서 개발 환경에서만, 배포 환경에서만, 두 환경 모두에 반영되도록 하는 기능들을 적용할 수 있다.

각 환경 파일은 아래와 같이 구분한다.

  • webpack.common.js
    • 개발 및 배포 모두에 공용적으로 적용할 설정을 관리하는 파일
  • webpack.dev.js
    • 개발 환경에서만 적용될 설정을 관리하는 파일
  • webpack.prod.js
    • 배포 환경에서만 적용될 설정을 관리하는 파일

해당 내용을 학습하기 위해 다른 분이 작성하신 webpack.common.js 파일을 참고하여 webpack에서 쓰이는 각 설정을 정리해봤다.

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = {
  // 개발 환경인지, 배포 환경인지를 설정할 수 있음.
  // development, production 두 가지가 있다.
  mode: "development",

  // 번들링을 시작할 파일을 설정할 수 있다.
  // 해당 파일 안에 import된 파일들을 webpack이 따라가면서 연관 파일을 모두 번들링해준다.
  entry: "./src/index.tsx",

  // 번들링된 결과 파일들에 대한 설정
  output: {
    // 번들링 파일 결과물
    filename: "bundle.js",
    // 번들링 결과 파일 경로
    path: path.resolve(__dirname, "dist"),
    // 번들링 시, 이전에 생성된 번들링 파일을 지울지 설정
    clean: true,
  },

  // 모듈 혹은 파일을 어떻게 해석할 것인지를 설정할 수 있다.
  resolve: {
    // 확장자 설정 - 이 경우, import할 때 확장자를 생략할 수 있다.
    extensions: [".ts", ".tsx", ".js", ".jsx"],
  },

  // 웹팩 기본 제공에 추가적으로 사용할 수 있는 확장 기능
  module: {
    // 각 파일에 적용할 로더를 설정할 수 있다.
    rules: [
      {
        // 로더를 적용할 파일의 확장자를 정규식으로 표현
        test: /\.(js|ts|tsx)$/i,
        // 정규 표현식에 해당되는 파일 중, 로더를 적용하지 않을 케이스를 적용
        exclude: /node_modules/,
        // 위의 로더를 적용할 파일들의 '로더'를 설정
        use: {
          loader: "ts-loader",
        },
      },
    ],
  },

  // 모듈은 번들링할 때에 적용될 확장 기능이라면
  // 플러그인은 위의 아웃풋, 즉 번들링된 결과물에 적용될 확장 기능들이다.
  plugins: [
    // 여기서는 아까 html-webpack-plugin 패키지를 설치했으므로,
    // 자동으로 index.html을 생성해주는 HtmlWebpackPlugin를 추가한다.
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],

    // 개발자 도구를 열 때 출력되는 소스맵을 어떻게 생성할지 규칙을 정한다.
  // [!] 소스 맵: 웹 개발자가 변환된 코드를 디버깅 시, 원본 소스의 어디를 참조해야하는지 도와주는,
  // 원본 코드와 매핑된 코드가 어디서 묶였는지 선언되어있는 파일을 가리킨다.

    // 콘솔 창에 console.log()를 찍으면 어떤 파일에서 이게 찍히는지를 확인할 수 있는 건 모두
    // 소스 맵 덕분이다.

    // inline-source-map은 DataURL이라는 URL 방식으로 소스 맵에 추가되어
    // 에러 코드 표시 시, 브라우저 콘솔에서 원본 코드의 특정 위치를 정확하게 파악할 수 있도록
    // 소스 맵을 참조시켜 준다.
    // 단, 이 방식은 빌드와 리빌드의 속도가 많이 느리다는 단점이 있다.
  devtool: "inline-source-map",

  // 코드가 변경될 때마다 자동으로 컴파일해주도록 하는 웹팩의 개발 서버 설정
  // webpack-dev-server 패키지를 설치하면 이용할 수 있다.
  devServer: {
    // webpack-dev-server를 로컬 환경에서 실행하기 위해 적용할 경로 파일
    static: "./dist",
    // 입력한 정보가 유지된 상태에서 수정된 부분만 바꿀지,
    // 아니면 새로고침 등을 해야만 수정된 정보를 반영할지를 설정함.
    hot: true,
    // 서버가 시작되면 웹 페이지를 자동으로 오픈해줄지 설정함.
    open: true,
  },
};

아래의 코드들은 개발 환경과 배포 환경에서 각각 적용될 설정들이다.

const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");

module.exports = merge(common, {
  mode: "development",
  // eval로 설정하면 모든 코드를 eval을 통해 묶어서 코드를 압축한다.
  // 개발 빌드를 할 때 해당 값을 이용하면 빌드와 리빌드도 빠르게 처리할 수 있다.
  devtool: "eval",
  devServer: {
    // React로 만든 SPA 같은 단일 index.html 페이지에서 history API를 이용해 가짜 주소를 만들어줄 것인지 설정
    // true로 할 경우, 서버에 없는 경로를 있는 것처럼 인식시킬 수 있음.
    historyApiFallback: true,
    // 개발 서버를 열 때, 어떤 로컬 환경 포트로 서버를 띄워줄 것인지 설정
    port: 3000,
    hot: true,
  },
});
const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");

module.exports = merge(common, {
  mode: "production",
  // hidden-이 붙으면 소스맵에 대한 참조를 추가하지 않는다.
  // 이 경우, 에러가 발생 시 번들링된 파일에서만 에러가 참조되기 때문에
  // 정확하게 어느 파일에서 문제가 발생했는지 디버깅 하려운 단점이 있다.
  // 따라서 해당 사항은 배포 빌드에서 주로 쓰인다.
  devtool: "hidden-source-map",
});

우선 여기까지 설정하니까 기가 빨린다..Orz

TypeScript를 사용하지 않는다면 추가 설정 없이 이제 디렉터리나 package.json 설정을 곁들고 확인하면 되지만, TypeScript를 쓰기 때문 tsconfig.json도 설정해야한다.

타입 스크립트 설정에 대해서도 어떤 설정이 있는지 참고해서 공부해보고 다음 글에서 다뤄보도록 하겠다.

🔖 참고 링크

create-react-app 없이 리액트 프로젝트 생성하기(webpack)

[webpack] 플러그인(Plugin) 사용하기

[React] webpack과 babel설정하기

webpack 설정하기

CRA 없이 리액트 시작하기 with webpack

historyApiFallback의 역할

소스 맵의 동작 원리는 무엇일까? | 요즘IT

SourceMap이란 무엇일까?(with webPack devtool)

소스 맵의 동작 원리는 무엇일까? - 재그지그의 개발 블로그

Devtool | 웹팩

Source Maps

source map

Data URL ?