웹팩을 사용하는 이유 / CRA를 사용하지 않고 웹팩을 이용해서 리액트 사용해보기

웹팩을 사용하는 이유

웹팩을 사용하는 이유는 뭘까? 내가 이해하고 있는바로는 웹팩은 번들도구이다. 번들이란 여러개의 파일들, 리소스들을 하나의 파일로 묶어주는 동작을 한다고 보면 될 거 같다. 하나의 파일이 아닐 수도 있지만 어쨌거나 잘 패키징하는 역할은 맞다. 그 과정에서 불필요한 코드는 없애고 또한 사이즈를 줄이기 위해 변수명을 최소화하고 불필요한 띄어쓰기는 없애게 된다.

웹팩을 사용하면서 바벨을 적용할 수도 있기 때문에 리액트에서는 CRA를 사용하는 것도 다 뒤에는 웹팩과 바벨이 있기 때문에 가능하다고 볼 수 있다. 그만큼 웹팩이란 도구는 강력하고 필수적인 도구가 되었다.

💻 참고 : https://www.youtube.com/watch?v=66_D4RYpFqY&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn&index=13


CRA를 사용하지 않고 웹팩을 이용해 리액트 개발 환경 세팅해보기

1. 라이브러리 설치

CRA를 사용하지 않고 웹팩을 이용해서 리액트를 처음부터 세팅해보는 건 어찌되었던가 한번쯤은 직접 해볼 필요가 있다고 생각한다. 그래야만 리액트를 좀 더 잘 이해할 수 있을테니까.

기본적으로 설치해야할 라이브러리이다.

yarn init -y
yarn add react react-dom
yarn add --dev webpack webpack-cli

2. index.html

index.html을 다음과 같이 작성해주자. 어제는 index.html에다가 script 넣고 거기서 작성하고 했는데 오늘은 dist/app.js 만 추가해주면 된다. 그 이유는 곧 알게 될 것이다.

<!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>React 끝말잇기</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="./dist/app.js"></script>
  </body>
</html>

3. jsx 파일 작성

WordRelay라는 컴포넌트를 jsx 파일을 통해 만들어 볼 수 있다. 기본적으로 node와 동일한 모듈 시스템을 사용해서 설치된 react, react-dom을 불러올 수 있다.

// WordRelay.jsx
const React = require("react");
const { Component } = require("react");

class WordRelay extends Component {
  state = {};

  render() {}
}

module.exports = WordRelay;

이렇게 만들어진 컴포넌트는 몇개라도 만들어서 쓸 수 있다. 이게 바로 컴포넌트에 장점이지.

// client.jsx
const React = require("react");
const ReactDom = require("react-dom");

const WordRelay = require("./WordRelay");

ReactDom.render(<WordRelay />, document.querySelector("#root"));

4. webpack.config.js

jsx 파일을 사용하기 위해서는 어찌됐건 바벨을 사용해야한다. 우리는 거기에다가 추가적으로 웹팩까지 같이 사용해 볼 것이다. 웹팩까지 사용하면 WordRelay.jsx와 client.jsx 두가지를 묶어서 번들링 할 수 있기 때문이다.

내가 느끼기에 webpack에 대한 거부감? 두려움?은 설정에 있는거 같다. 웹팩 설정 코드를 처음 보면 이게 무슨 소리인지 잘 이해가 가질 않기 때문이다. 하지만 이 과정을 넘어서면 좀 쉬워지지 않을까?? ㅎㅎ

const path = require("path");

module.exports = {
  name: "wordreplay-setting", // 사실 별 필요는 없지만 처음에 있는거?
  mode: "development", // 모드 설정. 운영모드라면 production 로 바꿔주면 된다. 이건 환경변수로 설정해서 조건문 걸어서 바꿔주는게 좋다.
  devtool: "eval", // 이건 뭐시여
  resolve: { // 웹팩이 알아서 경로나 확장자를 처리할 수 있게 도와주는 옵션
    extensions: [".js", ".jsx"],
  },
  entry: { // 시작점. 우리는 시작점을 client.jsx로 할 거임. 근데 resolve 설정을 했으니까 jsx는 입력할 필요가 없음
    app: "./client",
  },
  output: { // 빌드시 생성되는 폴더와 파일명
    path: path.join(__dirname, "dist"),
    filename: "app.js",
  },
};

일단 초 간단하게 웹팩 설정 파일을 세팅해봤다. 원래는 겁나 길지만 필수적인 부분만 설정한 것이다. 마지막으로 webpack을 실행하면 되는데 그냥 실행하면 당연히 못알아먹는다. 따라서 보통은 package.json에다가 설정하는 편이다.

