[React] 리액트 프로젝트와 익스프레스 연동하기

2025. 5. 10. 02:48Library/React

연동 전 폴더 구조 

프로젝트 폴더/
├── client/       # React 앱
└── server/       # Express 서버

1. 서버(Express) 설정

1-1. Express 프로젝트 생성

mkdir 프로젝트 폴더 명 // 프로젝트 폴더(루트 디렉토리) 생성
cd 프로젝트 폴더 명 // 프로젝트 폴더로 경로 이동
mkdir server // server 폴더 생성
cd server // server 폴더로 경로 이동

//npm 설치 + express 및 cors 패키지 설치
npm init -y
npm install express cors

// nodemon을 devDependency로 설치
npm install nodemon --save-dev

// dotenv 설치
npm install dotenv

// server/package.json 수정
{
  ...
  "main": "server.js", // index.js 를 server.js로 변경
  "scripts": {
    "dev": "nodemon server.js"
  }
}


// express 설치 확인
npm list express

//path-to-regexp(express 내부에서 사용하는 라우팅 관련 하위 의존성 패키지)가 
//어떤 버전으로 설치되었는지, 어디에서 사용되고 있는지 확인
npm list path-to-regexp

 

1-2. 기본 서버 파일 생성 및 수정(server/server.js)

const express = require('express');
const cors = require('cors');

const app = express();
const PORT = 5000;

// CORS 설정 (React dev 서버의 포트 허용)
app.use(cors({
  origin: 'http://localhost:3000', // 프론트엔드 포트
  credentials: true,               // 쿠키 사용 시 필요
}));

// 서버 코드에서 CORS 설정 관련 문제 점검 시
//app.use(cors());
//이렇게 기본값으로 변경해서 확인할 수 있음

app.use(express.json());

app.get('/api/hello', (req, res) => {
  res.json({ message: 'Hello from Express!' });
});

app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});
  • origin: 허용할 출처, 배열도 가능 (origin: ['http://localhost:3000', 'https://your-prod.com'])
  • credentials: true: 인증 관련 요청을 허용하려면 반드시 설정 (withCredentials: true와 함께 사용)

 

2. 클라이언트(React) 설정

2-1. 리액트 프로젝트 생성

루트 디렉터리(프로젝트 폴더)로 이동 후 명령어 실행

// 리액트 프로젝트 생성 (vite or CRA 선택)
// CRA로 설치
npx create-react-app client 
// vite로 설치 & 실행 명령어 npm run dev
npm create vite@latest

//이 때 create-react-app이 설치되어있지 않으면 아래와 같은 질문이 뜸. y 입력하면 됨
Need to install the following packages:
create-react-app@5.1.0
Ok to proceed? (y) y

// client 폴더로 이동 (CRA로 리액트 프로젝트 생성 시 자동 생성)
cd client

//(선택) axios 사용할 경우
npm install axios

//(선택) 배포 시 Express가 React 빌드 서빙하도록 설정
npm run build

// 리액트 테스트 실행(잘 설치됐는지)
npm start

// 번외로 CRA로 프로젝트 생성 시 아래와 같은 안내(지원 종료...ㅎ)를 볼 수 있음
create-react-app is deprecated.

You can find a list of up-to-date React frameworks on react.dev
For more info see:https://react.dev/link/cra

// 리액트 버전 다운그레이드
npm install react@18.3.1 react-dom@18.3.1
This error message will only be shown once per install.

2-2. client/package.json 수정

// client/package.json
{
  ...
  "proxy": "http://localhost:5000",
  "scripts": {
    "start": "react-scripts start"
  }
}

2-3. API 요청 테스트(예: src/app.js)

import React, { useEffect, useState } from 'react';
import axios from 'axios'; // axios 사용할 경우

function App() {
  const [message, setMessage] = useState('');

	useEffect(() => {
		axios.get('http://localhost:5000/api/hello', {
			withCredentials: true // 쿠키 필요 시
		})
		.then(res => setMessage(res.data.message))
		.catch(err => console.error(err));
    }, []);

  return (
    <div>
      <h1>{message || 'Loading...'}</h1>
    </div>
  );
}

export default App;

2-3. server/server.js에 아래 코드 추가

const path = require('path');

// React 정적 파일 서빙
app.use(express.static(path.join(__dirname, '../client/build')));

