본문 바로가기
FrontEnd/React.js

[React.js] 제로초 웹게임 - 2. 끝말잇기 (Webpack, Babel)

by Chaedie 2022. 10. 22.
728x90

강의를 통해 배운 것

리액트를 배울 때 애초에 CRA로 시작했고, 그렇기 때문에 파일 구조가 컴포넌트 단위로 또는 페이지 단위로 분리 되어있다는 걸 크게 의식하지 않고 사용했었다. 하지만 실제로 "index.html"에 script 태그 안에 파일을 다 밀어 넣는다는 생각을 먼저 하고, 해당 소스코드를 파일로 나누는걸 어떻게 하는거지? 라는 생각을 해보니 "webpack"의 중요성이나 webpack이 나오게 된 계기를 알게 되었다.

끝말잇기 컴포넌트는 1강 구구단과 크게 다를 게 없어서 만드는게 엄청나게 간단했는데, 웹팩 설정하는건 정

오래 걸렸다. 분명히 강의를 보면서 따라하는 것인데도 에러가 계속적으로 나왔고, 심지어 강의 구조도 2019년 강의에서 2020년 강의로 2021년 강의로 다시 2019년 강의로 타임머신을 타는 걸 경험했다. 이게 다 웹팩 설정 때문이고, 버젼 업이 되면 설정도 달라지고 해서 그랬는데, 정말 쉽지 않은 과정이었다.

하지만 쉽지 않은 과정인 만큼 더욱 값진 경험이었다고 생각한다. 웹팩, 바벨과 같은 프로젝트 세팅을 제대로 알아야 성능최적화를 알게 되고, 나중에 SSR이나 SSG에 대해 공부할 때도 더욱 감이 잘 오지 않을까? 하는 기대감이 있다. 언제까지 남이 짜준 CRA만 사용할 순 없고, 혹여 CRA나 vite를 사용한다 하더라도 내가 직접 세팅에 대해 이해하고 있어야 훨씬 좋은 개발이 되지 않을까? 생각한다.

아래 글은 강의를 들으며 적은 글이라 굉장히 어지러운데, 그냥 아카이빙용으로 퇴고 없이 저장해 둘 예정이다.


2. 끝말잇기

Webpack - Babel

npm init

npm i react react-dom

npm i -D webpack webpack-cli

//@webpack.config.js
module.exports = {};

//@client.jsx
const React = require('react');
const ReactDom = require('react-dom');
//@index.html
<!DOCTYPE html>
<html lang="en">
  <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>끝말잇기</title>
  </head>
  <body>
    <div id="root"></div>
    <script src=".dist/app.js"></script>
  </body>
</html>

이렇게 하는게 webpack 기본 세팅이다.

이것 + 좀 더 세팅하는게 CRA이다.

// @webpack.config.js
const path = require('path'); // node에서 경로 조작하는 path라는 애가 있다.

module.exports = {
  name: 'word-relay-setting',
  node: 'development', // 실서비스 : production
  devtool: 'eval', // 빠르게 하겠다.
  entry: {
    app: ['./client'],
  }, // 입력
  output: {
    path: path.join(__dirname, 'dist'),
    // path.join 하면 경로를 알아서 합쳐준다.
    // 현재 폴더 안에 있는 dist
    // /react-webgame/2-끝말잇기/dist (현재폴더 안에 있는 dist를 픽해준다.)
    filename: 'app.js',
  }, // 출력
};

위처럼 세팅을 한 뒤, cli에 webpack이라고 치면 알아서 해준다.

근데 webpack이 명령어로 등록이 안되어 있다.

⇒ 명령어로 등록을 해주거나

⇒ scripts에 적어주면 된다. package.json에 scripts에 "dev" : "webpack"

⇒ npx 를 같이 쳐주면 된다. npx webpack

❌ 그럼 에러가 나면서 webpack이 제대로 실행이 안된다.

왜냐면 webpackt setting은 했지만 아직 babel세팅을 안해서 jsx 문법을 읽지 못하기 때문이다. 그래서 다시 babel을 npm을 통해 설치하자.

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

npm i -D @babel/preset-react babel-loader

@babel/core : 바벨 기본

@babe/preset-env : 환경에 맞춰서 문법 맞춰줌

