학습 목표
- npm · package.json 기본 구조 이해
- ES Module을 사용한 정적 사이트 구동 경험
- React 패키지를 직접 불러오려다 생기는 오류 → 번들러 필요성 체감
| 항목 | 버전(예시) |
|---|---|
| Node.js | >= 20 |
| 에디터 | VS Code, Cursor |
mkdir week1-vanilla && cd week1-vanillanpm init -y{
"name": "week1-vanilla",
"version": "1.0.0",
"description": "Vanilla ES-Module + React 실습",
"private": true,
"type": "module", // ESM 구문 사용
"scripts": {
"dev": "serve .", // 개발 서버
"start": "npm run dev",
},
"devDependencies": { },
"engines": { "node": ">=20" }
}
npm add -D serve # devDependencies에 자동 반영
serve : 정적 파일을 간단히 서빙
week1-vanilla/
├─ src/.
│ ├─ main.js
│ └─ utils.js
└─ index.html
index.html
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<title>Vanilla ESM Demo</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./src/main.js"></script>
</body>
</html>
src/utils.js
export const greet = (name) => `Hello, ${name}!`;
src/main.js
import { greet } from './utils.js';
document.getElementById('root').textContent = greet('React Study');
npm run dev
브라우저에 “Hello, React Study” 문구가 보이면 성공.
npm add react react-dom
export default function App() {
return <h1>Hello React (without Bundler)</h1>;
}
import { createRoot } from 'react-dom/client';
import React from 'react'; // React 객체가
import App from './App.jsx';
const container = document.getElementById('root');
createRoot(container).render(<App />);
| 오류 메시지(콘솔) | 원인 | 한 줄 요약 |
|---|---|---|
Uncaught SyntaxError: Unexpected token '<' | App.jsx 로드 시 | 브라우저가 < 문자가 들어간 JSX 코드를 순수 JS 로 해석하려다 실패. 즉, Babel · 번들러가 없으면 JSX를 이해할 수 없음 |
Failed to load resource: /favicon.ico 404 | serve가 favicon.ico 를 찾지 못함 | 기능에는 영향 없음 |
부가 설명
<h1> 태그가 "예상치 못한 토큰 <" 이므로 구문 오류가 납니다.favicon.ico 추가Node ≥ 20, VS Code 기준.
mkdir react-study && cd react-study
npm init -y # package.json 생성
package.json의 루트에 "type": "module"을 추가해 ESM 모듈을 사용합니다.
| 구분 | 패키지 | 용도 |
|---|---|---|
| 런타임 | react react-dom | 컴포넌트 & 런타임 |
| 개발 | @babel/core @babel/cli @babel/preset-env @babel/preset-react | JSX·ESNext → ES5/ESM |
| 번들 | webpack webpack-cli webpack-dev-server babel-loader | 모듈 번들 + HMR |
| 미리보기(선택) | serve | 정적 파일 간이 서버 |
npm add react react-dom
npm add -D @babel/core @babel/cli @babel/preset-env @babel/preset-react \
webpack webpack-cli webpack-dev-server babel-loader serve
react-study/
├─ public/
│ └─ index.html
├─ src/
│ ├─ App.jsx
│ └─ index.jsx
├─ .babelrc
├─ webpack.config.js
└─ package.json
{
"presets": [
["@babel/preset-env", { "targets": "defaults" }],
["@babel/preset-react", { "runtime": "automatic" }]
]
}
runtime: "automatic" → import React from 'react' 생략 가능.
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
mode: process.env.NODE_ENV ?? 'development',
entry: './src/index.jsx',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
clean: true, // dist 정리
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: 'babel-loader',
}
],
},
resolve: { extensions: ['.js', '.jsx'] },
devServer: {
static: { directory: path.join(__dirname, 'public') },
port: 5173,
hot: true,
open: true,
},
};
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<title>React Study</title>
</head>
<body>
<div id="root"></div>
<script src="/bundle.js" defer></script>
</body>
</html>
src/App.jsx
export default function App() {
return <h1>Hello, React + Babel + Webpack!</h1>;
}
src/index.jsx
import { createRoot } from 'react-dom/client';
import App from './App.jsx';
const root = createRoot(document.getElementById('root'));
root.render(<App />);
"scripts": {
"dev": "webpack serve --env NODE_ENV=development",
"build": "webpack --env NODE_ENV=production",
"preview":"serve dist"
},
"type": "module"
npm run dev
“Hello, React + Babel + Webpack!”이 보이면 성공!
프로덕션 번들
npm run build # dist/bundle.js 생성
npm run preview # 번들 확인용 로컬 서버
Vite 프로젝트 생성
# 1) Vite 프로젝트 생성
npm create vite@latest week1-vite -- --template react
cd week1-vite
# 2) 의존성 설치
npm install
# 3) 개발 서버 실행
npm run dev
회원 가입 폼 만들어보기