리액트 CRA없이 프로젝트 구성하기

지금껏 리액트를 사용해오면서 무지성으로 CRA(create-reat-app)를 휘갈기며 프로젝트를 시작해 왔는데,
누군가 실무에서는 모듈을 세부적으로 설정해야 할 순간이 반드시 온다는 이야기를 들었다.
그 얘기를 듣고 문득 CRA가 어떤 식으로 구성이 되어 있는지 궁금해져서 CRA 없이 프로젝트를 구성하는 법에 대해 알아보았다.

실무에서 쓸 정도는 아니겠지만,
지금부터 아주 간단하게 CRA없이 리액트 프로젝트를 구성하는 법에 대해 살펴보려 합니다.

참고로 본 글은 제로초님의 react 웹 게임 강좌 초반부를 듣고 정리한 글입니다.
https://www.inflearn.com/course/web-game-react
리액트 기초 강좌에 나오는 세팅법을 듣고 정리한 글이기 때문에
이 글은 리액트 입문자의 시선에 맞춰져 있다는 점을 유의하고 읽어주시면 감사하겠습니다.


노드 프로젝트 생성

리액트에서 쌩으로 자바스크립트 파일을 작성하게 되면 프로젝트에 따라서 수만 개의 파일이
만들어지기 때문에 그 파일들을 하나로 합쳐주고,
동시에 바벨 적용 및 쓸데없는 코드마저 지워주는 마법 같은 도구인 '웹팩'을 사용합니다.

웹팩을 쓰기 전에 우선 노드(자바스크립트 실행기)를 사용합니다.
기본적으로 노드를 설치해 주시고,

npm init

터미널에서 npm init을 실행해 줍니다.
그러면 순서대로 package name부터 나오는데,
package name만 프로젝트명으로 설정해 주시고 author에 내 이름을 친 뒤,
나머지는 그냥 다 넘어가 줘도 무방합니다.
마지막에 yes를 치면서 마무리해주면 package.json파일이 생성이 됩니다.

이곳에 내가 설치한 패키지 정보가 나오게 됩니다.

리액트 패키지 설치

우선 가장 먼저 react와 react-dom을 설치해 줍니다.

npm i react react-dom

위 코드를 통해 npm이 react와 react-dom을 설치하게 되면
package.json에 내가 설치한 파일들이 나오게 됩니다.

웹팩 설치

npm i -D webpack webpack-cli

-D 는 개발에서만 사용하겠다는 의미를 담은 옵션입니다.
실제 서비스를 할 때는 webpack이 필요 없고, 개발에서만 필요하기 때문에 개발할 때만
webpack을 사용하겠다는 의미입니다.

그리고 웹팩을 설정할 수 있는 'webpack.config.js' 파일을 package.json과 동일한 위치에
있는 폴더에 생성해 줍니다.

동시에 'client.jsx'라는 파일도 생성해 줍니다.

import React from 'react';
import ReactDom from 'react-dom';

const App = () => {
	return <div></div>;
}

ReactDom.render(<App />, document.querySelector('#root'));

react와 react-dom을 불러오며 함수형 컴포넌트의 기본꼴을 만들어 줍니다.

<!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>Document</title>
</head>
<body>
  <div id="root"></div>

  <script src="./dist/app.js"></script>
</body>
</html>

index.html 파일을 만들어서 컴포넌트가 렌더될 div 하나와 웹팩으로 합친 하나의 파일인
app.js를 로드해 줍니다.

웹팩 설정

// webpack.config.js

const path = require('path');

module.exports = {
	name: 'react-setting',
	mode: 'development',  // 실서비스 땐 production
	devtool: 'eval',

	entry: {
		app: ['./client.jsx'],  //'./App.jsx' 파일은 client.jsx에서 불러오기 때문에 따로 불러올 필요가 없습니다.
	},  // 입력
	output: {
		path: path.join(__dirname, 'dist'),  // 현재 폴더를 기준으로 dist폴더의 위치를 가져온다.
		filename: 'app.js'
	},  // 출력
}

entry에서 파일들을 하나로 합쳐서 output으로 내보냅니다.

// webpack.config.js

const path = require('path');

module.exports = {
	name: 'react-setting',
	mode: 'development',
	devtool: 'eval',
	resolve: {
    	extensions: ['.js', '.jsx']
    },
  
	entry: {
		app: ['./client'],
	},  // 입력
	output: {
		path: path.join(__dirname, 'dist'),
		filename: 'app.js'
	},  // 출력
}

