๐Ÿ“˜ CRA์—์„œ Vite๋กœ ๋„˜์–ด์˜ฌ ๋•Œ ์กฐ์šฉํžˆ ๋ฐœ๋ชฉ ์žก๋Š” ๊ฒƒ๋“ค

@leekh8 ยท August 05, 2026 ยท 4 min read

SEO-Booster๋ฅผ create-react-app์—์„œ Vite 5๋กœ ์˜ฎ๊ฒผ๋‹ค. ๋‹จ์ˆœ ์„ค์ • ๊ต์ฒด๊ฒ ๊ฑฐ๋‹ˆ ํ–ˆ๋Š”๋ฐ, ์„ธ ๊ตฐ๋ฐ์„œ ์กฐ์šฉํžˆ ๋ง‰ํ˜”๋‹ค. ๊ณตํ†ต์ ์ด ์žˆ์—ˆ๋‹ค. ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ์›์ธ์„ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š์•˜๋‹ค.


ํ•จ์ • 1: JSX ํŒŒ์ผ ํ™•์žฅ์ž

Vite๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ Rollup ๊ธฐ๋ฐ˜์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  Rollup์€ .js ํŒŒ์ผ์—์„œ JSX๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค. @vitejs/plugin-react๋ฅผ ์„ค์น˜ํ•ด๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋‹ค. ํ”Œ๋Ÿฌ๊ทธ์ธ์ด JSX๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฑด ํ™•์žฅ์ž๊ฐ€ .jsx(๋˜๋Š” .tsx)์ผ ๋•Œ๋ฟ์ด๋‹ค.

CRA๋Š” react-scripts ๋‚ด๋ถ€์˜ Babel ์„ค์ •์ด .js ํŒŒ์ผ์—์„œ๋„ JSX๋ฅผ ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•ด์คฌ๋‹ค. ๊ทธ๋ž˜์„œ CRA ํ”„๋กœ์ ํŠธ์—์„  ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ์ด .js์—ฌ๋„ ์•„๋ฌด ๋ฌธ์ œ์—†์ด ๋Œ์•„๊ฐ„๋‹ค. ์ด๊ฒŒ Vite๋กœ ๋„˜์–ด์˜ค๋Š” ์ˆœ๊ฐ„ ํญํƒ„์ด ๋œ๋‹ค.

src/components/Editor.js โ†’ (Vite/Rollup) โ†’ JSX ์ฒ˜๋ฆฌ ์•ˆ ํ•จ โ†’ ๋นŒ๋“œ ์‹คํŒจ ๋˜๋Š” ๋Ÿฐํƒ€์ž„ ์˜ค๋ฅ˜

์ฆ์ƒ์€ ํ”„๋กœ์ ํŠธ๋งˆ๋‹ค ๋‹ค๋ฅด๋‹ค. ๋นŒ๋“œ ์ž์ฒด๊ฐ€ ๊นจ์ง€๊ธฐ๋„ ํ•˜๊ณ , ๊ฐœ๋ฐœ ์„œ๋ฒ„๋Š” ๋œจ๋Š”๋ฐ ํ™”๋ฉด์ด ๋นˆ ์ฑ„๋กœ ์ฝ˜์†”์— ํŒŒ์‹ฑ ์˜ค๋ฅ˜๊ฐ€ ๋œจ๊ธฐ๋„ ํ•œ๋‹ค. ์ฒ˜์Œ์—” ์„ค์ • ํŒŒ์ผ ๋ฌธ์ œ๋กœ ์ฐฉ๊ฐํ•˜๊ธฐ ์‰ฝ๋‹ค.

ํ•ด๊ฒฐ: .js โ†’ .jsx๋กœ ์ „๋ถ€ ๋ฐ”๊พผ๋‹ค. ์ผ๊ด„ rename์ด๋ผ ๋ฒˆ๊ฑฐ๋กญ์ง€๋งŒ, import ๊ฒฝ๋กœ๋„ ํ•จ๊ป˜ ๋ฐ”๊ฟ”์ค˜์•ผ ํ•œ๋‹ค.

# ์ผ๊ด„ ํ™•์ธ: JSX ๋ฌธ๋ฒ•์ด ๋‹ด๊ธด .js ํŒŒ์ผ ๋ชฉ๋ก
grep -rl "return (" src --include="*.js" | grep -v ".test.js"

