Webpack Setting

Webpack Setting


1. 폴더 구조


//React18
├─ dist
├─ package-lock.json
├─ package.json
├─ public
│  └─ index.html
├─ src
│  ├─ App.js
│  ├─ index.js
│  └─ index.css
└─ webpack.config.js

CRA 명령어로 생성한 것 처럼 위와 같이 구성했습니다.  각 폴더별 쓰임새는 아래와 같습니다.

  • public: HTML 템플릿과 이미지 파일 등 절대경로로 쓰이는 파일이 위치하는 장소
  • src: 기본적으로 작성하는 소스코드가 위치하는 장소
  • dist: 웹팩이 번들링된 결과를 저장하는 장소

이렇게 생성한 구조대로 npm 패키지 매니저를 통해 필요한 패키지들을 설치하고 웹팩 설정을 진행하도록 하겠습니다. 먼저 모듈 번들러나 웹팩에 대한 지식이 없는 분들은 아래 포스팅을 먼저 참고해주세요.

JS 모듈 번들러와 웹팩(Webpack) 요즘 회사에서는 Vue를 사용해 프로젝트를 진행하고 있습니다. 이번 1차 프로젝트가 곧 끝나가는데요. 2차도 마찬가지로 Vue를 사용해 개발한다고 합니다. 저는 리액트가 좋은데 말이죠? 아니면 juni-official.tistory.com

2. 패키지 생성


npm init

터미널을 통해 npm 명령어로 패키지를 생성해줍니다. 작성자 및 프로젝트 이름은 개별 설정해줍니다.

3. 패키지 설치


리액트

yarn add react react-dom

웹팩

yarn add webpack webpack-cli webpack-dev-server

웹팩과 플러그인은 개발환경에서만 필요하므로 설치 시 '-D' 또는 '--save-dev' 옵션을 추가해줍니다.

웹팩 플러그인

yarn add babel-loader html-webpack-plugin clean-webpack-plugin css-loader style-loader cross-env dotenv dotenv-webpack
  • babel-loader: 웹팩에서 바벨을 사용할 수 있도록 처리
  • CleanWebpackPlugin: 이전에 번들된 파일 자동 삭제
  • HtmlWebpackPlugin: HTML 템플릿 설정
  • css-loader/style-loader: CSS 관련 파일 처리

바벨

yarn add @babel/core @babel/preset-env @babel/preset-react

트랜스파일러(Transpiler)와 바벨(Babel) 자바스크립트를 공부하다 보면 쉽게 들을 수 있는 폴리필과 바벨에 대해서 다시 공부해보며 기록해본다. 자바스크립트는 현재까지 계속 업데이트되고 있는 언어이다. 그리고 브라우저마다 자 juni-official.tistory.com

3. 웹팩 설정


const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const ESLintPlugin = require("eslint-webpack-plugin"); // eslint 사용할 경우
const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
 
// const isDevelopment = process.env.NODE_ENV !== "production";
// const envPath = `./.env.${isDevelopment ? "development" : "production"}`;
 
// dotenv.config({
//   path: envPath,
// });
 
const config = {
  name: "React18-webpack-babel-setting", // 설정 이름
  mode: "development", // production, development // 설정 모드
  devtool: "eval",
  entry: {
    app: "./src/index.js",
  },
  resolve: {
    extensions: [".js", ".jsx"],
  },
  module: {
    rules: [
      {
        // 리액트 바벨 설정
        test: /\.js/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"],
          },
        },
      },
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: "./public/index.html", // 템플릿 설정
      minify: true, // 압축 설정
    }),
    new webpack.ProvidePlugin({
      // 리액트 자동 로드
      React: "react",
    }),
    new ESLintPlugin(),
    new ReactRefreshWebpackPlugin(),
  ],
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "app.js",
    publicPath: "/",
  },
  devServer: {
    // 개발 서버 설정
    port: 3000, // 포트 설정
    hot: true, // 핫 모듈 교체(HMR) 활성화
    compress: true, // 압축 유무
    open: true, // 기본 브라우저에서 실행
    historyApiFallback: true, // connect-history-api-fallback error 방지
  },
};
 