// package.json
  "scripts": {
    "dev": "webpack"
  },

하지만 막상 실행해보면 dist 폴더에 app.js는 잘 생성되지만 에러가 발생한다. 그 이유는 바벨이다. 바벨 설정을 하지 않아서 jsx를 못알아먹기 때문에 에러가 발생하는 것이다.

5. babel 세팅하기

아.. 설치할 게 좀 많다.

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

각각의 의미를 한번 살펴보자.

  • @babel/core : 가장 기본이 되는 놈이라고 보면 된다. (필수)
  • @babel/preset-env : babel이 무엇을 하게 하려면 결국 플러그인이 필요한데, 플러그인마다 화살표함수를 ES5 문법으로 바꿔주는 플러그인, 기타 여러가지 플러그인이 따로 따로 있다고 한다. 근데 이걸 하나하나 설치하기에는 힘드니까 한번에 ES2015+ 문법을 변환할 수 있도록 나온것이 @babel/preset-env이다(요즘엔 다 이걸 사용하고 있다) - 참고
  • @babel/preset-react : jsx 같은 문법을 처리하기 위해서, 즉 리액트 문법을 처리하기 위해서 사용되는 플러그인이다.
  • babel-loader : 실무 환경에서는 바벨을 직접 사용하는 것보다는 웹팩으로 통합해서 사용하는 것이 일반적이다. 웹팩 loader 설정에서 사용된다.

@babel/preset-env에 대해서는 할 이야기가 좀 많은거 같다. 타겟 브라우저를 설정할 수도 있고, 대부분의 경우 .browserslistrc 파일로 target 환경을 명시한다고 한다. (음 결국 package.json에 있는 browerslist로 설정한게 여기서 타켓팅이 되는 구나. 좋은 사실 알아간다)

바벨에 대해서는 할 이야기가 좀 많은 듯하다. 좋은 글 참고했으니 시간날때마다 봐라 (참고1, 참고2)

어쨌거나 설치가 끝나면 webpack.config.js를 수정해준다.

const path = require("path");

module.exports = {
  name: "wordreplay-setting", // 사실 별 필요는 없지만 처음에 있는거?
  mode: "development", // 모드 설정. 운영모드라면 production 로 바꿔주면 된다. 이건 환경변수로 설정해서 조건문 걸어서 바꿔주는게 좋다.
  devtool: "eval", // 이건 뭐시여
  resolve: {
    // 웹팩이 알아서 경로나 확장자를 처리할 수 있게 도와주는 옵션
    extensions: [".js", ".jsx"],
  },
  entry: {
    // 시작점. 우리는 시작점을 client.jsx로 할 거임. 근데 resolve 설정을 했으니까 jsx는 입력할 필요가 없음
    app: "./client",
  },
  module: {
    rules: [
      {
        // js, jsx 파일에 바벨을 적용해서 최신문법을 옛날문법으로 호환되도록 바꿔주겠다
        test: /\.jsx?/,
        loader: "babel-loader",
        options: {
          presets: ["@babel/preset-env", "@babel/preset-react"],
          plugins: [] // plugins 모음이 바로 presets라고 보면 된다.
        },
      },
    ],
  },
  output: {
    // 빌드시 생성되는 폴더와 파일명
    path: path.join(__dirname, "dist"),
    filename: "app.js",
  },
};

순서대로 설명하자면 entry로 불러와서 module로 규칙을 정해준다음 output으로 내보낸다고 이해하면 편할 듯하다. 그리고 이 module안에 rules로 규칙을 정해주는데 주로 어떤 파일에는 어떤 로더를 적용할 것인지를 주로 설정하는 거 같다.

여기서는 js, jsx 파일에 대해 바벨 로더를 적용해서 웹팩이 동작할 때 바벨이 적용되도록 한 것이다. (정말 신기하다)... 그리고 나서 정말 잘 적용이 되는지 확인하기 위해 WordRelay.jsx 파일에서 jsx 문법을 사용해보자.

// WordRelay.jsx
const React = require("react");
const { Component } = require("react");

class WordRelay extends Component {
  state = {
    text: "Hello, webpack",
  };

  render() {
    return <h1>{this.state.text}</h1>;
  }
}

module.exports = WordRelay;

소스코드를 보면 알아먹지도 못할 코드로 변환이 되어있는데 이게 신기하게 동작해서 화면에다가 잘 보여준다... (짝짝짝)

좋은 웹페이지 즐겨찾기