vite.config.js์—์„œ optimizeDeps.esbuildOptions๋กœ .js๋„ JSX๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๊ฐ•์ œํ•  ์ˆ˜ ์žˆ๊ธด ํ•˜๋‹ค. ํ•˜์ง€๋งŒ ํ™•์žฅ์ž๊ฐ€ ์—ญํ• ์„ ๋“œ๋Ÿฌ๋‚ด๋Š” ๊ฒŒ ๋‚ซ๋‹ค. ๊ฐ•์ œ ์„ค์ •์€ ๋‹ค์Œ ์‚ฌ๋žŒ์ด ์™œ ์ด๊ฒŒ ์žˆ๋Š”์ง€ ์ดํ•ด ๋ชป ํ•œ๋‹ค.

// vite.config.js โ€” ํ™•์žฅ์ž ๊ฐ•์ œ ๋ฐฉ๋ฒ• (๋น„๊ถŒ์žฅ, ์ž„์‹œ ์šฐํšŒ์šฉ)
export default defineConfig({
  optimizeDeps: {
    esbuildOptions: {
      loader: { '.js': 'jsx' },
    },
  },
});

ํ•จ์ • 2: %PUBLIC_URL%

CRA๋Š” public/ ํด๋” ์•ˆ์˜ ํŒŒ์ผ์„ ์ฐธ์กฐํ•  ๋•Œ %PUBLIC_URL%์ด๋ผ๋Š” ํŠน์ˆ˜ ๋ณ€์ˆ˜๋ฅผ ์ œ๊ณตํ•œ๋‹ค. public/index.html์—์„œ ์ž์ฃผ ์“ฐ์ธ๋‹ค.

<!-- CRA: public/index.html -->
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta property="og:image" content="%PUBLIC_URL%/logo192.png" />

Vite๋Š” ์ด๊ฑธ ๋ชจ๋ฅธ๋‹ค. ๊ทธ๋Œ€๋กœ ๋‘๋ฉด ์‹ค์ œ URL์— %PUBLIC_URL%์ด๋ผ๋Š” ๋ฌธ์ž์—ด์ด ๊ทธ๋Œ€๋กœ ๋ฐ•ํžŒ๋‹ค. ํŒŒ๋น„์ฝ˜์ด ์•ˆ ๋œจ๊ณ  OG ์ด๋ฏธ์ง€๊ฐ€ ๊นจ์ง„๋‹ค.

ํ•ด๊ฒฐ: Vite์˜ index.html์€ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— ๋†“๊ณ , public/ ํŒŒ์ผ์€ ๊ทธ๋ƒฅ /๋กœ ์ฐธ์กฐํ•œ๋‹ค.

<!-- Vite: index.html (๋ฃจํŠธ์— ์œ„์น˜) -->
<link rel="icon" href="/favicon.ico" />
<meta property="og:image" content="/logo192.png" />

๋นŒ๋“œ ๊ฒฝ๋กœ๋ฅผ ์ปค์Šคํ…€ํ–ˆ๊ฑฐ๋‚˜ ์„œ๋ธŒ๋””๋ ‰ํ† ๋ฆฌ์— ๋ฐฐํฌํ•œ๋‹ค๋ฉด import.meta.env.BASE_URL์„ ์“ด๋‹ค.

<link rel="icon" href="<%= import.meta.env.BASE_URL %>favicon.ico" />

ํ•จ์ • 3: react-helmet

