Framework/React & RN

[React] CRA 없이, 리액트 개발 환경을 설정해보자

Joonfluence 2022. 4. 21.

서론

학습목표

오늘은 리액트 개발 환경셋팅을 자동으로 해주는 CRA 없이 리액트 개발환경을 설정할 수 있다.
웹팩, 바벨이 하는 역할을 알고 직접 관련된 설정을 해줄 수 있다.
CRA가 해주는 역할에 대해서 바르게 안다.

본론

리액트로 처음 개발할 땐, CRA로 개발환경을 셋팅해주곤 합니다. CRA란 Create React App의 약자로 바벨, 웹팩, 린트 등 복잡한 개발환경을 쉽게 설정해줄 수 있도록 돕는 툴입니다. 사용법은 정말 쉽습니다. 그러나 문제는 개발자로써 더 환경설정을 커스터마이징하고 싶을 때, 하기 어렵다는 점입니다. 따라서 오늘은 CRA 없이 밑바닥부터 리액트 개발환경을 설정해보도록 하겠습니다. 참고로 2022년 4월 21일 기준으로 패키지 버젼을 맞춰 줬습니다.

프로젝트 셋팅하기

먼저 시작에 앞서, 디렉토리부터 생성해줍시다. 그리고 node.js 모듈들을 설치하기 위해, 기본 npm 셋팅을 해줍니다. 참고로 React에 Node.js가 꼭 필요한 건 아닙니다. 다만, 바벨과 웹팩 같은 Node.js 모듈들이 리액트 개발환경을 구성하기 위해 필수적이기 떄문에 node.js 역시 설치되어 있어야 합니다.

mkdir react-from-scratch;
cd react-from-scratch;
npm init -y;

그리고 세 개의 디렉토리를 만들어줍니다. 정적 파일을 둘 public와 리액트 소스코드를 둘 src입니다. 그리고 dist에는 번들된 파일이 위치하게 될 것입니다.

mkdir public src dist;

먼저 public 모듈 경로로 가, 리액트 스크립트가 로드될 html 파일을 아래와 같이 작성해줍니다. 여기서 짚고 넘어가야 할 게, 두 가지 있는데요. 첫째는 div id가 root인 요소가 꼭 있어야 한다는 점, 그리고 번들된 js파일을 로드하는 스크립트 태그가 있어야 한다는 점입니다. 전자는 해당 태그의 자식 요소로서 리액트 DOM이 위치하게 됩니다. 후자는 이후 웹팩에서 번들링된 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 from scratch</title>
  </head>
  <body>
    <div id="root"></div>
    <noscript> You need to enable JavaScript to run this app. </noscript>
    <script src="../dist/bundle.js"></script>
  </body>
</html>

 

바벨 설정하기

그 다음 해줄 것은 바벨을 설정하는 것입니다. 먼저 필요한 패키지들을 설치해줍니다.

yarn add -D @babel/cli@7.17.6 @babel/core@7.16.0 @babel/preset-env@7.16.11 @babel/preset-react@7.16.7

@babel-core는 바벨의 메인 패키지이며, babel-cli는 커맨드라인으로 파일을 컴파일 할 수 있도록 해줍니다. 또 preset-env는 ES6+ 문법을 ES5 이하의 자바스크립트 문법과 호환되도록 변환해주는 역할을 합니다. 그리고 preset-react는 preset-env와 역할이 같으나, JSX 문법을 사용할 수 있도록 해줍니다.

// .babelrc
{
  "presets": ["@babel/env", "@babel/preset-react"]
}

그리고 위와 같이, 바벨 설정을 해줍니다. 바벨에는 그 외에 다양한 설정을 할 수 있으며, 이는 공식문서에 자세하게 기록되어 있으므로 해당 링크를 참조하시면 좋습니다.

웹팩 설정하기

먼저 필요한 모듈들을 설치해줍니다.

yarn add -D webpack@5.64.4 webpack-cli@4.9.2 webpack-dev-server@4.6.0 style-loader@3.3.1 css-loader@6.5.1 babel-loader@8.2.3 react-hot-loader@4.13.0

그 다음은 웹팩입니다. 처음 웹팩 설정을 접하시는 분들은 이 부분이 조금 어려울 수 있습니다. 따라서 자세하게 설명드리도록 하겠습니다. 먼저, 프로젝트 루트 경로에 webpack.config.js 파일을 만들어줍니다. 저희가 설정해줄 것은 entry, mode, module, output, devServer, plugins,

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

