홈으로

[React] CRA 없이 리액트 환경 만들기

2020년 02월 21일

보통 리액트 관련 프로젝트는 CRA 툴을 사용하여 손쉽게 환경설정을 구축하는 것이 일반적이다. Webpack, Babel 등 설정하기가 귀찮은 많은 것들을 아주 편하게 해결해주는 좋은 툴이다. 하지만 단순히 생각없이 CRA를 사용하는 것은 개발자로서의 사고방식에 적합하지 않다. 이 툴이 어떤 것을 어떻게 잡아주는지 알아야 디버깅을 할 수 있고 리액트 환경을 혼자서 구축해야 할 일이 있을 때 필요하다. 따라서, 이번 포스팅에선 리액트 환경을 CRA 없이 구축해보는 법에 대해서 알아보자.

폴더 생성 및 초기화

cra 라는 폴더를 만들어주고 패키지 매니저인 yarn을 초기화 해주자.

mkdir cra
cd cra
yarn init -y

이제 package.json 파일이 생길 것이고 필요한 패키지들을 설치해주면 된다. 또한 기본적인 폴더와 파일들을 만들어주자.

mkdir src public dist
  • src : 리액트 작업을 할 폴더
  • public : 정적 파일들을 위한 폴더인데 여기선 HTML 파일만 사용
  • dist : 번들링 결과물이 위치할 폴더

이제 HTML 파일을 만들어서 루트 div 를 만들어주자.

cd public
touch index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>CRA 없이 설정하기</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

마지막으로 리액트 컴포넌트를 렌더링할 자바스크립트 파일을 만들어주면 초기 세팅이 끝난다.

cd src
touch index.js

Windows 사용자의 경우, mkdir 이나 touch 가 안 먹힐 텐데 git bash를 사용하거나 직접 만들면 된다.

리액트 설치

리액트의 핵심이 되는 패키지들을 설치해줘야 한다.

  • react : 리액트의 코어
  • react-dom : 리액트를 DOM과 연결
yarn add react react-dom

바벨 설치

JSX와 ES6+ 를 트랜스파일링 시킬 바벨을 설치해주자.

  • @babel/core : 바벨의 코어
  • @babel/preset-react : 리액트의 JSX를 트랜스파일링
  • @babel/preset-env : ES6+ 코드를 ES5로 트랜스파일링하고 브라우저 폴리필을 자동화

웹팩 설치

핵심

모듈 번들러인 웹팩의 핵심이 되는 패키지들도 설치해주자.

  • webpack : 웹팩의 코어
  • webpack-cli : 웹팩을 커맨드라인에서 사용
  • webpack-dev-server : 웹팩을 메모리 상에 빌드하여 개발 서버를 구동
yarn add -D webpack webpack-cli webpack-dev-server

로더

웹팩의 번들링에 필요한 로더들을 설치해주자.

  • babel-loader : JSX 및 ES6+ 문법을 트랜스파일링
  • css-loader : CSS 파일을 자바스크립트가 이해할 수 있도록 변환
  • style-loader : 변환된 CSS 파일을 <style> 태그로 감싸서 삽입
  • file-loader : 이미지 및 폰트 등의 파일 로딩
yarn add -D babel-loader css-loader style-loader file-loader

플러그인

웹팩으로 번들링을 한 후에 적용할 플러그인들을 설치해주자.

  • html-webpack-plugin : HTML 파일에 번들링된 자바스크립트 파일을 삽입해주고 번들링된 결과가 저장되는 폴더에 옮겨줌
  • clean-webpack-plugin : 번들링을 할 때마다 이전 번들링 결과를 제거함
yarn add -D html-webpack-plugin clean-webpack-plugin

바벨 설정

루트 경로에 babel.config.js 파일을 만들고 프리셋들을 설정해주자.

module.exports = {
  presets: ['@babel/preset-react', '@babel/preset-env']
};

웹팩 설정

루트 경로에 webpack.config.js 파일을 만들고 설정해주자.

  • entry : 모듈의 의존성이 시작되는 부분으로 이름을 지정할 수 있고 여러개를 만들 수 있다.
module.exports = {
  entry: {
    main: './src/index.js'
  }
}
  • resolve : 웹팩이 모듈을 처리하는 방식 정의하는 것으로 확장자를 생략하고도 인식하게 만든다.