react-helmet์€ <head> ํƒœ๊ทธ๋ฅผ ์ปดํฌ๋„ŒํŠธ์—์„œ ์ œ์–ดํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‹ค. CRA ํ”„๋กœ์ ํŠธ์—์„œ ๋ฉ”ํƒ€ ํƒœ๊ทธ, OG, ํƒ€์ดํ‹€ ๋“ฑ์„ ๋‹ค๋ฃจ๋Š” ๊ฐ€์žฅ ํ”ํ•œ ์„ ํƒ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ react-helmet์€ ์˜ค๋ž˜์ „๋ถ€ํ„ฐ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ๋ฉˆ์ถฐ ์žˆ๋‹ค. React 18์˜ StrictMode ์ด์ค‘ ๋งˆ์šดํŠธ์—์„œ ๋‚ด๋ถ€ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ์–ด๊ธ‹๋‚˜๊ณ , ํŠนํžˆ SSR ํ™˜๊ฒฝ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ณด๊ณ ๋œ๋‹ค. CRA ํ™˜๊ฒฝ์—์„  ํ‹ฐ๊ฐ€ ์•ˆ ๋‚˜๋‹ค๊ฐ€ Vite๋กœ ์˜ฎ๊ธฐ๋ฉฐ ๊ฐœ๋ฐœ ์„ค์ •์„ ์ •๋ฆฌํ•˜๋Š” ๊ณผ์ •์—์„œ ๊ฒฝ๊ณ ๊ฐ€ ๋ˆˆ์— ๋„๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค.

๋Œ€์ฒด์ œ๋Š” react-helmet-async ๋‹ค. API๊ฐ€ ๊ฑฐ์˜ ๊ฐ™์•„์„œ ๊ต์ฒด ๋น„์šฉ์ด ์ž‘๋‹ค.

npm uninstall react-helmet
npm install react-helmet-async
// โŒ react-helmet (์œ ์ง€๋ณด์ˆ˜ ์ค‘๋‹จ)
import { Helmet } from "react-helmet";

// โœ… react-helmet-async (React 18 StrictMode ํ˜ธํ™˜)
import { Helmet, HelmetProvider } from "react-helmet-async";

์•ฑ ์ตœ์ƒ๋‹จ์— <HelmetProvider>๋กœ ๊ฐ์‹ธ์ค˜์•ผ ํ•œ๋‹ค.

// main.jsx
import { HelmetProvider } from "react-helmet-async";

root.render(
  <React.StrictMode>
    <HelmetProvider>
      <App />
    </HelmetProvider>
  </React.StrictMode>
);

CRA ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด ๋ถˆํ•„์š”ํ•œ ํŒจํ‚ค์ง€๋ฅผ ๋“œ๋Ÿฌ๋‚ธ๋‹ค

react-scripts๋Š” ํŽธ๋ฆฌํ•˜์ง€๋งŒ ์˜์กด์„ฑ์„ ๋ธ”๋ž™๋ฐ•์Šค๋กœ ์ˆจ๊ธด๋‹ค. Vite๋กœ ๋„˜์–ด์˜ค๋ฉด์„œ package.json์„ ๋‹ค์‹œ ๋“ค์—ฌ๋‹ค๋ณด๋ฉด, ์‹ค์ œ๋กœ ์“ฐ์ง€ ์•Š๋Š” ํŒจํ‚ค์ง€๋“ค์ด ๋ช…์‹œ์ ์œผ๋กœ ๋ณด์ด๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค.

SEO-Booster๋ฅผ ์˜ฎ๊ธฐ๋ฉฐ ์ œ๊ฑฐํ•œ ํŒจํ‚ค์ง€๋“ค:

axios, redux, react-redux, react-router-dom,
react-dnd, tui-editor, react-helmet, dotenv, web-vitals

9๊ฐœ๊ฐ€ ํ•œ ๋ฒˆ๋„ ์‹ค์ œ ๊ธฐ๋Šฅ์— ์“ฐ์ด์ง€ ์•Š์•˜๋‹ค. ์ดˆ๊ธฐ ์„ธํŒ… ์‹œ "๋‚˜์ค‘์— ์“ธ ๊ฒƒ ๊ฐ™์•„์„œ" ๋„ฃ์–ด ๋‘” ๊ฒƒ๋“ค์ด๋‹ค. CRA ๋•Œ๋Š” react-scripts๊ฐ€ ๋นŒ๋“œ๋ฅผ ์•Œ์•„์„œ ํ•ด์ค˜์„œ ์ด๊ฒŒ ๋นŒ๋“œ ์‹œ๊ฐ„์ด๋‚˜ ๋ฒˆ๋“ค ํฌ๊ธฐ์— ์–ผ๋งˆ๋‚˜ ์˜ํ–ฅ์„ ์ฃผ๋Š”์ง€ ์ฒด๊ฐํ•˜๊ธฐ ์–ด๋ ต๋‹ค. Vite๋กœ ๋„˜์–ด์˜ค๋ฉด ๋ฒˆ๋“ค ๋ถ„์„๋„ ์‰ฌ์›Œ์ง€๊ณ , ๋ถˆํ•„์š”ํ•œ ๊ฒƒ๋“ค์ด ๋ˆˆ์— ํ™• ๋“ค์–ด์˜จ๋‹ค.