먼저 entry 입니다. 이는 웹팩이 번들링을 시작하는 시작점이 어느 파일인지 나타냅니다. src에 index.js을 진입점으로 삼겠습니다.

module.exports = {
  return {
    ...
    mode: 'development'
  }
}

그 다음은 mode입니다. 개발환경에서 사용될 것인지, 배포환경에서 웹팩이 쓰일 것인지를 지정해줄 수 있습니다. 저희는 개발 서버에서 테스트해볼 것이기 떄문에 development로 설정해줍니다.

module.exports = {
  return {
    ...,
    module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /(node_moduels|bower_components)/,
          loader: 'babel-loader',
          options: { presets: ['@babel/env'] },
        },
        {
          test: /\.css$/,
          use: ['style-loader', 'css-loader'],
        },
      ],
    },
  }
}

다음은 module입니다. module은 자바스크립트 파일을 rules 속성에 주어진 값에 따라, js 파일이 어떻게 변환되어야 할 것인지 나타내줍니다. 리액트에서 JSX 문법을 함께 사용할 것이므로 파일 확장자에 따라, 적용될 수 있도록 Regex로 js와 jsx 파일만 통과시킵니다. 또 앞서 설치한 바벨 로더를 통해, 파일을 로드합니다. 마지막으로 options에는 (앞서 바벨 설정에서 추가한) @babel/env 프리셋으로 js 파일을 변환해주면 됩니다. 또한 CSS 같은 경우에는 style-loader와 css-loader를 통해 불러올 수 있습니다. 그 외 다양한 파일들을 웹팩을 통해서 불러올 수 있는데, 그 외 내용은 해당 링크를 참조하시면 좋을 것입니다. 정말 다양한 파일들을 웹팩으로 불러올 수 있습니다..!

module.exports = {
  return {
    ...
    resolve: { extensions: ["*", ".js", ".jsx"] },
  }
}

resolve 속성은 웹팩이 불러올 경로, 확장자들을 처리할 수 있게 도와줍니다.

module.exports = {
  return {
    ...,
    output: {
      path: path.resolve(__dirname, 'dist/'),
      publicPath: '/dist/',
      filename: 'bundle.js',
    },
  }
}

output에는 번들된 파일의 결과물이 위치할 경로(path)와 파일명(filename)을 적어줍니다.

module.exports = {
  return {
    ...,
    devServer: {
      static: path.join(__dirname, 'public/'),
      port: 3000,
    },
    plugins: [new webpack.HotModuleReplacementPlugin()],
  }
}

devServer는 개발 환경에서 실행되는 webpack의 옵션을 설정해주는데, static에는 정적 파일(index.html)의 경로를 적어줍니다. publicPath에는 번들된 코드가 위치한 경로를 말해줍니다. 마지막으로 변경된 내역을 파악해, 페이지를 새로고침 해주는 HotModuleReplacementPlugin(줄여서 HRM) 플러그인 설정을 해주고 아래처럼 리액트 코드에 반영해주면 끝입니다!

 

prettier 설정하기

yarn add -D prettier;

먼저 모듈을 설치해줍니다.

// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2
}

prettier는 코드를 정돈하기 위해 사용합니다. 문장 마지막에 세미콜론을 넣을 것인지, 말 것인지. 혹은 홀따움표로 적을지 쌍따움표로 적을지 등을 적어줍니다. 탭 했을 때의 간격도 정해줄 수 있습니다.

그 다음으로는 코드를 수정 한 후 저장했을 때, 자동으로 prettier 설정을 처리해주도록 해주겠습니다. vsCode의 설정 파일을 연 후, editor.formatOnSave를 검색해줍니다. 그런 후, 체크박스를 클릭해줍니다. 그러면 자동으로 파일 저장할 때, prettier 설정이 동작합니다.

eslint 설정하기

eslint는 린팅을 돕는 모듈인데요, 린팅이란 코드를 작성할 때 자동으로 규약을 맞춰주는 도구입니다. 혼자서 개발할 떄는 크게 필요성을 느끼지 못할 수 있으나, 여러 사람이 하나의 프로젝트를 진행하다보면 코드 스타일의 통일성을 유지하는 게 꽤 중요해집니다. 그 때, 일정한 스타일로 강제하는 역할을 해줍니다. 저는 평소 airbnb의 린트 설정을 따르므로, 이번 포스팅에서도 마찬가지로 설정해주겠습니다. 먼저 설치해줘야 하는 패키지들은 다음과 같습니다.