// 여기서부터 module.exports 생략
resolve: {
  extensions: ['.js', '.jsx']
},
  • devtool : source-map을 설정하는 부분으로 에러가 발생했을 때 번들링된 파일에서 어느 부분에 에러가 났는지를 쉽게 확인할 수 있게 해주는 도구이다. 문서 에서 각 source-map의 종류와 기능을 확인할 수 있다.
devtool: 'eval-cheap-source-map',
  • devServer : webpack-dev-server의 옵션을 설정해주는 부분이다.
devServer: {
  hot: true,
  overlay: true,
  writeToDisk: true,
},

hot 은 모듈의 변화된 부분만 자동으로 리로딩하는 HMR(Hot Module Replacement) 기능을 사용할 것인지에 대한 옵션이고 overlay 는 에러가 발생했을 때 브라우저에 띄울 것인지, writeToDisk 는 메모리 뿐만 아니라 직접 파일로 만들 것인지에 대한 옵션이다.

  • output : 웹팩의 번들링 결과물에 대한 옵션이다.

path 모듈을 사용하기 위해서 설정 파일의 module.exports 위에 선언해주자.

const path = require('path');

....
output: {
  filename: 'bundle.js',
  path: path.resolve(__dirname, 'dist'),
}

filename 은 번들링 파일의 이름이고 path 는 번들링 파일이 위치할 경로로 절대경로 이다.

  • module.rules : 모듈에 적용할 여러가지 로더들과 그 옵션들을 추가하는 부분이다.
module: {
  rules: [
    {
      test: /\.(js|jsx)$/,
      exclude: '/node_modules/',
      loader: 'babel-loader'
    },
    {
      test: /\.css$/,
      use: [
        { loader: 'style-loader' },
        { loader: 'css-loader' }
      ]
    },
    {
      test: /\.jfif$/,
      loader: 'file-loader',
      options: {
        name: '[name].[ext]'
      }
    }
  ]
},

test 는 어떤 파일에 적용될지 그 확장자를 명시한 것이다. 로더가 1개라면 loader 로, 2개 이상이라면 use 배열로 설정할 수 있다. 또한 exclude 로 로더를 제외할 대상을 적용할 수도 있다.

  • 플러그인 적용

플러그인을 먼저 불러와야 한다.

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

이제 plugins 옵션으로 설정해주면 된다.

plugins: [
  new CleanWebpackPlugin(),
  new HtmlWebpackPlugin({
    template: './public/index.html',
  })
]

여기서 html-webpack-plugin의 template 은 번들링 파일을 주입하고 번들링 폴더로 복사할 대상 HTML 파일을 명시하는 옵션이다.

  • package.json에 스크립트 입력
{
  "scripts": {
    "dev": "webpack-dev-server --progress --mode development",
    "build": "webpack --progress --mode production"
  }
}

웹팩은 개발/프로덕션 모드가 있기 때문에 각각 다르게 설정해준다. ( 물론 여기선 dev 만 사용할 것이다. ) 참고로 --progress 옵션은 번들링 진행 상태를 보기 위함이다.

리액트 컴포넌트 생성

이제 간단한 사각형 안에 배경 이미지를 나타내는 리액트 컴포넌트를 생성해보자. 먼저 배경이미지로 나타낼 이미지 파일을 받아 놓아야 한다. 여기선 image.jfif 파일을 사용한다. (jfif도 png/jpg 같은 확장자 이름이다)

cd src
touch App.jsx App.css
  • App.jsx
import React from 'react';
import './App.css';

const App = () => {
  return <div className="container" />
};
  
export default App;
  • App.css
.container {
  width: 500px;
  height: 300px;
  background: url("image.jfif") center no-repeat;
  background-size: cover;
  margin: 0 auto;
}
  • index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

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

실행

이제 package.json 에 등록한 스크립트 명령어로 실행해보자.

yarn run dev

아래와 같이 실행되는 것을 확인할 수 있다.

마무리

지금까지 CRA 없이 리액트 환경을 구축해보는 법에 대해 알아보았다. 정말 기본적인 부분만 살펴보았기 때문에 이외에도 설정할 것은 무수히 많다. 그래도, 공부를 하면서 CRA의 소중함에 대해 더욱 느끼게 되었고 실제로 어떻게 환경을 구축할 수 있는지 알아볼 수 있어서 유익했다. 본 포스팅의 예시 코드는 깃헙 에 있다.

Loading script...