@babel/preset-react : jsx 문법

bable-loader : 바벨과 웹팩 연결해주는 것

(여기서 정상적으로 에러가 나면 웹팩이 에러메세지를 통해 친절히 어떻게 해결할지 알려주는데, 저 처럼 mode : ‘development'node : ... 이런식으로 오타를 내거나 하면 친절하게 알려주지를 않습니다.

Screen Shot 2022-10-22 at 11.35.43 AM.png

웹팩-바벨 세팅 성공~!! 🔥

끝말잇기

const { useState } = require('react');
const React = require('react');

function WordRelay() {
  const [text, setText] = useState('시작');
  const [input, setInput] = useState('');
  const [result, setResult] = useState('');
  const [score, setScore] = useState(0);

  const onSubmitInput = e => {
    e.preventDefault();
    if (text[text.length - 1] === input[0]) {
      setResult('딩동댕');
      setInput('');
      setText(input);
      setScore(prev => prev + 1);
    } else {
      setResult('땡');
    }
  };

  return (
    <>
      <header>
        <h1>구구단</h1>
      </header>
      <main>
        <h3>제시어 : {text}</h3>
        <form onSubmit={onSubmitInput}>
          <input type="text" value={input} onChange={e => setInput(e.target.value)} />
          <input type="submit" value="submit" />
        </form>
        <h3>결과 : {result}</h3>
        <h3>점수 : {score}</h3>
      </main>
    </>
  );
}

module.exports = WordRelay;

끝말잇기는 구구단과 유사해서 금방 만들 수 있다. 다만 CRA와 다르게 직접 Webpack, Babel을 설치하다 보니 소스코드를 수정할 때마다 build를 실행 해줘야 하는 단점이 있다. 이 또한 CRA처럼 자동으로 빌드가 되도록 설정이 가능하다.

npm i react-refresh @pmmmwh/react-refresh-webpack-plugin -D

npm i -D webpack-dev-server

위 명령어를 통해 자동 새로고침, 자동 새로고침 with 데이터 유지 를 다운 받고, webpack-dev-server도 다운 받는다. 그리고 아래와 같이 webpack.config.js를 고친다.

중요한 부분은 맨 아래 devServer 부분과 module 안의 plugins: [’react-refresh/babel], 부분이다.

const path = require('path'); // node에서 경로 조작하는 path라는 애가 있다.
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = {
  name: 'word-relay-setting',
  mode: 'development', // 실서비스 : production
  devtool: 'eval', // 빠르게 하겠다.
  resolve: {
    extensions: ['.js', '.jsx'], // entry에 확장자 없이 적어도 여기있는걸 찾겠다.
  },
  entry: {
    app: ['./client'],
  }, // 입력
  module: {
    rules: [
      {
        test: /\.jsx?/,
        loader: 'babel-loader',
        options: {
          presets: [
            [
              '@babel/preset-env',
              {
                targets: {
                  browsers: ['> 1% in KR'], //browserslist
                },
              },
            ],
            '@babel/preset-react',
          ], // plugin의 모음이 preset이다.
          plugins: ['react-refresh/babel'],
        },
      },
    ],
  }, // 모듈을 적용
  plugins: [new ReactRefreshWebpackPlugin()],
  output: {
    path: path.join(__dirname, 'dist'),
    // path.join 하면 경로를 알아서 합쳐준다.
    // 현재 폴더 안에 있는 dist
    // /react-webgame/2-끝말잇기/dist (현재폴더 안에 있는 dist를 픽해준다.)
    filename: 'app.js',
    publicPath: '/dist',
  }, // 출력
  devServer: {
    devMiddleware: { publicPath: '/dist' },
    static: { directory: path.resolve(__dirname) },
    hot: true,
  },
};

너무 적을게 많다보니 어떻게 적어야 될지 모르겠다. 또한 버젼업이 되면서 점점 config도 방식이 달라지다 보니 최신화가 안되는 문서를 이렇게 남기는게 의미가 있는지는 모르겠다.

하지만… 우선 지금 배운 내용을 머릿속에서 정리하기 위해 기록으로 남겨야겠다.

지금은 잘 안 와닿지만 많이 경험하고, 삽질하다보면 체화되지 않을까? 생각한다.

댓글