์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR)๊ณผ ๋ฆฌ์กํธ ์ปดํฌ๋ํธ ์ต์ ํ ์ ๋ต
ํ๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ด๊ธฐ ๋ก๋ฉ ์๋์ ๊ฒ์ ์์ง ์ต์ ํ(SEO)๊ฐ ๋งค์ฐ ์ค์ํ ์์๋ก ๋ถ๊ฐ๋๊ณ ์์ต๋๋ค. ํนํ, ๋ฆฌ์กํธ ๊ธฐ๋ฐ์ SPA(Single Page Application)๋ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ ๋๋ง(CSR)์ ์ฃผ๋ก ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์, ์ด๊ธฐ ํ์ด์ง ๋ก๋ฉ ์ ๋น ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ฑฐ๋ ๊ฒ์ ์์ง ํฌ๋กค๋ฌ๊ฐ ์ฝํ ์ธ ๋ฅผ ์ ๋๋ก ์ธ์ํ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Next.js์ ๊ฐ์ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR) ํ๋ ์์ํฌ๋ฅผ ํ์ฉํ๋ฉด, ์๋ฒ์์ ๋ฏธ๋ฆฌ HTML์ ์์ฑํ์ฌ ํด๋ผ์ด์ธํธ์ ์ ๋ฌํ ์ ์์ผ๋ฉฐ, ์ด๋ก ์ธํด ๋น ๋ฅธ ์ด๊ธฐ ๋ ๋๋ง๊ณผ SEO ์ต์ ํ๋ฅผ ๋์์ ๋ฌ์ฑํ ์ ์์ต๋๋ค.
SSR์ ๊ฐ๋ ๊ณผ ํ์์ฑ
์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ ์ฌ์ฉ์๊ฐ ์น ํ์ด์ง์ ์ ์ํ ๋, ์๋ฒ์์ ๋ฏธ๋ฆฌ ์์ฑ๋ HTML ์ฝํ ์ธ ๋ฅผ ์์ฑํ์ฌ ์ ์กํ๋ ๋ฐฉ์์ ๋๋ค. ์ด์ ๋ฌ๋ฆฌ CSR์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ฒ๋ค์ด ๋ก๋๋ ํ ๋ธ๋ผ์ฐ์ ์์ ๋์ ์ผ๋ก ๋ ๋๋ง๋๋ฏ๋ก, ์ด๊ธฐ ๋ก๋ฉ ์๊ฐ์ด ๊ธธ์ด์ง๊ณ SEO ์ธก๋ฉด์์ ๋ถ๋ฆฌํ ์ ์์ต๋๋ค. SSR์ ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ ์ ๊ณตํฉ๋๋ค.
- ๋น ๋ฅธ ์ด๊ธฐ ๋ ๋๋ง: ์๋ฒ์์ ์ด๋ฏธ ์์ฑ๋ HTML์ ์ ๋ฌํ๊ธฐ ๋๋ฌธ์, ์ฌ์ฉ์๋ ํ์ด์ง์ ๋น ๋ฅด๊ฒ ์ ๊ทผํ ์ ์์ต๋๋ค.
- SEO ์ต์ ํ: ๊ฒ์ ์์ง ํฌ๋กค๋ฌ๊ฐ ์๋ฒ์์ ๋ ๋๋ง๋ HTML์ ๋ฐ๋ก ์ธ์ํ ์ ์์ด, ๊ฒ์ ์์์ ๋ ธ์ถ์ ์ ๋ฆฌํฉ๋๋ค.
- ์์ ๋ฏธ๋์ด ๋ฏธ๋ฆฌ๋ณด๊ธฐ: ๋งํฌ๋ฅผ ๊ณต์ ํ ๋, ๋ฉํ ํ๊ทธ ๋ฑ ํ์ํ ์ ๋ณด๊ฐ ํฌํจ๋ HTML์ด ์ ๊ณต๋์ด ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ด๋ฏธ์ง๋ ์ค๋ช ์ด ์ ๋๋ก ํ์๋ฉ๋๋ค.
Next.js๋ฅผ ํ์ฉํ SSR ์ ์ฉ
Next.js๋ ๋ฆฌ์กํธ ๊ธฐ๋ฐ์ SSR ํ๋ ์์ํฌ๋ก, ๊ฐ๋จํ ์ค์ ๋ง์ผ๋ก SSR ๊ธฐ๋ฅ์ ํ์ฉํ ์ ์์ต๋๋ค. Next.js๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ด์ง๋ณ๋ก ๋ฐ์ดํฐ ํ์นญ๊ณผ ๋ ๋๋ง์ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ, ํ์ผ ๊ธฐ๋ฐ ๋ผ์ฐํ ๊ณผ ์ฝ๋ ์คํ๋ฆฌํ ๋ฑ์ ๊ธฐ๋ฅ์ ํตํด ๊ฐ๋ฐ ์์ฐ์ฑ๊ณผ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ๋์์ ๋ฌ์ฑํ ์ ์์ต๋๋ค.
Next.js ํ๋ก์ ํธ ๊ตฌ์ฑ ๋ฐ ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
Next.js ํ๋ก์ ํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก pages ํด๋ ๋ด์ ์กด์ฌํ๋ ๊ฐ ํ์ผ์ ํ๋์ ๋ผ์ฐํธ๋ก ์ธ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, pages/index.tsx ํ์ผ์ ํํ์ด์ง ์ญํ ์ ํ๊ณ , ๋ค๋ฅธ ํ์ด์ง๋ค๋ ๋์ผํ ๋ฐฉ์์ผ๋ก ์์ฑํ ์ ์์ต๋๋ค.
์๋๋ Next.js๋ฅผ ์ด์ฉํ ๊ฐ๋จํ SSR ํ์ด์ง ์์ ์ ๋๋ค.
// pages/index.tsx
import React from 'react';
import { GetServerSideProps, NextPage } from 'next';
interface HomeProps {
data: string;
}
const Home: NextPage<HomeProps> = ({ data }) => {
return (
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
<h2>Next.js SSR ์์ </h2>
<p>์๋ฒ์์ ๋ฏธ๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ํจ์นญํ์ฌ ์ ๋ฌ๋ฐ์ ๋ด์ฉ: {data}</p>
</div>
);
};
export const getServerSideProps: GetServerSideProps = async (context) => {
// ์ค์ API ํธ์ถ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ ๋ฑ ๋ณต์กํ ๋ก์ง์ด ๋ค์ด๊ฐ ์ ์์
const data = '์๋
ํ์ธ์, SSR ํ๊ฒฝ์์ ๋ ๋๋ง๋ ํ์ด์ง์
๋๋ค.';
return {
props: { data },
};
};
export default Home;
์ ์์ ์์ getServerSideProps ํจ์๋ ํ์ด์ง๊ฐ ์์ฒญ๋ ๋๋ง๋ค ์๋ฒ์์ ํธ์ถ๋๋ฉฐ, ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ํจ์นญํ ํ ์ปดํฌ๋ํธ์ props๋ก ์ ๋ฌํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ฌ์ฉ์๋ ํ์ด์ง ์ ์ ์ ๋ฏธ๋ฆฌ ์ค๋น๋ ๋ฐ์ดํฐ๋ฅผ ์ฆ์ ํ์ธํ ์ ์์ต๋๋ค.
SSR ํ๊ฒฝ์์์ ์ปดํฌ๋ํธ ์ค๊ณ ์ ๋ต
SSR ํ๊ฒฝ์์ ์ปดํฌ๋ํธ๋ฅผ ์ค๊ณํ ๋๋ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ๋ฐ์ดํฐ ์ ๋ฌ๊ณผ ์ํ ๊ด๋ฆฌ์ ์ฃผ์ํด์ผ ํฉ๋๋ค. ์๋๋ ๋ช ๊ฐ์ง ์ฃผ์ ์ ๋ต์ ๋๋ค.
1. ๋ฐ์ดํฐ ํ์นญ ์ต์ ํ
- ์๋ฒ์ ํด๋ผ์ด์ธํธ ๋ถ๋ฆฌ: SSR ์ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ํ์นญํ์ฌ ๋ ๋๋งํ ๋์ ํด๋ผ์ด์ธํธ์์ ์ถ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ ๋์ ์ฐจ์ด๋ฅผ ๋ช ํํ ๊ตฌ๋ถํฉ๋๋ค. Next.js์์๋ getServerSideProps ๋๋ getStaticProps๋ฅผ ํตํด ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๋ก๋ํ๊ณ , ํด๋ผ์ด์ธํธ์์๋ SWR(React Hooks ๊ธฐ๋ฐ ๋ฐ์ดํฐ ํ์นญ ๋ผ์ด๋ธ๋ฌ๋ฆฌ)์ด๋ React Query๋ฅผ ํ์ฉํ์ฌ ์ ๋ฐ์ดํธ๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ์บ์ฑ ์ ๋ต: ๋ฐ์ดํฐ ํ์นญ ์ ์บ์ฑ ์ ๋ต์ ๋์ ํ๋ฉด, ๋ฐ๋ณต๋๋ ์์ฒญ์ ๋ํด ์๋ฒ ๋ถํ๋ฅผ ์ค์ด๊ณ ์๋ต ์๋๋ฅผ ํฅ์์ํฌ ์ ์์ต๋๋ค. CDN, ์๋ฒ ์บ์, ํน์ ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ์บ์ฑ์ ์ ์ ํ ํ์ฉํฉ๋๋ค.
2. ์ปดํฌ๋ํธ ์ต์ ํ
- ์ฝ๋ ์คํ๋ฆฌํ : Next.js๋ ์๋์ผ๋ก ํ์ด์ง๋ณ ์ฝ๋ ์คํ๋ฆฌํ ์ ์ง์ํ์ง๋ง, ํ์์ ๋ฐ๋ผ ๋์ ์ํฌํธ(dynamic import)๋ฅผ ํ์ฉํ์ฌ ๋น๋๊ธฐ ๋ก๋ฉ์ ์ต์ ํํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ด๊ธฐ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ , ์ฌ์ฉ์๊ฐ ํ์ํ ์์ ์๋ง ์ถ๊ฐ ์ฝ๋๋ฅผ ๋ก๋ํ ์ ์์ต๋๋ค.
- ์ปดํฌ๋ํธ ์บ์ฑ: React.memo, useMemo, useCallback ๋ฑ์ ํ์ฉํ์ฌ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ์ต์ํํ๊ณ , SSR๊ณผ ํด๋ผ์ด์ธํธ ์ฌ์ด๋์์ ์ผ๊ด๋ ๊ฒฐ๊ณผ๋ฅผ ์ ์งํ ์ ์๋๋ก ํฉ๋๋ค.
์๋๋ ๋์ ์ํฌํธ๋ฅผ ํ์ฉํ ์ปดํฌ๋ํธ ๋ก๋ฉ ์์ ์ ๋๋ค.
// components/DynamicComponent.tsx
import React from 'react';
const DynamicComponent: React.FC = () => {
return (
<div style={{ padding: '10px', backgroundColor: '#f0f0f0', borderRadius: '8px' }}>
<h3>๋์ ์ํฌํธ ์ปดํฌ๋ํธ</h3>
<p>์ด ์ปดํฌ๋ํธ๋ ํ์ํ ๋๋ง ๋ก๋๋ฉ๋๋ค.</p>
</div>
);
};
export default DynamicComponent;
// pages/feature.tsx
import React, { Suspense, lazy } from 'react';
import { NextPage } from 'next';
const DynamicComponent = lazy(() => import('../components/DynamicComponent'));
const FeaturePage: NextPage = () => {
return (
<div style={{ padding: '20px' }}>
<h2>ํน์ ๊ธฐ๋ฅ ํ์ด์ง</h2>
<Suspense fallback={<div>์ปดํฌ๋ํธ๋ฅผ ๋ถ๋ฌ์ค๋ ์ค์
๋๋ค...</div>}>
<DynamicComponent />
</Suspense>
</div>
);
};
export default FeaturePage;
์ ์์ ๋ DynamicComponent๋ฅผ ๋์ ์ํฌํธ๋ฅผ ํตํด ํ์ํ ์์ ์๋ง ๋ก๋ํ๋๋ก ๊ตฌ์ฑํ์์ต๋๋ค. Suspense ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํ์ฌ ๋ก๋ฉ ์ํ๋ฅผ ๊ด๋ฆฌํจ์ผ๋ก์จ, ์ฌ์ฉ์์๊ฒ ์ํํ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค.
3. SEO ์ต์ ํ ๊ณ ๋ ค
- ๋ฉํ ํ๊ทธ ๊ด๋ฆฌ: Next.js์ Head ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํ์ฌ ๊ฐ ํ์ด์ง๋ณ๋ก ์ ์ ํ ๋ฉํ ํ๊ทธ(title, description, og ํ๊ทธ ๋ฑ)๋ฅผ ์ค์ ํฉ๋๋ค. ์ด๋ฅผ ํตํด ๊ฒ์ ์์ง์ด ํ์ด์ง์ ๋ด์ฉ์ ์ ํํ ์ธ์ํ ์ ์์ต๋๋ค.
- ์ ์ ์ฌ์ดํธ ์์ฑ(SSG) ํ์ฉ: ์ฝํ ์ธ ๋ณ๊ฒฝ์ด ์ฆ์ง ์์ ๊ฒฝ์ฐ, Next.js์ getStaticProps๋ฅผ ํตํด ์ ์ ํ์ด์ง๋ฅผ ์์ฑํ๋ฉด ๋์ฑ ๋น ๋ฅธ ์๋ต ์๋์ SEO ์ต์ ํ๋ฅผ ๋ฌ์ฑํ ์ ์์ต๋๋ค.
- ์ ๊ทผ์ฑ ๋ฐ ์ฑ๋ฅ ๊ฐ์ : ์๋ฒ์์ ๋ ๋๋ง๋ ํ์ด์ง๋ ์ด๊ธฐ HTML์ด ์์ฑ๋์ด ์์ด, ์คํฌ๋ฆฐ ๋ฆฌ๋๋ SEO ํฌ๋กค๋ฌ๊ฐ ์ฝํ ์ธ ๋ฅผ ์ฝ๊ฒ ํ์ ํ ์ ์์ต๋๋ค. ๋ํ, ๋ถํ์ํ ์๋ฐ์คํฌ๋ฆฝํธ ์คํ์ ์ค์ฌ ํ์ด์ง ๋ก๋ฉ ์ฑ๋ฅ์ ๊ฐ์ ํฉ๋๋ค.
์ค์ ํ๋ก์ ํธ ์ ์ฉ ์ฌ๋ก ๋ฐ ํ์ ์ ๋ต
Next.js์ SSR์ ํ์ฉํ ํ๋ก์ ํธ์์๋ ๋์์ธ ์์คํ , API ์๋ฒ, ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ฑ ์ฌ๋ฌ ์์๊ฐ ๋ณตํฉ์ ์ผ๋ก ์๋ํฉ๋๋ค. ์ด๋ ํ ๋ด ํ์ ์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- API ์ค๊ณ์ ๋ฐ์ดํฐ ํ์นญ ํ์ : ํ๋ก ํธ์๋์ ๋ฐฑ์๋ ํ์ด ํ์ ํ์ฌ RESTful API ๋๋ GraphQL API๋ฅผ ์ค๊ณํ๊ณ , ๋ฐ์ดํฐ ํ์นญ ์ ๋ต์ ์ฌ์ ์ ๋ ผ์ํฉ๋๋ค.
- ๋์์ธ ์์คํ ๊ณผ ์ปดํฌ๋ํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ: Storybook๊ณผ ๊ฐ์ ๋๊ตฌ๋ฅผ ํ์ฉํ์ฌ, ์ปดํฌ๋ํธ๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ๊ฐ๋ฐํ๊ณ ๋ฌธ์ํํ ํ, Next.js ํ๋ก์ ํธ์ ํตํฉํฉ๋๋ค.
- CI/CD ํ์ดํ๋ผ์ธ ๊ตฌ์ถ: ์๋ํ๋ ํ ์คํธ์ ์ ์ ๋ถ์, ๋น๋ ๋ฐ ๋ฐฐํฌ ๊ณผ์ ์ ํตํด, SSR ํ์ด์ง์ ์์ ์ฑ๊ณผ ์ฑ๋ฅ์ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๊ณ ๊ฐ์ ํฉ๋๋ค.
๊ฒฐ๋ก
Next.js์ ๊ฐ์ SSR ํ๋ ์์ํฌ๋ฅผ ํ์ฉํ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ ์ด๊ธฐ ๋ก๋ฉ ์๋ ๊ฐ์ ๊ณผ SEO ์ต์ ํ์ ์์ด ๊ฐ๋ ฅํ ๋๊ตฌ์ ๋๋ค. SSR ํ๊ฒฝ์์ ์ปดํฌ๋ํธ๋ฅผ ์ค๊ณํ ๋๋ ๋ฐ์ดํฐ ํ์นญ, ์ฝ๋ ์คํ๋ฆฌํ , ์บ์ฑ ์ ๋ต ๋ฑ ๋ค์ํ ์ต์ ํ ๊ธฐ๋ฒ์ ์ ์ ํ ๋์ ํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ทน๋ํํ ์ ์์ต๋๋ค. ๋ํ, ๋ฉํ ํ๊ทธ ์ค์ ๋ฐ ์ ์ ์ฌ์ดํธ ์์ฑ์ ํตํ SEO ๊ฐ์ ์ ๊ฒ์ ์์ง์์์ ๋ ธ์ถ ํจ๊ณผ๋ฅผ ๋์ด๋ฉฐ, ์ ๋ฐ์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ํ์ง์ ํฅ์์ํต๋๋ค.
์์ผ๋ก ๋ฆฌ์กํธ ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ ์ SSR ํ๊ฒฝ์ ์ ๊ทน ๊ณ ๋ คํ๊ณ , Next.js์ ๋ค์ํ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ์์ ์ ์ด๊ณ ํ์ฅ์ฑ ์๋ ํ๋ก์ ํธ๋ฅผ ๊ตฌํํ์๊ธธ ๋ฐ๋๋๋ค. ์ด๋ฅผ ํตํด ๋น ๋ฅธ ์ด๊ธฐ ๋ ๋๋ง, ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๊ด๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ์ฐ์ํ SEO ์ต์ ํ๋ฅผ ๋์์ ๋ฌ์ฑํ์ฌ, ์ฌ์ฉ์์ ๊ฒ์ ์์ง ๋ชจ๋์๊ฒ ๋ง์กฑ์ค๋ฌ์ด ์น ์๋น์ค๋ฅผ ์ ๊ณตํ ์ ์์ ๊ฒ์ ๋๋ค.
๋๊ธ