2 minute read

이 글은 프론트엔드 크루 노아가 작성했습니다.

프로젝트를 본격적으로 시작하기 전 기본적인 웹팩 설정을 마무리하였다. 하지만 여러 가지의 이유로 인해 웹팩 설정을 추가하거나 수정해야 하는 경우가 생긴다. 하루스터디의 경우 폰트를 추가하고, png, jpg와 같은 asset 그리고 라우팅으로 인해 웹팩 설정을 추가하고 수정을 해야 했다. 웹팩으로 리액트 시작하기 세 번째 파트에서는 이러한 문제를 해결하는 과정을 다룬다.


1. 폰트 적용하기

폰트 가져오기

서비스에 적용하고 싶은 폰트의 otf파일을 다운받고 프로젝트 내 폴더로 옮긴다. 이후 이를 바탕으로 새로운 @font-face을 만든다. @font-face.css파일에서 만든다.

/* src/fonts/font.css */

@font-face {
  font-family: "S-Core Dream";
  font-style: normal;
  font-weight: 100;
  src: url("./SCDream1.otf") format("woff");
}

@font-face {
  font-family: "S-Core Dream";
  font-style: normal;
  font-weight: 200;
  src: url("./SCDream2.otf") format("woff");
}

/*  */

웹팩 설정하기

webpack을 통해 .css파일을 처리할 수 있도록 loader을 추가한다. 이때, 필요한 loader은 다음 두 가지이다.

  • css-loader: .css파일을 확인하여 객체(배열)를 만든다. 아직 스타일엔 적용되지 않는다.
  • style-loader: css-loader를 통해 만들어진 객체(배열)를 웹 페이지 안에 style태그로 주입한다.

css-loaderstyle-loader을 설치한다.

yarn add -D css-loader style-loader

웹팩에 css-loaderstyle-loader를 추가한다.

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

module.exports = () => {
  const isDevelopment = process.env.NODE_ENV !== "production";

  return {
    // ...

    module: {
      rules: [
        {
          test: /\.(ts|tsx)$/,
          use: {
            loader: "ts-loader",
            options: {
              configFile: path.resolve(__dirname, "tsconfig.json"),
            },
          },
          exclude: /node_modules/,
        },
        // 아래 부분을 추가
        {
          test: /\.css$/,
          use: ["style-loader", "css-loader"], // 순서도 중요하다.
        },
      ],
    },

    // ...
  };
};

2. asset 적용하기

png, jpg등과 같은 asset을 프로젝트에서 사용한다면 webpackAsset Modules을 활용하면 된다.

Asset Modules | 웹팩

Asset Modules에는 4대의 모듈 유형이 있는데 하루스터디에서는 asset/resource를 사용하였다.

  • asset/resource: 별도의 파일을 내보내고 URL을 추출한다. 이전에는 file-loader를 사용하여 처리할 수 있었다.
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = () => {
  const isDevelopment = process.env.NODE_ENV !== "production";

  return {
    // ...

    module: {
      rules: [
        {
          test: /\.(ts|tsx)$/,
          use: {
            loader: "ts-loader",
            options: {
              configFile: path.resolve(__dirname, "tsconfig.json"),
            },
          },
          exclude: /node_modules/,
        },
        {
          test: /\.css$/,
          use: ["style-loader", "css-loader"],
        },
        // 아래 부분을 추가
        {
          test: /\.(png|svg|jpg|jpeg|gif)$/i,
          type: "asset/resource",
        },
      ],
    },

    // ...
  };
};

3. 라우팅 문제 해결하기

다음은 지금까지 프로젝트를 진행하면서 라우팅과 관련하여 마주한 문제는 두가지였다. 이는 모두 웹팩 설정을 통해 해결할 수 있었다.

  1. 직접 주소를 수정하여 페이지에 접근을 하지 못한다.
  2. 라우팅으로 페이지를 이동하고 새로고침하면 접근을 하지 못한다.
  3. 중첩 라우팅에 해당하는 주소로 접근을 하지 못한다.

다음은 이와 같은 문제에 대한 웹팩 설정이다.

historyApiFallback 설정하기

위의 1, 2번 문제는 devServerhistoryApiFallback을 설정하여 해결할 수 있다.

DevServer | 웹팩

  • historyApiFallback: 리액트는 SPA이기 때문에 index.html만 가지고 있다. 하지만 HTML5 History API를 사용하여 라우팅을 하기 때문에 여러 가지 URL이 있는 것처럼 가짜주소를 만들어 준다.
const path = require("path");

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

module.exports = () => {
  const isDevelopment = process.env.NODE_ENV !== "production";

  return {
    // ...

    devServer: {
      historyApiFallback: true, // 추가
      port: 3000,
      hot: false,
    },

    // ...
  };
};

publicPath 설정하기

해당 설정은 위의 3번 문제에 대한 해결 방법이다. 우선 문제 상황은 다음과 같다. /product/:productId 과 같은 중첩 라우팅(Nested Routing)에 접근하고자 한다. navigate 혹은 Link을 통해 이동이 가능하다. 하지만 새로고침을 하거나 직접 주소를 입력하여 접근을 한다면 페이지를 찾을 수 없다. 정확히는 /product/bundle.js를 찾을 수 없다.


이러한 문제를 webpack설정 중 outputpublicPath를 설정하여 해결할 수 있다.

Public Path | 웹팩

  • publicPath: 브라우저가 참고할 번들링 결과 파일의 url 주소를 지정한다.
const path = require("path");

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

module.exports = () => {
  const isDevelopment = process.env.NODE_ENV !== "production";

  return {
    // ...

    output: {
      filename: "bundle.js",
      path: path.resolve(__dirname, "dist"),
      clean: true,
      publicPath: "/", // 추가
    },

    // ...
  };
};

publicPath"/"로 설정함으로써 브라우저는 번들링 결과 파일을 "/"에서 참고한다. 즉, 중첩된 주소에서도 /bundle.js를 참고할 수 있다.