CRA 방식이 아닌 방법으로 직접 설치하기
개요
CRA로 설치하면 너무 편하지만, React를 직접 설치 하는 방법을 알아보자. \
서비스 개발하다보면 CRA의 기본 설정 값을 변경해야 할때가 온다. SSR, code splitting 등등... \
이럴 때를 대비해 먼저 공부해두면 좋다.
Library 설치
npm init 으로 empty project를 만들고 아래의 Library를 추가한다. \
webpack을 설치하는 이유는 번들링하기 위함인데, Babel를 필수적으로 사용해야 한다. \
React는 JSX문법으로 이루저 있는데, 이 문법이 브라우저에서는 작동을 안한다. \
그래서 Babel를 이용해서 브라우저가 이해할 수 있는 문법으로 변환해주어야 하기 때문이다.
express 설치하는 이유는 root path가 아닌 path로 접근 시 404에러가 발생하기 때문이다. \
이유는 SPA이다보니, 각각의 path마다 페이지가 존재 하는게 아니라 하나의 페이지에서 여러 path를 client단에서 제어하기 때문에 직접 다양한 path로 접근 시 에러가 발생한다.
npm install --save-dev webpack webpack-cli
npm install --save-dev html-webpack-plugin css-loader style-loader
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader
npm install --save react react-dom react-router-dom express
Webpack 설정
Project Root Directory에 webpack.config.js를 만들고 아래와 같이 작성한다. \
설정파일에 대해 설명하자면,
- index.js 중심으로 번들링이 시작되고, path에 이미 어떤 파일이 있으면 지우고 시작한다.
- code splitting이 optimization object에 이루어지고 있다.
- webpack은 기 본적으로 js파일만 번들링이되기 때문에 css 파일을 읽으려면 추가 설정을 해야한다.
- css-loader가 css 파일을 읽고, style-loader가 읽어드린 css 파일 정보를 html 문서에 추가한다.
- 번들링 후 code splitting된 js 파일과 css정보를 추가해야할 html문서는 HtmlWebpackPlugin이 생성해주고 있다.
webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, './dist'),
clean: true
},
mode: 'development',
optimization: {
splitChunks: {
chunks: "all",
name: false
},
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader','css-loader']
},
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/env', '@babel/preset-react']
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "src/index.html"
}),
]
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Client Side React Source Code
리엑트 소스를 간단하게 추가해보자.
index.js
import React from 'react'
import ReactDOM from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import App from "./component/App";
ReactDOM.render(<BrowserRouter><App/></BrowserRouter>, document.getElementById('root'))
App.js
import React from 'react'
import { Routes, Route } from "react-router-dom";
import Home from "./Home";
import About from "./About";
export default function App() {
return (
<div>
<h1>hello world</h1>
<Routes>
<Route exact path={'/'} element={<Home/>}/>
<Route path={'/about'} element={<About/>}/>
</Routes>
</div>
)
}
Server Side Source Code
const http = require('http');
const express = require('express')
const path = require('path')
const fs = require('fs')
const app = express();
const index = fs.readFileSync(path.resolve(__dirname, '../dist/index.html')).toString();
app.use('/', express.static(path.resolve(__dirname, '../dist')));
app.get('*', (req, res) => {
res.send(index);
})
const server = new http.Server(app);
server.listen(3000, (err) => {
if (err) {
return console.error(err);
}
});
실행 및 테스트
webpack으로 client side에 대해 번들링을 하여 server에서 읽어드릴 index.html를 획득하고, 그다음에 server 코드를 실행해서 앱을 실행한다.
"npm run dev": "webpack --config webpack.config.js && node src/server.js"