# Vite ๋นŒ๋“œ ํ›„ ๋ฒˆ๋“ค ๋ถ„์„
npx vite-bundle-visualizer

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ˆœ์„œ ์ •๋ฆฌ

  1. react-scripts ์ œ๊ฑฐ, vite + @vitejs/plugin-react ์„ค์น˜
  2. vite.config.js ์ž‘์„ฑ (root: '.', publicDir: 'public')
  3. index.html์„ ๋ฃจํŠธ๋กœ ์ด๋™, %PUBLIC_URL% ์ œ๊ฑฐ
  4. ์ปดํฌ๋„ŒํŠธ ํŒŒ์ผ .js โ†’ .jsx ์ผ๊ด„ rename + import ๊ฒฝ๋กœ ์ˆ˜์ •
  5. ํ™˜๊ฒฝ๋ณ€์ˆ˜ prefix REACT_APP_ โ†’ VITE_, ์ฐธ์กฐ ์ฝ”๋“œ process.env. โ†’ import.meta.env.
  6. react-helmet โ†’ react-helmet-async ๊ต์ฒด (์“ฐ๊ณ  ์žˆ๋‹ค๋ฉด)
  7. package.json scripts ์ˆ˜์ •: "start": "vite", "build": "vite build", "preview": "vite preview"
  8. ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ Jest์—์„œ Vitest๋กœ ์ „ํ™˜ (์„ ํƒ, ํ•˜์ง€๋งŒ ๊ถŒ์žฅ)

๋งˆ๋ฌด๋ฆฌ

์„ธ ํ•จ์ • ๋ชจ๋‘ CRA๊ฐ€ ๋‚ด๋ถ€์—์„œ ํ•ด์ฃผ๋˜ ๊ฑธ Vite๋Š” ์•ˆ ํ•ด์ค€๋‹ค๋Š” ํŒจํ„ด์ด๋‹ค. CRA๋Š” ํŽธ์˜๋ฅผ ์œ„ํ•ด ๋งŽ์€ ๊ฑธ ์ˆจ๊ฒผ๊ณ , ๊ทธ ๋•์— ์‹œ์ž‘์€ ๋น ๋ฅด์ง€๋งŒ ์•ˆ์—์„œ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๋Š”์ง€ ์ž˜ ์•ˆ ๋ณด์˜€๋‹ค. Vite๋Š” ๋” ํˆฌ๋ช…ํ•˜๊ณ  ๋น ๋ฅด์ง€๋งŒ, ๊ทธ ํˆฌ๋ช…ํ•จ์ด ์ˆจ๊ฒจ์ ธ ์žˆ๋˜ ์ „์ œ๋“ค์„ ํ•œ๊บผ๋ฒˆ์— ๋“œ๋Ÿฌ๋‚ธ๋‹ค.

๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ž์ฒด๋Š” ์–ด๋ ต์ง€ ์•Š๋‹ค. ๋‹ค๋งŒ ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ์›์ธ์„ ์ง์ ‘ ์•ˆ ์•Œ๋ ค์ค„ ๋•Œ๊ฐ€ ๋งŽ๋‹ค. "JSX ํŒŒ์‹ฑ ์˜ค๋ฅ˜"๊ฐ€ ๋œจ๋ฉด ํ™•์žฅ์ž๋ฅผ, ํŒŒ๋น„์ฝ˜์ด ๊นจ์ง€๋ฉด %PUBLIC_URL%์„, StrictMode ๊ฒฝ๊ณ ๊ฐ€ ๋ณด์ด๋ฉด react-helmet์„ ๋จผ์ € ํ™•์ธํ•œ๋‹ค.


๊ด€๋ จ ๊ธ€


@leekh8
๋ณด์•ˆ, ์›น ๊ฐœ๋ฐœ, Python์„ ๋‹ค๋ฃจ๋Š” ๊ธฐ์ˆ  ๋ธ”๋กœ๊ทธ