yarn add -D eslint eslint-config-airbnb eslint-config-prettier eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-react-hooks;

각각의 기능을 살펴보겠습니다. 먼저 eslint는 앞서 말했듯, 린팅 기능을 해주는 node 모듈입니다. eslint-config-airbnb는 airbnb의 린트 설정을 plugin 방식으로 제공하는 모듈입니다. eslint-config-prettier는 prettier와 eslint의 설정이 충돌되지 않도록 기능하는 모듈입니다. eslint-plugin-import은 import/export syntax가 가능하도록 돕고 import 순서를 올바르게 정렬해주는 모듈입니다. react-a11y는 리액트로 작성된 element에 대한 접근성을 체크해주는 데, eslint-plugin-jsx-a11y은 이 룰을 지켰는지 linting 과정에서 확인하는 모듈입니다. eslint-plugin-react eslint plugin-react-hooks는 리액트와 리액트 훅의 문법을 확인해주는 기능을 담당합니다.

// eslintrc.js 

module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: ['plugin:react/recommended', 'airbnb', 'prettier'],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  plugins: ['react'],
  rules: {},
};

이제, 파일에서 관련 설정을 해주겠습니다. 설정은 .eslint.js, .eslint.json, package.json 파일에서 모두 가능합니다. 보편적으로 js 파일에서 많이 설정하므로 js 파일에서 처리해주겠습니다.

이제 차례대로 설명 드리겠습니다. env는 해당 js 파일이 실행되는 환경을 말합니다. 리액트 코드는 브라우저에서 실행되기 때문에 'browser: true'로 처리해주시면 됩니다. 참고로 만약 해당 코드가 노드에서 실행된다면 'node: true'로 설정 가능합니다. 또 최신 EcmaScript 버젼을 사용할 것이므로 'es2021: true'도 추가해줍니다.

extends는 플러그인을 기본적으로 설정된 preset의 규칙들로 적용할 때 사용합니다. plugins는 기본 설정, 즉 이미 설정된 preset을 적용하지 않고 각 사용자가 원하는대로 규칙들을 적용하고자 할 때 사용합니다. rules는 Plugin의 세부 사항을 설정할 떄 사용합니다.

 

리액트 코드 추가하기

이제, 간단하게 리액트 코드를 추가한 후 실제 서버를 구동시켜 보겠습니다.

// src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';

ReactDOM.render(<App />, document.getElementById('root'));

위와 같이, index.js 파일에 root 클래스를 불러오는 리액트 코드를 추가해줍니다. 간단한 css 코드도 입력해줍니다.

// src/App.css

.Wrapper {
  margin: 0 auto;
  position: absolute;
  left: 45%;
  top: 25%;
}

.App {
  margin: 1rem;
  font-family: Arial, Helvetica, sans-serif;
  background-color: red;
  padding: 20px;
}
// src/app.js

import React, { Component } from 'react';
import { hot } from 'react-hot-loader';
import './App.css';

class App extends Component {
  render() {
    return (
      <div className="Wrapper">
        <div className="App">
          <h1>Hello, World! </h1>
          <h2>Hello, World! </h2>
          <h3>Hello, World! </h3>
          <h4>Hello, World! </h4>
          <h5>Hello, World! </h5>
          <h6>Hello, World! </h6>
        </div>
      </div>
    );
  }
}

export default hot(module)(App);

그 다음으론 실제 렌더링할 내용을 App.js 라는 파일명으로 생성 후, 입력해줍니다.

 

서버 구동하기

자, 이제 실행시켜줍시다. 터미널에서 "webpack-dev-server --mode development"을 입력해줍니다. 혹은 package.json에 저와 같이, scripts에 추가해주셔도 됩니다.

{
  "name": "react-from-scratch",
  "version": "1.0.0",
  "description": "",
  "main": "src/index.js",
  "scripts": {
    "start": "webpack-dev-server --mode development",
    "build": "webpack --mode production"
  }
  ...
}

개발 서버를 구동시킬 분은 yarn start, 배포를 위한 빌드를 하실 분은 yarn build를 입력해주시면 됩니다. 그럼 성공적으로 서버가 구동 혹은 빌드될 겁니다.

이상으로, 긴 글 읽어주셔서 감사합니다.

 

참고한 글

https://www.zerocho.com/category/Webpack/post/58aa916d745ca90018e5301d
https://medium.com/@JedaiSaboteur/creating-a-react-app-from-scratch-f3c693b84658

반응형

댓글