CRA는 리액트 프로젝트를 쉽게 구축할수 있도록 도와주는 도구입니다. 기본적인 로드와 빌드, 초기에 복잡한 Webpack과 Babel등을 직접 설정 할 필요 없이 명령어 한번에 개발에 필요한 환경을 세팅해줍니다.
일반적으로는 CRA를 사용하면 손 쉽게 리액트 환경을 구축 할 수 있습니다. 하지만 프로젝트에 따라서 Webpack, Babel에 추가적인 설정을 해야 하는 경우 직접 리액트 세팅을 하는게 쉬울 수 있습니다.
이번 게시글에서는 CRA없이 리액트 환경을 구축하는 법을 알아보겠습니다.
(1) 리액트 및 타입스크립트 설정
$ npm init -y
$ npm i react react-dom
프로젝트 기본설정과 리액트를 설치 해 줍니다.
$node_modules/.bin/tsc --init
최상위 경로에 tsconfig.json 파일이 생성 되는데 프로젝트에 맞게 수정하도록 합니다.
tsconfig.json
{
"compilerOptions": {
"sourceMap": true,
"target": "es5",
"lib": ["dom", "ES2015", "ES2016", "ES2017", "ES2018", "ES2019", "ES2020"],
"allowJs": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"module": "commonjs",
"isolatedModules": true,
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"baseUrl": "./",
"outDir": "./dist",
"moduleResolution": "node"
},
"exclude": ["node_modules"],
"include": ["**/*.ts", "**/*.tsx"]
}
(2) 바벨(Babel) 설정
$ npm i -D babel-loader @babel/core @babel/preset-env
$ npm i -D @babel/preset-react @babel/preset-typescript
타입스크립트를 Babel이 해석할 수 있도록 트랜스파일러를 설치해줘야 합니다.
이후 아래와 같이 Babel 설정파일을 생성 후 작성합니다.
babel.config.js
module.exports = {
presets: ['@babel/preset-react', '@babel/preset-env', '@babel/preset-typescript'],
};
@babel/preset-react
: JSX로 작성된 코드들을 createElement 함수를 이용한 코드로 변환해 주는 바벨 플러그인이 내장(리액트를 변환하기 위한 프리셋)
@babel/preset-typescript
: 타입스크립트를 변환하기 위한 프리셋
@babel/preset-env
: preset-env는 ECMAScript2015+를 변환할 때 사용합니다. IE 지원을 위한 프리셋
(3) 웹팩(Webpack) 설정
$ npm i -D webpack webpack-cli webpack-dev-server
$ npm i -D html-webpack-plugin ts-loader
webpack, webpack-cli : 웹팩 기본파일
html-webpack-plugin: html 파일에 필요한 플러그인
webpack-dev-server: 개발 도중 변경사항을 확인할 수 있음
ts-loader : 타입스크립트 코드를 자바스크립트 코드로 변환
이후 아래 Webpack 설정파일을 생성 후 작성합니다.
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
const prod = process.env.NODE_ENV === 'production';
module.exports = {
mode: prod ? 'production' : 'development',
devtool: prod ? 'hidden-source-map' : 'eval',
entry: './src/index.tsx',
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
module: {
rules: [
{
test: /\.tsx?$/,
use: ['babel-loader', 'ts-loader'],
},
],
},
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js',
},
plugins: [
new webpack.ProvidePlugin({
React: 'react',
}),
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
};
mode : 프로덕션 모드인지 개발 모드인지 확인하는 옵션
devtool : 프로덕션 모드인 경우엔 hidden-source-map을 권장합니다. (외부에서 리액트 구조를 확인할 수 없게 해줍니다.)
resolve : 확장자나 경로를 알아서 처리할 수 있도록 설정하는 옵션입니다.
module : 이 옵션에 설치한 ts-loader와 babel-loader를 설정하면 됩니다. loader들은 오른쪽에서 왼쪽 방향으로 적용되기 때문에 ts-loader가 babel-loader보다 오른쪽에 위치해야 합니다.
output : 번들화 된 파일을 export할 경로와 파일명을 설정합니다.
plugins : 설치한 플러그인을 적용하는 옵션입니다.
(4) Webpack-dev-server 추가설정
webpack-dev-server는 핫리로딩 기능을 갖춘 개발 서버로 개발하는 과정에서 코드가 수정이 일어났는지 바로바로 확인할 수 있어서 유용합니다. 또한 프록시 설정기능을 제공하여 CORS문제 등 브라우저 및 서버에러를 처리할 수 있습니다.
const webpack = require('webpack');
...
module.exports = {...
devServer: {
historyApiFallback: true,
inline: true,
port: 3000,
hot: true,
publicPath: '/',
},
plugins: [
...,
new webpack.HotModuleReplacementPlugin(),
...,
],
...
}
historyApiFallback : 히스토리 API를 사용하는 SPA 개발 시 설정하며 404에러가 발생하면 index.html로 리다이렉트 한다.
inline : inline모드를 활성화 해준다.
port : 접속 포트를 설정한다.
hot : webpack의 HMR기능을 활성화 한다. (리로드 기능)
publicPath : 브라우저를 통해 접근하는 기본 주소값을 설정한다.
(5) package.json 변경설정
...,
"scripts": {
"dev": "webpack serve --mode development --open --hot",
"build": "webpack --mode production",
"prestart": "npm build",
"start": "webpack --mode development"
},
...
예전에는 webpack-dev-server 명령어로 실행했는데 webpack serve로 바뀌었습니다.(webpack-cli는 4버전이랑 같이 써야 오류가 안난다.)
dev 명령어는 webpack serve를 실행하는 명령어고 start는 리액트 프로젝트를 빌드해 dist폴더 안에 번들링 된 파일을 추출시켜 줍니다.
(6) react 기본파일 설정
src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
const rootElement = document.getElementById('root');
ReactDOM.render(<App />, rootElement);
src/App.tsx
import React from 'react';
const App = () => <>Test</>;
export default App;
src/index.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
</html>