TLDR;
๋ฆฌ์กํธ ์ฑ์ ์ค์นํ๊ธฐ ์ํด CRA๋ฅผ ์ฌ์ฉํ๊ณ ๊ณ์ จ๋์? ์ด์ ๋ CRA๊ฐ deprecate ๋ฉ๋๋ค.
ํด๋น ์ด์ ๋ ํฌ๊ฒ CRA๋ ๋ผ์ฐํ , ๋ฐ์ดํฐ fetching, ์ฝ๋ ์คํ๋ฆฟ์ ์์ฒด์ ์ผ๋ก ์ง์ํ์ง ์์
์ถ๊ฐ์ ์ผ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์กดํด์ผํ๋ค๋ ์ , ์ต๊ทผ ๋ง์ ํ๋ ์์ํฌ๋ค์ด ํด๋น ๋ฌธ์ ๋ค์ ํด๊ฒฐํ๊ณ ํด๋น ๊ธฐ๋ฅ๋ค์ ์ํด CRA๊ด๋ฆฌ๊ฐ ๋ถํ์ํด์ก๊ธฐ ๋๋ฌธ์ ๋๋ค.
ํ๋ ์์ํฌ๋ ๋น๋ ํด๋ก ๋ฆฌ์กํธ ํ๋ก์ ํธ๋ฅผ ๋ง์ด๊ทธ๋ ์ด์ ํ๊ธฐ๋ฅผ ๊ถ์ฅํฉ๋๋ค. ๋น๋ก CRA+๋น๋ ํด๋ ์ ํ ๊ฐ๋ฅํ ์ต์ ์ด์ง๋ง ๋ผ์ฐํ , ๋ฐ์ดํฐ fetching, ์ฝ๋ ์คํ๋ฆฟ ๊ธฐ๋ฅ์ “์” ํตํฉํด๋์ Next.js, React Router, Expo์ ๊ฐ์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ถ์ฒํฉ๋๋ค.
์์ ํ๋ ์์ํฌ๋ค์ SSR๊ณผ CSR ์ต์ ๋ชจ๋ ์ ๊ณตํฉ๋๋ค.
SSR์ด SEO๋ฟ๋ง ์๋๋ผ ๋ค์ด๋ก๋ํด์ผํ ์๋ฐ์คํฌ๋ฆฝํธ ์์ ์ค์ฌ ์ฑ๋ฅ ์ต์ ํ์ ๋์์ด ๋๋ค๋ ์ ์ ๊ณ ๋ คํ๋ฉด SSR์ CSR์ด ํ์ํ ํ์ด์ง๋ฅผ ์ ์ ํ๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ํด๋ณด์ ๋๋ค.
ํด๋น ๊ธ์ February 14, 2025 by Matt Carroll and Ricky Hanlon์ด ์์ฑํ Sunsetting create react app์ ๋ฒ์ญ/์์ญ ํ์ต๋๋ค.
Create React App๋ฅผ deprecateํ๊ธฐ๋ก ํ์ต๋๋ค.
CRA๋ก ๋ง๋ค์ด์ง ์ฑ๋ค์ ํ๋ ์์ํฌ๋ก ๋ง์ด๊ทธ๋ ์ด์ ์ ํ๊ฑฐ๋ vite, parcel ์ด๋ RSBuild ์ ๊ฐ์ build tool๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๊ธฐ๋ฅผ ๊ถ์ฅํฉ๋๋ค.
ํด๋น ํฌ์คํธ๋ ์ถ๊ฐ์ ์ผ๋ก ํ๋ก์ ํธ์ ์ ์ ํ ํ๋ ์์ํฌ๊ฐ ์๋ ๊ฒฝ์ฐ๋ฅผ ์ํด ํ๋ ์์ํฌ ๋ง๋๋ ๋ฒ, React app ์ฒ์๋ถํฐ ๋ง๋๋ ๋ฒ์ ๋ํด ๋ค๋ฃจ๊ณ ์ ํฉ๋๋ค.
2016๋ ์ Create React app์ ์ถ์ํ์ ๋น์, React app์ ‘์ด๋ป๊ฒ ๋ง๋ค์ด์ผํ๋ค’๋ ๊ท์น์ด ์์์ต๋๋ค.
React ์ฑ์ ๋ง๋ค๊ธฐ ์ํด์๋ JSX, lint, hot reloading์ ๊ฐ์ ๊ธฐ๋ณธ ๊ธฐ๋ฅ๋ค์ ์ง์ํ๊ธฐ ์ํด ์ฌ๋ฌ ํด๋ค์ ์ถ๊ฐ์ ์ผ๋ก ์ค์นํด์ผํ์ฃ . ์ด ๊น๋ค๋ก์ด ์ผ์ ์ปค๋ฎค๋ํฐ๊ฐ ๋ง๋ boilerplates๊ฐ ํธ๋ค๋งํ์์ง๋ง, boilerplate์ ์ ๋ฐ์ดํธํ๊ธฐ๋ ์ด๋ ต๊ณ fragmentation์ ๋ฆฌ์กํธ๊ฐ ์๋ก์ด ๊ธฐ๋ฅ๋ค์ ์ถ๊ฐํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋ค์์ต๋๋ค.
CRA๋ ์ด ๋ฌธ์ ๋ฅผ ํ๋์ ํต์ผ๋ ๊ถ์ฅ ์ค์ ๋ฐฉ์์ผ๋ก ์ฌ๋ฌ ํด๋ค์ ํฉ์ณ์ ํด๋น ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์์ฃ .
์ด ๋ฐฉ์์ผ๋ก ์ฑ๋ค์ด ๊ฐ๋จํ๊ฒ ์๋ก์ด ํด๊ณผ ๊ธฐ๋ฅ์ ์ง๋ ๋ฒ์ ผ์ผ๋ก ์ ๊ทธ๋ ์ด๋๋ฅผ ํ๊ฑฐ๋, ๋ฆฌ์กํธ ํ์ด ์์ง ์์ ํด ๋ณํ(Fast Refresh support, React Hooks lint rules)๋ฅผ ๊ฐ๋ฅํ ๋ง์ ์ฌ์ฉ์๋ค์๊ฒ ์ ๊ณตํ ์ ์๋๋ก ํ์ฃ . ์ด ๋ชจ๋ธ์ ์ธ๊ธฐ์ ํ์ ์ด ์ค๋๋ ์๋ ํด๋น ๋ฐฉ์์ผ๋ก ์์ ํ๋ ํด๋ค๋ง์ ์นดํ ๊ณ ๋ฆฌ๊ฐ ์์ ์์ ์ ๋๊ฐ ๋์์ต๋๋ค.
Deprecating Create React App
๋น๋ก CRA๋ก ํ๋ก์ ํธ ์์ํ๊ธฐ๋ ์ฝ์ง๋ง, ํ๋ก๋์ ์ฑ์ผ๋ก์จ ์ต์์ ๊ธฐ๋ฅ๋ค์ ํ๊ธฐ์๋ ์ฌ๋ฌ ์ ์ฝ๋ค ์ด ์์์ต๋๋ค.
์์น๋๋ก๋ผ๋ฉด ํ๋ ์์ํฌ๋ก ๋ฐ์ ์์ผ์ ํด๊ฒฐํ ๋ฌธ์ ์ด์ง๋ง, CRA๋ ํ์ฌ ์ ์ง๋ณด์ ๊ด๋ฆฌ์๋ค์ด ์๊ณ ,
์ด๋ฏธ ์ด ๋ฌธ์ ๋ค์ ํด๊ฒฐํ ํ๋ ์์ํฌ๋ค์ด ์๋ํด์ CRA๋ฅผ deprecateํ๊ธฐ๋ก ํ์ต๋๋ค.
์ค๋๋ถํฐ ์๋ก์ด app์ CRA๋ก ์ค์นํ ๊ฒฝ์ฐ deprecation ๊ฒฝ๊ณ ๋ฅผ ๋ณด์๊ฒ ๋ ๊ฒ์ ๋๋ค.
ํ๋ ์์ํฌ๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๊ธฐ
์ด์ ๋ ํ๋ ์์ํฌ๋ก ์๋ก์ด ๋ฆฌ์กํธ์ฑ ์์ฑํ๊ธฐ๋ฅผ ๊ถ์ฅํฉ๋๋ค.
๊ถ์ฅํ๊ณ ์๋ ๋ชจ๋ ํ๋ ์์ํฌ๋ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋๋๋ง(CSR)๊ณผ ์ฑ๊ธ ํ์ด์ง ์ฑ(SPA)์ ์ง์ํ๊ณ , CDN์ด๋ ์๋ฒ์์ด ์ ์ ํธ์คํ ์๋น์ค๋ก ๋ฐฐํฌ๊ฐ ๊ฐ๋ฅํ๋๋ก ์ง์ํฉ๋๋ค.
์ด๋ฏธ CRA๋ก ๋ง๋ค์ด์ง ์ฑ์ ๋ค์์ ๊ฐ์ด๋๋ฅผ ํตํด ์์ ํด๋ผ์ด์ธํธ(client-only) ๊ธฐ๋ฐ์ SPA๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๋๋ฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค.
- Next.js’ Create React App migration guide
- React Router’s framework adoption guide.
- Expo webpack to Expo Router migration guide
๋น๋ ํด๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๊ธฐ
์ฑ์ด ๋ ํนํ ์ ์ฝ์ด ์๊ฑฐ๋, ์ง์ ํ๋ ์์ํฌ๋ฅผ ๋ง๋ค์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ๋ฅผ ์ํ๊ฑฐ๋, ๋ฆฌ์กํธ๊ฐ ์ด๋ป๊ฒ ๋์ํ๋ ์ง ๋ผ๋๋ถํฐ ์ดํด๋ณด๊ณ ์ถ๋ค๋ฉด Vite, Parcel ๋ Rsbuild๋ฅผ ํตํด ๋ฆฌ์กํธ ์ธํ ์ ์ปค์คํ ๋ง์ด์งํ ์ ์์ต๋๋ค.
์๋์ ๋งํฌ๋ค์ CRA๋ก ๋ง๋ค์ด์ง ์ฑ์ ๋น๋ํด๋ก ๋ง์ด๊ทธ๋ ์ด์ ํ๋๋ฐ ๋์์ด ๋ ๊ฒ์ ๋๋ค:
- Vite Create React App migration guide
- Parcel Create React App migration guide
- Rsbuild Create React App migration guide
Vite, Parcel ๋ Rsbuild๋ก ์์ํ๊ธฐ ์ํด ๋์์ด ํ์ํ์๋ฉด Building a React App from Scratch๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
๐ค ํ๋ ์์ํฌ๊ฐ ํ์ํ ๊น์?
๋๋ถ๋ถ์ ์ฑ๋ค์ ํ๋ ์์ํฌ์ ๋์ ๋ณด๊ฒ ์ง๋ง, ํน์ ๊ฒฝ์ฐ์๋ ๋ฆฌ์กํธ๋ฅผ ์ฒ์๋ถํฐ ์ํ ํ๋ ๊ฒ์ด ๋ ์ ์ ํ ์ ์์ต๋๋ค. ๋จผ์ ์ดํด๋ณผ ๊ฒ์ ์ฑ์ด ๋ผ์ฐํ ์ด ํ์ํ ๊ฒฝ์ฐ๋ผ๋ฉด ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค.
Svelte๊ฐ Sveltekit์ด ์๊ณ , Vue๋ Nuxt๊ฐ ์๊ณ , Solid๊ฐ SolidStart๊ฐ ์๋ฏ์ด, ๋ฆฌ์กํธ๋ data-fetching ์ code-splitting๊ณผ ๊ฐ์ ๊ธฐ๋ฅ๋ค์ด ๋ผ์ฐํ ์ ์ฒ์๋ถํฐ ์์ ํ ํตํฉ๋์ด ์๋ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํฉ๋๋ค. ๋ณต์กํ ์ค์ ์ ์ง์ ํด์ผํ๋ ์๊ณ ์ค๋ฌ์์ ์ด๋ฏธ ๋ง๋ค์ด์ง ํ๋ ์์ํฌ๋ค์ด ํด๊ฒฐํ์ฃ . ํ์ง๋ง Vite, Parcel ๋๋ Rsbuild์ ๊ฐ์ ๋น๋ ํด๋ก ๋ฆฌ์กํธ ์ฑ ์ฒ์๋ถํฐ ๋ง๋๋ ๊ฒ ๋ํ ์ธ์ ๋ ์ ํ๊ฐ๋ฅํ ์ต์ ์ ๋๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๋ฆฌ์กํธ๊ฐ ํ๋ ์์ํฌ ์ฌ์ฉ์ ๊ถ์ฅํ๋ ์ด์ ์ ๋น๋ ํด์ ํ๊ณ์ ๋ํด ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋น๋ ํด์ ํ๊ณ
CRA์ ๋น๋ ํด์ ํตํด ๋ฆฌ์กํธ ์ฑ์ ์์ํ๋ ๊ฒ์ด ์ฌ์์ก์ต๋๋ค.
npx create-react-app my-app๋ฅผ ์คํํ๋ฉด dev ์๋ฒ, linting, production ๋น๋๋ฅผ ํฌํจํด ์ถฉ๋ถํ ์ค์ ์ด ๋ ๋ฆฌ์กํธ ์ฑ๊ฐ ๋ง๋ค์ด์ง์ฃ .
์๋ฅผ ๋ค๋ฉด ๋ด๋ถ ์ด๋๋ฏผ ํด์ ๋ง๋ค๊ณ ์ ํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋๋ฉ ํ์ด์ง๋ก ์์ํ ์ ์์ต๋๋ค:
export default function App() {
return (
<div>
<h1>Welcome to the Admin Tool!</h1>
</div>
)
}
JSX์ ๊ฐ์ ๋ฆฌ์กํธ ๊ธฐ๋ฅ๋ค์ ๋ฐ๋ก ์ฌ์ฉํ์ฌ ์ฝ๋ฉ์ ํ ์ ์๊ณ , ๋ํดํธ ๋ฆฐํธ ๊ท์น, dev ์ prod ๊ฐ๊ฐ์์ ์คํ๊ฐ๋ฅํ๋๋ก ํ๋ ๋ฒ๋ค๋ฌ๊ฐ ์์ง๋ง, ์ค์ ํ๋ก๋์ ์ฑ์ ๋ง๋ค๊ธฐ์๋ ํ์์ ์ธ ํด๋ค์ด ๋ถ์ฌํ์ฃ .
๋๋ถ๋ถ์ ํ๋ก๋์ ์ฑ๋ค์ routing, data fetching ๊ทธ๋ฆฌ๊ณ ์ฝ๋ ์คํ๋ฆฟํ๊ธฐ ๋ฑ์ ๊ธฐ๋ฅ๋ค์ด ํ์ํฉ๋๋ค.
๋ผ์ฐํ
CRA๋ ๋ผ์ฐํ ๊ท์น์ ํน์ ํ๊ณ ์์ง๋ ์์ต๋๋ค. ๋ง ๋ฆฌ์กํธ๋ฅผ ์์ํ๋ค๋ฉด useState์ ํตํด ๋ผ์ฐํธ๋ฅผ ๋ณ๊ฒฝํ๋ ๋ฐฉ์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ํ์ง๋ง ํด๋น ๋ฐฉ์์ ์ฑ์ ๋งํฌ๋ฅผ ๊ณต์ ํ ์ ์๋๋ก ํฉ๋๋ค. ๋ชจ๋ ๋งํฌ๋ค์ ๊ฐ์ ํ์ด์ง๋ฅผ ๊ฐ๋ฆฌํค๊ณ , ์ฑ์ ๊ตฌ์กฐ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ์ด๋ ค์์ง์ฃ .
import {useState} from 'react';
import Home from './Home';
import Dashboard from './Dashboard';
export default function App() {
// โ Routing in state does not create URLs
const [route, setRoute] = useState('home');
return (
<div>
{route === 'home' && <Home />}
{route === 'dashboard' && <Dashboard />}
</div>
)
}
CRA๋ฅผ ์ฌ์ฉํ๋ ๋๋ถ๋ถ์ ์ฑ๋ค์ React Router ๋Tanstack Router์ ๊ฐ์ ๋ผ์ฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ์ฌ ๋ผ์ฐํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค. ๋ผ์ฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด ์ฑ์ ์ถ๊ฐ์ ์ธ ๋ผ์ฐํธ๋ฅผ ๊ตฌ์ฑํ ์ ์๊ณ , ์ฑ์ ๊ตฌ์กฐ์ ๋ํ opinion์ ์ ๊ณตํ๋ฉฐ ๋ผ์ฐํธ์ ํด๋น๋๋ ๋งํฌ๋ฅผ ๊ณต์ ํ ์ ์๋๋ก ํฉ๋๋ค.
React Router์ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ด ๋ผ์ฐํธ๋ฅผ ์ ์ํ ์ ์์ฃ :
import {RouterProvider, createBrowserRouter} from 'react-router';
import Home from './Home';
import Dashboard from './Dashboard';
// โ
Each route has it's own URL
const router = createBrowserRouter([
{path: '/', element: <Home />},
{path: '/dashboard', element: <Dashboard />}
]);
export default function App() {
return (
<RouterProvider value={router} />
)
}
์ด์ /dashboard๋งํฌ๋ฅผ ๊ณต์ ํ ์ ์๊ณ , ์ฑ์ด ๋์ฌ๋ณด๋ ํ์ด์ง๋ก ์ด๋ํ ์ ์๊ฒ ๋์์ฃ .
๋ผ์ฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ฉด ์ค์ฒฉ ๋ผ์ฐํธ(nested routes), ๋ผ์ฐํธ ๊ฐ๋(route guard), ๋ผ์ฐํธ ํธ๋์ง์ (route transition)์ ๊ฐ์ด ๋ผ์ฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ด ๊ตฌํํ๊ธฐ ์ด๋ ค์ด ๊ธฐ๋ฅ๋ค์ ๋๋ฆด ์ ์๋๋ก ํฉ๋๋ค.
๋น๋ก ๋ผ์ฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ด ์ฑ์ ๋ณต์ก๋๋ฅผ ๋์ด์ง๋ง ์์ผ๋ฉด ๊ตฌํํ๊ธฐ ์ด๋ ค์ด ์ถ๊ฐ ๊ธฐ๋ฅ๋ค์ ์ ๊ณตํ๊ธฐ๋ ํ์ฃ .
๋ฐ์ดํฐ fetching
CRA์ ํฐ ๋ฌธ์ ์ ์ค ํ๋๋ data fetching์ด ์์ต๋๋ค. CRA๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐฉ์์ด ํน์ ๋์ด ์์ง ์๊ณ , ์ด์ ๋ง ์์ํ๊ณ ์๋ ์ ์ฅ์ด๋ผ๋ฉด useEffect์์ ๋ฐ์ดํฐ๋ฅผ fetchํด์ ๋ก๋ํ๋ ์ต์ ์ ๊ณ ๋ คํ์ ์๋ ์์ต๋๋ค.
ํ์ง๋ง ์ด ๋ฐฉ์์ ์ปดํฌ๋ํธ๊ฐ ๋๋๋ ์ดํ์ ๋ฐ์ดํฐ๊ฐ fetch๋๊ธฐ ๋๋ฌธ์ ๋คํธ์ํฌ waterfall๋ฅผ ์ผ์ผํฌ ์์๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๋คํธ์ํฌ waterfall์ ์ฝ๋๋ฅผ ๋ค์ด๋ก๋ ํ๊ณ ์์ ๋ ๋ณ๋ ฌ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ fetchํ๋ ๊ฒ์ด ์๋๋ผ, ์ฑ์ด ๋๋๋ ๋ ์ํํ์ฌ ๋ฐ์ํฉ๋๋ค.
๋ค์๊ณผ ๊ฐ์ด useEffect ์์์ ๋ฐ์ดํฐ๋ฅผ fetchํ๋ฉด ์ค์ ๋ก๋ ๋ ์ผ์ฐ ๋ฐ์ดํฐ๋ฅผ fetchํ ์ ์์์์๋ ๋ถ๊ตฌํ๊ณ , ์ ์ ๋ ์ค์ ์ฝํ ์ธ ๋ฅผ ๋ณด๊ธฐ๊น์ง ๋ ์ค๋ ๊ธฐ๋ค๋ ค์ผํ๋ค๋ ๋ฌธ์ ๊ฐ ์๊น๋๋ค.
export default function Dashboard() {
const [data, setData] = useState(null);
// โ Fetching data in a component causes network waterfalls
useEffect(() => {
fetch('/api/data')
.then(response => response.json())
.then(data => setData(data));
}, []);
return (
<div>
{data.map(item => <div key={item.id}>{item.name}</div>)}
</div>
)
}
React Query, SWR, Apollo, or Relay ์ ๊ฐ์ fetch ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฅผ prefetchํ์ฌ ์ปดํฌ๋ํธ๊ฐ ๋๋ํ๊ธฐ ์ ์ ์์ฒญ์ ์์ํ ์ ์๋๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ฃ .
๋ค์ ์์์ ๊ฐ์ด ๋ผ์ฐํ loader ํจํด์ ํจ๊ป ๋ผ์ฐํธ ๋ ๋ฒจ์ ๋ฐ์ดํฐ ์์กด์ฑ์ ๋ถ์ฌํ๋ฉด ๋ผ์ฐํฐ๊ฐ ๋ฐ์ดํฐ fetch๋ฅผ ํน์ ํํ์ฌ ์ต์ ํํ๋๋ก ํ ์ ์์ต๋๋ค:
export async function loader() {
const response = await fetch(`/api/data`);
const data = await response.json();
return data;
}
// โ
Fetching data in parallel while the code is downloading
export default function Dashboard({loaderData}) {
return (
<div>
{loaderData.map(item => <div key={item.id}>{item.name}</div>)}
</div>
)
}
์ฒซ ๋ก๋ ์ ๋ผ์ฐํฐ๋ ๋ผ์ฐํธ๋ฅผ ๋๋ํ๊ธฐ ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๋ก fetchํ ์ ์๊ฒ ๋ฉ๋๋ค.
์ ์ ๊ฐ ์ฑ ๋ด์์ ์ด๋ ์ ๋ฐ์ดํฐ์ ๋ผ์ฐํธ๋ฅผ ๋ณ๋ ฌ์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์๊ฒ ๋์ด ํ๋ฉด์ ์ฝํ ์ธ ๋ฅผ ๋ณด๊ธฐ๊น์ง์ ์๊ฐ์ ๋จ์ถํ๊ณ ์ ์ ๊ฒฝํ์ ๊ฐ์ ํ ์ ์์ฃ .
ํ์ง๋ง ํด๋น ๋ฐฉ์์ ๋ก๋๋ฅผ ์ ์ ํ configureํด์ผํ๊ณ , ์ฑ๋ฅ๊ณผ ๋ณต์ก์ฑ ๊ฐ์ ํธ๋ ์ด๋์คํ๋ฅผ ์๊ตฌํฉ๋๋ค.
์ฝ๋ ์คํ๋ฆฟํ๊ธฐ
CRA์ ํฐ ๋ฌธ์ ์ค ํ๋๋ ์ฝ๋ ์คํ๋ฆฟํ๊ธฐ์ ๋๋ค.
CRA๋ ์ฝ๋ ์คํ๋ฆฟ์ ํ๊ธฐ ์ํด ํน์ ๋ ํด๊ฒฐ์ฑ ์ ์ ์ํ์ง ์์ฃ . ๋ฆฌ์กํธ๋ฅผ ๋ง ์์ํ ์ ์ฅ์ด๋ผ๋ฉด ์ฝ๋ ์คํ๋ฆฟํ๋ ๊ฒ ์์ฒด๋ฅผ ์์ ๊ณ ๋ คํ์ง ์์์ ์๋ ์์ต๋๋ค.
ํด๋น ๊ฒฝ์ฐ, ์ฑ์ด ์ฑ๊ธ ๋ฒ๋ค์ ๊ฒฝ์ฐ bundle.js : 75kb๋ก ์ ๊ณต๋๋ค๋ ์ ์ ๋๋ค.
ํ์ง๋ง ์ ์ ๊ฐ ํ์ํ ๊ฒฝ์ฐ์๋ง ๋ฒ๋ค์ ๋ค์ด๋ก๋ํ ์ ์๋๋ก ๋ถ๋ฆฌํ๋ ๊ฒ์ด ์ฑ๋ฅ์ ๊ณ ๋ คํ๋ฉด ์ด์์ ์ด์ฃ .
์ ์ ๊ฐ ํ์ฌ ์๋ ํ์ด์ง์ ๋ํ ์ฝ๋๋ง ๋ค์ด๋ก๋ํด๋ ๋๊ธฐ ๋๋ฌธ์ ์ฑ์ ๋ก๋ํ๊ธฐ๊น์ง ๋๊ธฐ์๊ฐ์ ์ค์ผ ์ ์์ต๋๋ค.
- core.js 25kb
- home.js 25kb
- dashboard.js 25kb
์ฝ๋ ์คํ๋ฆฟ์ ํ๋ ๋ฐฉ๋ฒ ์ค ํ๋๋ React.lazy๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
ํ์ง๋ง ์ด๋ ์ปดํฌ๋ํธ๊ฐ ๋๋๋๊ธฐ ์ ๊น์ง ์ฝ๋ fetch๋์ง ์๋๋ค๋ ๊ฒ์ ์๋ฏธํ๊ณ , ์ด๋ ๋คํธ์ํฌ waterfall๋ก ์ด์ด์ง ์ ์์ต๋๋ค. ๋ ์ ์ ํ ํด๊ฒฐ์ฑ ์ ์ฝ๋๊ฐ ๋ค์ด๋ก๋ํ๊ณ ์์ ๋ ๋ณ๋ ฌ์ ์ผ๋ก ์ฝ๋๋ฅผ fetchํ ์ ์๊ฒ ๋ผ์ฐํฐ feature๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค.
์๋ฅผ ๋ค์ด React Router๋ lazy ์ต์ ์ ์ถ๊ฐํ์ฌ ํน์ ๋ผ์ฐํธ์์๋ ์ฝ๋ ์คํ๋ฆฟ์ ํ์ฌ ๋ก๋๋ ๋ ์ต์ ํ๋ฅผ ํด์ค๋๋ค:
import Home from './Home';
import Dashboard from './Dashboard';
// โ
Routes are downloaded before rendering
const router = createBrowserRouter([
{path: '/', lazy: () => import('./Home')},
{path: '/dashboard', lazy: () => import('Dashboard')}
]);
์ต์ ํ๋ ์ฝ๋ ์คํ๋ฆฟํ๊ธฐ๋ ์ฝ์ง ์๊ณ , ์ ์ ๋ค์ด ํ์ ์ด์์ผ๋ก ๋ง์ ์ฝ๋๋ฅผ ๋ค์ด๋ก๋ํ๊ฒ๋ ํ๋ ์ค์๋ก ์ด์ด์ง ์๋ ์์ต๋๋ค. ์บ์ฑ ์ต๋ํํ๊ธฐ, ๋ณ๋ ฌ fetch, "์ํธ์์ฉ ์์ ์ํฌํธํ๊ธฐ (import on interaction)" ํจํด๊ณผ ํจ๊ป ์ฌ์ฉ๋์ด์ผ ๋ผ์ฐํฐ์ ๋ฐ์ดํฐ ๋ก๋ฉ ํด๊ฒฐ์ฑ ์ ์ ์ฌ์ฉํ ์ ์์ฃ .
+ CRA๋ฅผ ๋ณด๋ด์ฃผ๋ ์ถ๊ฐ์ ์ธ ์ด์ ๋ค…
๋ผ์ฐํ , ๋ฐ์ดํฐ fetching, ์ฝ๋ ์คํ๋ฆฟํ๊ธฐ ๋ฑ์ ๊ธฐ๋ฅ ๋ถ์ฌ๋ CRA๋ฅผ ๋ณด๋ด์ค์ผํ๋ ์ฌ๋ฌ ์ด์ ๋ค ์ค ๋ช๊ฐ์ง์ ๋ถ๊ณผํฉ๋๋ค. ์์ ๊ธฐ๋ฅ๋ค์ ์ถ๊ฐํ๊ณ ๋ pending state ๊ณ ๋ คํ๊ธฐ, ๋ค๋น๊ฒ์ด์ ์ธํฐ๋ฝ์ , ์ฌ์ฉ์๋ค์ ์ํ ์๋ฌ ๋ฉ์ธ์ง, ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ revalidateํ๊ธฐ ๋ฑ ์ค์ ์ฑ์ ๋ง๋ค๊ธฐ ์ํด์ ํด๊ฒฐํ ๋ฌธ์ ๋ค์ด ์กด์ฌํ์ฃ .
์ค์ ์ ์ ๋ค์ ์ํด์ ํด๊ฒฐํด์ผํ ๋ฌธ์ ์นดํ ๊ณ ๋ฆฌ๋ค์ ๋์ดํ์๋ฉด:
- Accessibility
- Asset loading
- Authentication
- Caching
- Error handling
- Mutating data
- Navigations
- Optimistic updates
- Progressive enhancement
- Server-side rendering
- Static site generation
- Streaming
์ด ๋ชจ๋ ์ต์ ์ ๋ก๋ฉ ์ํ์ค(loading sequence)๋ฅผ ๋ง๋ค๊ธฐ ์ํด ํจ๊ป ๊ณ ๋ คํด์ผํ ์ฌํญ์ด์ฃ .
CRA๋ก ๊ฐ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ์๋ ๊ฐ ์์๋ค์ด ์๋ก ๋ณต์กํ๊ฒ ์ฝํ์๊ณ ์ฌ์ฉ์๋ค์ด ์ต์ํ์ง ์์ ๊น์ด์ ์ ๋ฌธ์ฑ์ด ํ์ํ ๊ฒฝ์ฐ๋ ์์ต๋๋ค. ํด๋น ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ ์ ๋ค์ CRA๊ฐ ํด๊ฒฐํ๊ณ ์ ํ๋ ๋ฌธ์ ๋ค์ ์ง์ ํด๊ฒฐํ๊ธฐ์ ๋์์ ๋ง๋ค๊ฒ ๋์์ฃ .
ํ๋ ์์ํฌ๋ฅผ ๊ถ์ฅํ๋ ์ด์
์ด์ฐ์ ์ฐ CRA์ ๋น๋ ํด(e.g. Vite, Parcel)์ ํตํด ์์ ์ธ๊ธํ ๋ฌธ์ ๋ค์ ํด๊ฒฐํ ์ ์์๊ฒ ์ง๋ง, “์”ํ๊ธฐ๋ ์ฝ์ง ์๋ค๋๊ฒ ์ฌ์ค์ ๋๋ค. CRA๊ฐ ์ฌ๋ฌ ๋น๋ ํด๊ณผ ํตํฉ๋์๋ฏ์ด, ์ ์ ์๊ฒ ์ต์ ์ ๊ฒฝํ์ ์ ๊ณตํ๊ธฐ ์ํด ํด๋น ๊ธฐ๋ฅ๋ค์ ์ง๋ ํด๋ค์ ํตํฉํ๊ธฐ ์ํ ๋ ธ๋ ฅ์ด ํ์ํ์ฃ .
ํด๋น ์นดํ ๊ณ ๋ฆฌ(๋น๋ ํด, ๋๋๋ง, ๋ผ์ฐํ , ๋ฐ์ดํฐ fetching, ์ฝ๋ ์คํ๋ฆฟํ๊ธฐ)์ ํด๋ค์ ํตํฉํ ๊ฒ์ด ๋ฐ๋ก “ํ๋ ์ ์ํฌ”์ ๋๋ค. ๋ฆฌ์กํธ ์์ฒด๋ฅผ ํ๋ ์์ํฌ๋ผ๊ณ ๋ถ๋ฅด์ ๋ค๋ฉด, ํด๋ค์ ํตํฉํด๋์ ํด๋น ์นดํ ๊ณ ๋ฆฌ๋ฅผ “๋ฉํ ํ๋ ์์ํฌ”๋ผ๊ณ ๋ ๋ถ๋ฅผ ์ ์๊ฒ ์ฃ .
ํ๋ ์์ํฌ๋ ๋น๋ ํด๋ค์ด ํด ์ฌ์ฉ์ด ์ฉ์ดํ๋๋ก opinion์ ๊ฐ์ ํ๋ฏ์ด, ๋ ์ข์ ์ ์ ๊ฒฝํ์ ์ํด ์ฑ์ ํน์ ๊ตฌ์กฐ๋ก ๋ง๋ค๋๋ก opinion์ ๊ฐ์ ํ ์ ์์ต๋๋ค.
์์ ๋งํ ์ด์ ๋๋ฌธ์ ์ ํ๋ก์ ํธ๋ฅผ ์์ํ ๊ฒฝ์ฐ Next.js, React Router , Expo๋ฅผ ๊ถ์ฅํฉ๋๋ค. ํ๋ ์์ํฌ๋ค์ CRA๋ฅผ ์ฌ์ฉํ ๋์ ๊ฐ์ ๊ฒฝํ๊ณผ ๋๋ถ์ด ์ ์ ๋ค์ด ์ค์ ํ๋ก๋์ ์ฑ๋ค์ ๋ง๋ค๊ธฐ ์ํด ํ์ํ ํด๊ฒฐ์ฑ ๋ค์ ์ ์ํ์ฃ .
๐ค ์๋ฒ์ฌ์ด๋ ๋๋๋ง์ด ํ์์ธ๊ฐ์?
์์ ๊ถ์ฅํ ํ๋ ์์ํฌ๋ค ๋ชจ๋ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋๋ ๊ธฐ๋ฐ์ ์ฑ์ ๋ง๋ค ์ ์๋ ์ต์ ์ ์ ๊ณตํฉ๋๋ค.
ํน์ ๊ฒฝ์ฐ CSR๊ฐ ํ์ด์ง์ ์ ์ ํ ์ ํ์ผ ์ ์์ง๋ง, ๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๊ทธ๋ ์ง ์์ ๊ฒ๋๋ค. ์ฑ ๋๋ถ๋ถ์ด ํด๋ผ์ด์ธํธ ์ฌ์ด๋๋ผ๊ณ ํด๋ static-site generation (SSG) ๋ server-side rendering (SSR)์ ๋์ ๋ณผ ํ์ด์ง๋ค์ด ์ข ์ข ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด ์ด์ฉ ์ฝ๊ด ํ์ด์ง(Terms of Service page), ๋ํ๋ฉํ ์ด์ ๋ฑ์ด ํด๋น๋์ฃ .
์๋ฒ ๋๋๋ง์ ์ฃผ๋ก ํด๋ผ์ด์ธํธ ์ชฝ์ ์๋ฐ์คํฌ๋ฆฝํธ์ ๋ ๋ณด๋ด๊ณ , ์์ฑ๋ HTML ๋ฌธ์๋ฅผ ๋ณด๋ด๊ธฐ ๋๋ฌธ์ Total Blocking Time (TBD)๋ฅผ ์ค์ฌ First Contentful Paint (FCP)๊ฐ ๋น ๋ฅด๊ฒ ์ด๋ฃจ์ด์ ธ Interaction to Next Paint (INP)๋ฅผ ๊ฐ์์์ผ ์ค๋๋ค.
์ด๋ฌํ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํด ํฌ๋กฌ ํ์ static ์ด๋ server-side ๋๋๋ฅผ ์์ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋๋ ๋ณด๋ค ๊ถ์ฅํฉ๋๋ค. ์๋ฒ๋ฅผ ์ฌ์ฉํ๊ธฐ์ ํธ๋ ์ด๋์คํ๋ค์ด ์๊ณ ๋ชจ๋ ํ์ด์ง๋ฅผ ์ํ ์ต์ ์ ์ ํ์ด ์๋ ์ ์์ต๋๋ค.
ํ์ด์ง๋ฅผ ์๋ฒ์์ ์์ฑํ๊ธฐ ์ํ ์ถ๊ฐ ๋น์ฉ๊ณผ ์๊ฐ์ Time to First Byte (TTFB)๋ฅผ ์ฆ๊ฐ์ํฌ ์ ์์ต๋๋ค. ๊ฐ๊ฐ์ ํธ๋ ์ด๋์คํ๋ฅผ ๊ณ ๋ คํ์ฌ ์ ํฉํ ๋๋๋ง ๋ฐฉ์์ ํ์์ ๋ฐ๋ผ ์ทจ์ฌ์ ํํ์ฌ ์ต์ ํ๋ ์ฑ์ ๋ง๋ค ์ ์์ต๋๋ค.
ํ๋ ์์ํฌ๋ค์ ํ์ด์ง์ ์๋ฒ๋ฅผ ์ฌ์ฉํ ์ต์ ๋ง ์ค๋ฟ, ๊ฐ์ ํ์ง๋ ์์ต๋๋ค.
ํด๋น ๋ฐฉ์์ผ๋ก ์ฑ์ ๊ฐ ํ์ด์ง์ ์ ์ ํ ๋๋๋ง ์ ๋ต์ ์ ํํ ์ ์์ฃ .
๊ทธ๋ผ ์๋ฒ ์ปดํฌ๋ํธ๋?
์์ ์ธ๊ธํ ํ๋ ์์ํฌ ๋ชจ๋ ๋ฆฌ์กํธ ์๋ฒ ์ปดํฌ๋ํธ ์ฌ์ฉ์ ์ง์ํฉ๋๋ค.
์๋ฒ ์ปดํฌ๋ํธ๋ค์ ๋ผ์ฐํ ๊ณผ ๋ฐ์ดํฐ fetching ๋ฌธ์ ๋ค์ ์๋ฒ์์ ํด๊ฒฐํ ์ ์๋๋ก ํ๊ณ , ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ฅผ ์ํ ์ฝ๋ ์คํ๋ฆฟ์ ๋๋ํด์ผํ๋ ๋ฐ์ดํฐ์ ๋ฐ๋ผ ํด์ฃผ๊ธฐ ๋๋ฌธ์ ๋ณด๋ด์ผํ๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ์ค์ด๊ณ loading sequence๋ฅผ ์ต์ ํํฉ๋๋ค.
์๋ฒ ์ปดํฌ๋ํธ๋ ์๋ฒ๊ฐ ํ์ํ์ง ์์ต๋๋ค.CI ์๋ฒ์์ static-site generated app (SSG) ์ฑ์ ์์ฑํ๊ธฐ ์ํด ๋น๋ ํ์ ์ ์คํ๋ ์ ์๊ณ , ์น ์๋ฒ์์ SSR(์๋ฒ ์ฌ์ด๋ ๋๋)๋ ์ฑ์์ ๋ฐํ์์ ์คํ๋ ์ ์์ต๋๋ค.
๋ฆฌ์กํธ ์๋ฒ ์ปดํฌ๋ํธ์ ์ ๋ก-๋ฒ๋ค ์ฌ์ด์ฆ ์๊ฐ ์ ๊ณต์ ๋ฌธ์์์ ์ถ๊ฐ์ ์ธ ๋ด์ฉ์ ์ดํด๋ณด์ค ์ ์์ต๋๋ค.
๐๏ธ ์๋ฒ ๋๋๋ง์ SEO๋ง์ ์ํ ๊ฒ์ ์๋๋๋ค.
์๋ฒ ๋๋๋ง์ด SEO๋ง์ ์ํ ๊ฒ์ด๋ผ๋ ํํ ์คํด๊ฐ ์๋ค.
์๋ฒ ๋๋๋ง์ด SEO๋ฅผ ๊ฐ์ ํ ์๋ค๋ ๊ฒ์ ๋ง์ง๋ง, ์ ์ ๊ฐ ํ๋ฉด์ ์ฝํ ์ธ ๋ฅผ ๋ณด๊ธฐ ์ํด ๋ค์ด๋ก๋ํ๊ณ ํ์ฑํด์ผํ ์๋ฐ์คํฌ๋ฆฝํธ์ ์์ ์ค์ฌ์ ์ฑ๋ฅ์ ๊ฐ์ ํ ์ ์๋ค.
์ด๋ฌํ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ด์ ๋ก ํฌ๋กฌ ํ์ ๊ฐ๋ฐ์๋ค์๊ฒ ์์ ํ ํด๋ผ์ด์ธํธ ์ฌ์ด๋๋ณด๋ค static์ด๋ ์๋ฒ ์ฌ์ด๋ ๋๋๋ง์ ์ฅ๋ ค ํ๋ค.
Reference
Sunsetting Create React App – React
The library for web and native user interfaces
react.dev
'๐ฉ๐ปโ๐ป dev' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋ก์ปฌ ์คํ ๋ฆฌ์ง vs ์ธ์ ์คํ ๋ฆฌ์ง vs ์ฟ ํค (0) | 2025.03.13 |
---|---|
๐ฌ React import ์ Wrapper ํจํด ํ์ฉํด๋ณด๊ธฐ (0) | 2025.03.12 |
[Nextjs] Dynamic metadata tag ์์ฑํ๊ธฐ (Part.2) (1) | 2025.02.26 |
[Nextjs] Dynamic metadata tag ์์ฑํ๊ธฐ (SEO ์งํ 54 โก๏ธ 91) (0) | 2025.02.25 |
Nextjs blurDataUrl dynamicํ๊ฒ ์ ๊ณตํ๊ธฐ (1) | 2025.02.15 |