resolve를 통해 확장자를 설정하면 entry에 따로 확장자를 쓰지 않아도 웹팩이 알아서 확장자를
찾아줍니다.

웹팩으로 빌드하기

이제 설정한 웹팩을 가지고 빌드를 하기 위해 터미널에 webpack 명령어를 쳐야 하는데,
webpack은 명령어로 등록이 되어 있지 않아서 바로 사용할 수 없습니다.
그래서 package.json에 scripts에서 설정을 해줍니다.

// package.json

"scripts": {
	"dev": "webpack"
}

위와 같이 설정해준 뒤, 터미널에 'npm run dev' 명령어를 통해 webpack를 실행할 수 있습니다.

webpack 명령어를 쓰기 위한 두번째 방법은

npx webpack

위 코드를 터미널에 사용하면 webpack이 실행이 되고 app.js파일이 생성됩니다.

그런데 이렇게 실행을 하면 오류가 납니다.

바벨 설정

JSX문법을 사용하려면 바벨이 필요하기 때문에 웹팩에 추가적으로 바벨 설정을 해주어야 합니다.

npm i -D @babel/core

위 코드로 개발용 바벨을 설치해 줍니다.

npm i -D @babel/preset-env

위 코드가 최신문법을 옛날 브라우저에서도 돌아갈 수 있도록 해주는 역할을 합니다.

npm i -D @babel/preset-react

위 코드로 JSX를 지원합니다.

npm i -D babel-loader

이 코드는 바벨과 웹팩을 연결해주는 역할을 합니다.

이렇게 설치한 패키지를 설정해 줍니다.

// webpack.config.js

const path = require('path');

module.exports = {
	name: 'react-setting',
	mode: 'development',
	devtool: 'eval',
	resolve: {
    	extensions: ['.js', '.jsx']
    },
  
	entry: {
		app: ['./client'],
	},  // 입력
  
  	module: {
		rules: [{
			test: /\.jsx?/,  // js와 jsx 파일들에 룰을 적용하겠다. (정규표현식)
			loader: 'babel-loader',
			options: {
				presets: ['@babel/preset-env', '@babel/preset-react'],  // 설치한 바벨 패키지를 넣어줍니다.
			}
		}],
	}
  
	output: {
		path: path.join(__dirname, 'dist'),
		filename: 'app.js'
	},  // 출력
}

module을 통해 파일을 읽고 출력하기 전에 규칙을 정해줍니다.
여기까지만 설정해 줘도 되지만, 코드를 고칠 때마다 계속 webpack을 실행해 주어야 하는
불편함이 있기 때문에 이것을 '핫 리로딩'으로 해결할 수 있습니다.

웹팩 데브 서버와 핫 리로딩

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

위 코드로 핫리로딩하는 두 패키지를 개발용으로 설치해 줍니다.
그리고 개발용 서버가 하나 필요하기 때문에

npm i -D webpack-dev-server

위 코드로 함께 설치해 줍니다.

그럼 이제 package.json에 dev부분을 'webpack serve --env development'로 바꿔줍니다.

// package.json

"scripts": {
	"dev": "webpack serve --env development"
}

그 후에 설치한 패키지를 webpack.config.js에서 장착을 시켜줍니다.

const path = require('path');
const RefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = {
  name: 'wordrelay-setting',
  mode: 'development',
  devtool: 'eval',
  resolve: {
    extensions: ['.js', '.jsx']
  },

  entry: {
    app: ['./client'],
  },

  module: {
    rules: [{
      test: /\.jsx?/,
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env', '@babel/preset-react'],
        plugins: [
          'react-refresh/babel',
        ]
      }
    }]
  },

  plugins: [
    new RefreshWebpackPlugin()
  ],

  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'app.js',
    publicPath: '/dist/',
  },

	devServer: {
    devMiddleware: { publicPath: '/dist/' },
		static: { directory: path.resolve(__dirname) },
    hot: true,
  }
}

웹팩 데브 서버의 역할은 webpack.config.js의 결과물대로 빌드를 해준 뒤,
'publicPath'에 설정한 'dist' 폴더에 메모리로 결과물을 저장해 놓습니다.
그래서 html을 싱행하면 저장해놓은 결과물을 실행해 주는데,
여기서 웹팩 데브서버가 변경점을 감지하고 그에 따른 결과물을 수정해 줍니다.

그래서 'npm run dev'를 하면 localhost 주소가 나오는데, 그 주소를 통해 실행을 하면,
코드가 변경될 때마다 자동으로 결과물을 수정해 줍니다.

좋은 웹페이지 즐겨찾기