ABOUT ME

-

오늘
-
어제
-
-
  • Webpack으로 React 개발 환경 세팅해보기
    Front-end/React 2020. 11. 30. 12:51

    리액트 프로젝트

    리액트 프로젝트를 생성하는 방법에는 몇가지가 있는데요 대표적으로 CRA(Create React App)이 있습니다.

    CRA를 통해 프로젝트를 생성하게 되면 개발자가 특별한 세팅을 하지 않아도 아주 쉽고 편리하게 사용할 수 있습니다.

    CRA로 생성된 프로젝트는 웹팩 뿐만 아니라 엄청나게 많은 기본 세팅이 되어있는데요, 처음 프로젝트를 생성하면 등장하는 README.md를 보게되면 eject라는 명령어가 있다는 것을 알 수 있습니다.

     

    이는 리액트 내부에 숨겨져 있는 설정 파일들을 꺼내서 볼 수 있게 해주는데요 실행을 해보면 아래와 같은 디렉토리가 추가가 되고 엄청나게 많은 양의 설정 파일들이 있습니다.

    이만큼 하나의 프로젝트를 세팅하기 위해 엄청나게 많은 코드와 모듈이 필요한 것을 알 수 있습니다.

    웹팩만으로도 간단하게 이를 흉내낼 수 있는데요 간단한 예제를 만들어보면서 리액트 프로젝트를 세팅해보겠습니다.

     

    ❗️ 웹팩과 바벨의 개념을 숙지했다는 가정 하에 진행하니 만약 웹팩과 바벨의 개념을 모르신다면 웹팩 글을 읽고 오시면 도움이 될 것 같습니다.

     

    전체 코드 보기

    프로젝트 구조

    프로젝트 생성

    mkdir webpack-react-project && cd webpack-react-project
    npm init -y

    먼저 디렉토리를 하나 생성 후 Node 프로젝트를 생성해줍니다.

    개발 환경 구성

    프로젝트가 생성 되었다면 개발 환경을 세팅해주기 위해 패키지들을 추가해줍니다.

    리액트 프로젝트니 만큼 리액트, 웹팩, 그리고 트랜스파일러인 바벨까지 추가해주겠습니다.

    리액트(React)

    npm i react react-dom

    바벨(Babel)

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

    웹팩(Webpack)

    npm i -D babel-loader css-loader style-loader sass-loader node-sass webpack@4.44.2 webpack-cli@3.1.0 webpack-dev-server html-webpack-plugin

    위 종류별로 패키지를 나누었고 전체를 설치하면 아래와 같이 나타납니다.

    {
      "name": "webpack-react",
      "version": "1.0.0",
      "main": "index.js",
      "scripts": {
        "build": "webpack",
        "watch": "webpack --watch",
        "start": "webpack-dev-server"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "description": "",
      "devDependencies": {
        "@babel/core": "^7.12.3",
        "@babel/preset-env": "^7.12.1",
        "@babel/preset-react": "^7.12.1",
        "babel-loader": "^8.1.0",
        "css-loader": "^5.0.0",
        "html-webpack-plugin": "^4.5.0",
        "sass-loader": "^10.0.3",
        "style-loader": "^2.0.0",
        "webpack": "^4.44.2",
        "webpack-cli": "^3.1.0",
        "webpack-dev-server": "^3.11.0",
        "node-sass": "^4.14.1"
      },
      "dependencies": {
        "react": "^17.0.0",
        "react-dom": "^17.0.0"
      }
    }
    

    웹팩 스크립트문도 추가해주었습니다.

    디렉토리 설정

    CRA 환경과 동일하게 구성하기 위해 public, src 디렉토리를 나누어줍니다.

    public/index.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>React Webpack Project</title>
    </head>
    <body>
        <div id="root"></div>
    </body>
    </html>

    src/index.css

    .webpack {
      color: blue;
      font-weight: 700;
      font-size: 20px;
    }
    

    src/App.js

    import React from 'react';
    import './index.css';
    
    function App() {
      return <div className='webpack'>웹팩 + 리액트 시작!</div>;
    }
    
    export default App;
    

    src/index.js

    import React from 'react';
    import ReactDOM from 'react-dom';
    import App from './App';
    
    ReactDOM.render(<App />, document.getElementById('root'));
    

    내부 구조는 CRA와 동일하게 구성하였습니다.

     

    웹팩 설정(webpack.config.js)

    이제 위에 생성한 디렉토리들을 웹팩 설정을 통해 구현해보겠습니다.

     

    Entry

    웹팩4 부터는 기본적으로 src/index.js 설정이 되어있어서 생략이 가능하지만 명시성을 위해 작성해줍니다.

    module.exports = {
      entry: './src/index.js',
    }

     

    Output

    dist 폴더로 번들링 파일을 빌드해줍니다.

    const path = require('path');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
    }

     

    Loader

    CSS, SCSS, SASS, JS, JSX 파일들을 로더를 통해 이펙트들을 적용해줍니다.

     

    CSS

    const path = require('path');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.(c|sc|sa)ss$/,
            use: ['style-loader', 'css-loader', 'sass-loader'],
          },
        ],
      },
    }

    모든 CSS 관련 파일들을 대상으로 합니다.

     

    Babel

    const path = require('path');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.(c|sc|sa)ss$/,
            use: ['style-loader', 'css-loader', 'sass-loader'],
          },
          {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env', '@babel/preset-react'],
              },
            },
          },
        ],
      },
    }

    JS와 JSX 파일을 모두 포함하고, node_module에 있는 파일들은 제외하며 일반 JS 파일 뿐만 아니라 react에 해당되는 파일들도 트랜스파일링을 해야하는 대상이기 때문에 @babel/preset-react를 추가해줍니다.

    바벨의 공식문서를 보게 되면 웹팩 세팅 이외에도 .babelrc 파일을 루트 디렉토리에 생성하여 세팅하는 방법도 소개되어 있습니다.

     

    Resolve

    만약 js 파일 이외에 jsx 파일을 사용하여 개발할 경우도 이를 함께 호환 해주기 위해 extension을 추가할 수 있습니다.

    const path = require('path');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.(c|sc|sa)ss$/,
            use: ['style-loader', 'css-loader', 'sass-loader'],
          },
          {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env', '@babel/preset-react'],
              },
            },
          },
        ],
      },
      resolve: {
        extensions: ['.js', '.jsx'],
      },
    }

     

    Plugin

    번들링 된 결과를 html 파일과 함께 적용하도록 하기 위해 HtmlWebpackPlugin을 사용해줍니다.

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.(c|sc|sa)ss$/,
            use: ['style-loader', 'css-loader', 'sass-loader'],
          },
          {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env', '@babel/preset-react'],
              },
            },
          },
        ],
      },
      resolve: {
        extensions: ['.js', '.jsx'],
      },
      plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })],
    }

    자 이제 여기까지 세팅을 했다면 빌드시 문제 없이 번들링이 된 후 dist 폴더 내에 두 개의 파일이 생성되어야합니다.

    확인해보겠습니다.

    짠!

     

    빌드가 완료된 html 파일을 열어보니 이상 없이 전부 적용이 되었네요

    하지만 뭔가 빠진 느낌이죠

     

    CRA로 프로젝트를 생성하면 로컬 서버를 실행 시키면 개발자가 직접 새로고침 하지 않아도 자연스럽게 반영되는 기능이 있죠?

    이 역할을 해주는게 바로 webpack-dev-server입니다.

     

    devServer

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    const port = process.env.PORT || 3000;
    
    module.exports = {
      entry: './src/index.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
      },
      module: {
        rules: [
          {
            test: /\.(c|sc|sa)ss$/,
            use: ['style-loader', 'css-loader', 'sass-loader'],
          },
          {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env', '@babel/preset-react'],
              },
            },
          },
        ],
      },
      resolve: {
        extensions: ['.js', '.jsx'],
      },
      plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })],
      devServer: {
        contentBase: path.join(__dirname, 'dist'),
        host: 'localhost',
        port: port,
        open: true,
      },
    };
    

     

    위 설정을 해주게 되면 기본 dist 폴더를 필두로 호스트, 포트, 실행시 새창 오픈 여부 등을 설정할 수 있습니다.

     

    이렇게 세팅 후 아까 설정한 스크립트문인 npm run start를 통해 실행하면 자동으로 새창이 열리게 되고 코드 수정 후 저장하면 즉각 반영되는 것을 확인할 수 있습니다.

    댓글