app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, '../client/build/index.html'));
});

3. (선택) React + Express 프로젝트 동시 실행 및 미리보기 (핫 리로드)

3-1. server 폴더에서 nodemon 설치 (위에서 한 부분임)

cd server
npm install --save-dev nodemon

//server/package.json에 script 추가
"scripts": {
  "dev": "nodemon server.js"
}

// (선택) 로그 더 자세히 보기
"scripts": {
  "dev": "nodemon --verbose server.js"
}

3-2. 루트 디렉토리에서 concurrently 설치 및 package.json 수정

cd ..
npm install --save-dev concurrently
(또는 npm install -D concurrently)

"scripts": {
  "client": "npm run start --prefix client",   // client 폴더에서 "start" 실행
  "server": "npm run dev --prefix server",     // server 폴더에서 "dev" 실행 (nodemon)
  "dev": "concurrently \"npm run server\" \"npm run client\""
}

//위에 오류나면 dev 부분을 아래처럼 변경
{
  "name": "my-app-root",
  "version": "1.0.0",
  "scripts": {
    "dev": "concurrently \"npm run dev --prefix server\" \"npm start --prefix client\""
  }
}

3-3. client 폴더에서 package.json 수정

"scripts": {
  "dev": "react-scripts start", //추가하는 부분
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject"
}

4. .env 설정을 통해 포트나 환경 변수 분리

// 리액트 프로젝트를 vite로 생성 시 3000 대신 5173
// client/.env
PORT=3000 
REACT_APP_API_BASE=http://localhost:5000


//server/.env
PORT=5000
NODE_ENV=development
CLIENT_ORIGIN=http://localhost:3000


//server/server.js 수정
require("dotenv").config(); // .env 불러오기
const express = require("express");
const cors = require("cors");
const path = require("path");

const app = express();
const PORT = process.env.PORT || 5000;

// CORS 설정 (React 개발 서버 허용)
app.use(cors({
  origin: process.env.CLIENT_ORIGIN,
  credentials: true,
}));

// JSON 요청 파싱
app.use(express.json());

// 배포 환경일 때만 React 정적 파일 서빙
if (process.env.NODE_ENV === "production") {
  app.use(express.static(path.join(__dirname, "../client/build")));

  app.get("*", (req, res) => {
    res.sendFile(path.join(__dirname, "../client/build/index.html"));
  });
}
// 개발 모드 (NODE_ENV=development) 에는 정적 파일 안 읽고 React 개발 서버 사용
// 배포 모드 (NODE_ENV=production) 에는 Express가 build 폴더 서빙

// API 라우트 예시
app.get("/api/hello", (req, res) => {
  res.json({ message: "Hello from Express!" });
});

// 서버 시작
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

//server/package.json
"scripts": {
  "dev": "nodemon index.js",
  "start": "NODE_ENV=production node index.js"
}
// ** Windows에서는 NODE_ENV=production 방식이 안 되기 때문에 아래처럼 변경
"start": "set NODE_ENV=production && node index.js" // Windows용


// .gitignore에 .env 추가
# .gitignore
.env

//client/src/App.js 수정
  useEffect(() => {
		axios.get(`${process.env.REACT_APP_API_BASE}/api/hello`, {
			withCredentials: true // 쿠키 필요 시
		})
		.then(res => console.log(res.data))
		.catch(err => console.error(err));
  }, []);
  
  // fetch인 경우
  // fetch(`${process.env.REACT_APP_API_BASE}/api/hello`)

5. 최종 실행 테스트

  • npm run dev : concurrently 패키지를 통해 server와 client를 동시에 실행하는 스크립트.
    주로 개발 환경에서 서버클라이언트를 동시에 실행할 때 사용(= 서버 API와 리액트 앱을 동시 개발 시 사용)
  • npm start : React 애플리케이션을 실행하는 데 사용됨. 즉, client 폴더에서 React 개발 서버를 실행함.(cli만 실행)
    >> React가 동작하는 개발 모드에서 npm start를 사용
  • 결론
    > 리액트 클라이언트를 독립 실행할 때 >> npm start (클라이언트 폴더)
    > 서버와 클라이언트를 동시 실행해야할 때 >> npm run dev (프로젝트 루트 디렉토리)