module.exports = config;

변경 히스토리

+추가)

..
plugins: [
    ..
    new webpack.ProvidePlugin({
        "React": "react",
    })
    ..
]
..

컴포넌트마다 import React from 'react' 선언을 꼭 해줘야 하는데요. ProviderPlugin을 사용하면 리액트 라이브러리가 필요한 곳에는 웹팩이 알아서 넣어줍니다. 물론 CRA를 통해 프로젝트를 만들어도 동일하지만요 :)

moment 같이 자주 사용하는 라이브러리가 있을 경우 추가해 놓으면 상단에 선언 없이 사용할 수 있어 편리합니다.

devServer HMR & 핫 리로딩


yarn add @pmmmwh/react-refresh-webpack-plugin

기존 리로딩은 변경사항이 발생하면 전체가 새로고침 되는데, 변경된 부분만 빠르게 바꿔주는 react-refresh-webpack-plugin을 적용합니다. 해당 라이브러리를 설치하고 플러그인에 추가해줍니다.

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
 
..
    plugins: [
    	...
        new webpack.HotModuleReplacementPlugin(),
        new ReactRefreshWebpackPlugin()
        ...
    ],
    devServer: {// 개발 서버 설정port: 3000,// 포트 설정hot: true,// 핫 모듈 교체(HMR) 활성화compress: true,// 압축 유무open: true,// 기본 브라우저에서 실행historyApiFallback: true,// connect-history-api-fallback error 방지
    }
 
..

devServer와 관련된 설정이 엄청 많아 세부 설정 내용은 아래에서 참고해주세요.

DevServer | 웹팩 웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다. webpack.kr

4. package.json


필요한 패키지 및 웹팩 설정이 끝났습니다. package.json 파일에 스크립트를 작성해주도록 하겠습니다.

// package.json"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "cross-env webpack serve --env development",
    "build": "cross-env NODE_ENV=production webpack"
  }
  • npm run dev: 웹팩 데브 서버 실행 명령어
  • npm run build: 웹팩 번들링 명령어

이제 본격적으로 리액트 코드를 작성할 수 있는 환경을 만들어놨습니다. index.html -> index.js -> app.js 순으로 코드를 작성해보도록 하겠습니다.

5. 코드작성


public/index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello, React18!</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

비주얼 스튜디오에서 ! -> tab 에밋 기능으로 만들어줍니다. 태그에는

태그 하나를 만들어 줍니다.

src/index.js

import ReactDom from "react-dom/client";
import App from "./App";
import "./index.css";
 
const root = document.getElementById("macjjuni");
 
ReactDom.createRoot(root).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
 
// 리액트 18 이전 버전// ReactDom.render(//    <App/>,//    document.getElementById("root")// )

리액트 18 이전 버전에서는 ReactDom.render 함수를 사용했으나 18 이후 ReactDom.createRoot().render 함수로 변경되었습니다.

여기서 리액트 자체를 선언하지 않았는데, 그 이유는 웹팩에서 설정해줬기 때문입니다.

src/app.js

export default function App() {
  return (
    <>
      <div className="wrap">
        <h1 className="title">Hello, React18!</h1>
      </div>
    </>
  );
}

src/index.css

@charset "utf8";
 
* {
    box-sizing: border-box;
    margin: 0 auto;
}
 
.wrap {
    display: flex;
    flex-direction: column;
    justify-content: space-evenly;
    align-items: center;
    width: 100vw;
    height: 100vh;
}
 
.title {
    font-size: 50px;
    font-weight: bold;
    color: skyblue;
}

이제 웹팩 개발 서버를 실행해서 결과를 확인해보겠습니다.

개발서버 실행


yarn dev