Frontendμμ uiλ₯Ό λ λλ§νλ λ°©μμ λ€μκ³Ό κ°μ΄ 4κ°μ§λ‘ ν¬κ² ꡬλΆν μ μλ€.
- SSG (Static Site Generators)
- SSR (Server-Side Rendering)
- CSR (Client-Side Rendering)
- ISR (Incremental Static Regeneration) (λλ ISGλΌκ³ λ νλ€)
κ° λ°©μλ§λ€ μ₯λ¨μ μ΄ μκ³ μ§μνλ library/frameworkλ λ€λ₯΄λ€. λν νλ‘μ νΈμ κΈ°νμ΄λ UX designμ λ°λΌμλ μ΄λ€ λ°©μμ μ μ©ν μ§ λ¬λΌμ§ μ μλ€. νλμ μλΉμ€μ νκ°μ§ λ°©λ²λ§μ μ¬μ©νμ§ μμλ λλ€. μ΄λ€ νμ΄μ§λ SSG, λ λ€λ₯Έ νμ΄μ§λ SSRμ μ¬μ©ν μλ μλ€.
본격μ μΌλ‘ λ λλ§μ μ΄μΌκΈ°νκΈ° μ μ, SPA(Single page application)μ λν΄μ μμ보μ. SPAλ 2010λ
μ΄λ°, νλ‘ νΈμλ κ°λ°μλ€μ΄ κ° νμ΄μ§μ λν΄μ κΈ°μ‘΄ HTML/CSS/JS μ‘°ν©μ μ¬μ©νλ λμ μ 체 μ± μ»¨ν
μΈ νλ¦μ javascriptλ§μΌλ‘ ꡬννκΈ°λ₯Ό μνμ¬ νμνκ² λμλ€. λ°λΌμ μλ‘ λ€λ₯Έ CSSμ javascript 리μμ€λ₯Ό λ‘λνλ μ¬λ¬ HTMLμ 보μ νκ³ , browserκ° λ§ν¬λ₯Ό μ¬μ©ν΄ νμ΄μ§ μ¬μ΄λ₯Ό νμνλ λμ μ, SPAλ₯Ό μ΄μ©νμ¬ μ»¨ν
μΈ κ° μλ λ¨μΌ HTMLνμ΄μ§λ₯Ό μ¬μ©νμ¬ νλ μ΄μμ javascript νμΌμ λ‘λν μ μκ² λ κ²μ΄λ€. SPAμ λ±μ₯μΌλ‘ λ€μκ³Ό κ°μ μ΄μ μ΄ μκΈ°κΈ°λ νλ€.
- μνλ λ°©μμΌλ‘μ μ½λ μ€κ³/λ°°ν¬λ₯Ό λ¨μΌ ν¨ν€μ§λ‘ ꡬμΆ
applicationμ΄ νλ²μ λͺ¨λ λ‘λλλ―λ‘ νμ λ°interactionμ μΌλ°μ μΌλ‘ μΆκ°μ μΈ λ¦¬μμ€ λ‘λ©μ΄ νμνμ§ μμ λΉ λ₯Έ μλSPAλapiλ₯Ό μ¬μ©ν΄contentλ₯ΌqueryνκΈ° λλ¬Έμdataμuiκ°μdecouplingμΌλ‘ κ΄μ¬μ¬ λΆλ¦¬
νμ§λ§ λμμ λ€μμ κ°μ νκ³μ λ λ°μνμλ€.
app bundleμ μ 체 ν¬κΈ°κ° μλΉν μ»€μ Έ μ΄κΈ°λ‘λ©μλκ° λλ €μ§ -> μ±λ₯λΆλ΄μΌλ‘ λ°μ - νμ΄μ§ νμμ μνκ΄λ¦¬κ° 볡μ‘ν΄μ§μ μλ κ°λ₯μ±
- κΉλ€λ‘μ΄
SEOμ΅μ ν *
νΉν SEOκ° μ μ μ€μν μν μ νκ² λλ©΄μ SPAμ νκ³μ μ€ νλμΈ SEO μ΅μ νλ₯Ό 컀λ²νκΈ° μν΄ μ¬λ¬κ°μ§ rendering λ°©μμ΄ λ±μ₯νκ² λμλ€.
SSG (Static Site Generators)
μ΄κΈ° SSGλ 2008λ
λΆν° λ±μ₯νμΌλ©° CMS(Content Management System) κΈ°λ°μ applicationμ λν μλ‘μ΄ λμμ μ μνλ €κ³ νλ€. μ€μ λ‘ λ§μ μΉμ¬μ΄νΈμμλ CMS(ex Wordpress)λ‘ νΈμ§λ μ½ν
μΈ λ₯Ό λͺ¨λ μ¬μ©μμκ² servingνλ€. μ½ν
μΈ κ° runtimeμ μμ±λλ―λ‘ CMSμ λ³κ²½ μ¬νμ μ¬μ©μμκ² μ§μ λ°°ν¬ν μ μλ€. μ΅κ·Όμλ react/vue κΈ°λ°μ Gatsbyκ° λνμ μΈ SSG frameworkλ‘ μ¬μ©λκ³ μλ€.
Nextjsλ κΈ°λ³Έμ μΌλ‘ SSGλ₯Ό pre-renderingμ΄λΌκ³ μκ°νλ€. κ° νμ΄μ§λ₯Ό 미리 HTMLμ λ¬Έμλ‘ μμ±νμ¬ κ°μ§κ³ μλ κ²μ΄λ€. client λ¨μμ μΆκ°λ λλ§μ΄ λ°μνμ§ μμΌλ©° Nextjsμ renderingμμ defaultκ°μΌλ‘ μ μ©λλ€.
SPAλμ SSGλ₯Ό μ¬μ©ν κ²½μ° λ€μκ³Ό κ°μ μ΄μ μ κ°μ§λ€.
- λ λμ
SEO: μ¬λ¬HTMLνμ΄μ§λ‘ ꡬμ±λμ΄ μμΌλ―λ‘crawlingμ΄ λ μ½κ³ μ½ν μΈ μindexκ° μ μμ±λλ€ - μ±λ₯ ν₯μ: μ΅μ
SSGλꡬμλ μμ²ν νμ΄μ§λ₯Ό μ€ννλ λ° νμνJS/CSSμ½λλ§ ν¬ν¨λμ΄ μμΌλ©° μ¬μ©μκ° μΉ μ¬μ΄νΈλ₯Ό νμνλ©΄ μΆκ° μ½λλ₯Όloadνλ€ - λ€μ€ μμ€ μ½ν
μΈ :
SSGλheadless CMS(Contentful,Strapi), λ‘컬markupνμΌκ°μ λ€μ€ μ½ν μΈ μμ€ ν΅ν©μ μ 곡νλ€
νμ§λ§ λ¨μ λ μ‘΄μ¬νλ©° λ€μκ³Ό κ°λ€.
- μ¬μ©μ λ§μΆ€ν μ½ν μΈ : λͺ¨λ μ¬μ©μκ° λμΌνλ€κ³ μκ°νκ³ κ°μ£Όνκ² λλ€. κ·Έλ μ§ μμΌλ©΄ κ° μ¬μ©μμ λν΄ μ μ μ½ν μΈ λ₯Ό λ§λ€μ΄μ€μΌ νλ©° μ©λμ΄λ 보μ λ±μ λ¬Έμ κ° μκΈ΄λ€
learning curve:Gatsbyκ°μ κ²½μ°reactκΈ°λ°μμλ λΆκ΅¬νκ³ μ½ν μΈ μΏΌλ¦¬μgraphQLμ μ¬μ©νλ―λ‘ μ΄λ₯Ό μμΈν μ΄ν΄λ³΄μμΌνλ€- μ¦κ°μ μΈ λ°μ μ΄λ €μ: μ΅μ μνμ μΉ μ»¨ν
μΈ λ₯Ό 보μ¬μ£ΌκΈ° μν΄μλ λ°°ν¬λ₯Ό μ§νν΄μΌ νκ³ κ·Έλ§νΌμ μκ°μ μμνκ² λλ€. λ§μ½
CI/CDμ 10λΆμ΄ κ±Έλ¦°λ€λ©΄ μ¬μ©μλ 10λΆ νμ νμ¬μ 컨ν μΈ λ₯Ό λ³΄κ² λ κ²μ΄λ€
SSR (Server Side Rendering)
renderingμμ μ΅μ νΈλ λλ SSRμΌ κ²μ΄λ€. μ¬μ€ κ·Έλμ SSRμ μ€λ«λμ μ¬μ©λμ΄ μλ€.
<div>Hello <?php echo 'world'; ?></div> <!-- μ΄λ₯Ό μ½λ κΈ°μ΅νλκ° ? -->SSRμ serverλ¨μμ HTML 컨ν
μΈ λ₯Ό rendering νλκ²μ μλ―Ένλ€. JEE, ASP.NET, PHPλ±μ μΌλ°μ μΈ MVC frameworkλ SSRμ κ°λ₯νκ²νλ template κΈ°λ°μ engineμ κ°μ§κ³ μλ€.
μ΄λ¬ν SSRμ νκ°μ§ μ νμ¬νμ΄ μλ€. clientλ¨μμμ interactionμ serverμμ μ²λ¦¬ν μ μμΌλ©°, λΈλΌμ°μ μ νμλλ 컨ν
μΈ λ μ΄κΈ° serverμμ μμ±λ 컨ν
μΈ λ‘ μ νλλ€λ κ²μ΄λ€.
κ·Έ λ€μ λμλ€μ javascript νμΌμ μμ±λμ΄μΌ νλ€. νμ§λ§ Nodejsμ λ±μ₯μΌλ‘ μ΄μ λ serverλ¨κ³Ό clientλ¨ λͺ¨λ javascriptλ₯Ό μ€νν μ μκ² λμκ³ , rendering 곡μ κ° κ°λ₯ν΄μ‘λ€. μ¦, Nextjs, Nuxt λ±μ frameworkκ° μ 곡νλκ²μ javascriptλ₯Ό νμ©νμ¬ serverλ¨μ μ΄κΈ° λ‘λμ clientλ¨μ interactionμ ν΅ν©νμ¬ renderingμ 곡μ νλ κ²μ΄λΌκ³ ν μ μλ€.
SSRμ λ€μκ³Ό κ°μ μ₯λ¨μ μ κ°μ§λ€.
μ₯μ
SEOμ μ 리: κ²μμμ§indexingμ΄λsocial mediaμ 곡μ ν μ μλ μ 보λ₯Ό κ°μ§κ³ μλ€- λΉ λ₯Έ μ±λ₯: μΌλ°μ μΈ
SPAλ³΄λ€ λ¦¬μμ€ λ‘λμ λ λμ μ±λ₯μ κ°μ§λ€ - API
hostingκ°λ₯:SSRμ΄serverμμ μ€νλλ―λ‘SSRμ μ¬μ©νμ¬APIλ₯Ό κ°λ°ν μλ μλ€
λ¨μ
serverκ° νμ:SSRμ΄ μλνλ €λ©΄ λΉμ°νserverκ° νμνλ€. μ΄λ μΆκ°μ μΈ λ¦¬μμ€ λΉμ©μΌλ‘ κ°μ£Όλλ€learning curve:clientλ¨μμλ§ μμ νλκ²μ λΉν΄ λ§μ μλ‘μ΄ κ°λ κ³Ό λ΄μ©μ΄ λ§μΌλ―λ‘ μ¬μ νμ΅μ΄ νμνλ€clientκ³Ό λ€λ₯Έ λμ: μλ₯Όλ€μ΄windowκ°μ²΄λserverμμλ μ¬μ©ν μ μμΌλ―λ‘ μ΄λ¬ν μ°¨μ΄λ₯Ό νμΈνμ¬ μ 체μ μΌλ‘ μ λμνλμ§ ν΅ν©μ μΈ ν μ€νΈκ° νμνλ€
CSR (Client Side Rendering)
CSRμμλ νμ΄μ§μ κΈ°λ³Έ HTML 컨ν
μ΄λλ§ μλ²μ μν΄ renderingλλ€. κ·Έλ¦¬κ³ νμ΄μ§μ 컨ν
μΈ λ₯Ό νμνκΈ° μν΄ νμν λ‘μ§μ΄λ data fetch, routing λ±μ μ€νλλ javascript μ½λμ μν΄ μ²λ¦¬λλ€. SPAμ μ±μ₯κ³Ό ν¨κ» CSRλ μμ°μ€λ½κ² μΈκΈ°λ₯Ό μ»μλ€. frontend κ°λ°μλ€μκ² κ°μ₯ μΉμνκ³ λ κΈ°λ³Έμ μΌλ‘ μ¬μ©νλ λ°©μμΌκ²μ΄λ€. κ°λ¨ν μ₯λ¨μ λ§ μ§κ³ λμ΄κ°λλ‘ νκ² λ€.
μ₯μ
- λ°μ΄λ μ¬μ©μ κ²½ν: νμ΄μ§ μλ‘κ³ μΉ¨ μμ΄ νμμ μ§μνκ³ , λ°μ΄λ μ¬μ©μ κ²½νμ μ 곡νλ
SPAλ₯Ό κ°λ₯νκ² νλ©°, νμ΄μ§κ°routingμ΄ μΌλ°μ μΌλ‘ λΉ λ₯΄κΈ° λλ¬Έμ λ°μμ±μ΄ μ’μ보μΈλ€ - κ΄μ¬μ¬μ λΆλ¦¬:
clientμ½λμserverμ½λλ₯Ό λͺ ννκ² λΆλ¦¬ν μ μλ€
λ¨μ
SEOμ΅μ νκ° μ΄λ €μ:CSRμ κ²½μ° ν°payloadμnetworkμμ²μΌλ‘ μλ―Έμλ μ½ν μΈ κ°crawlerκ°indexλ₯Ό μμ±ν λ§νΌ λΉ λ₯΄κ²renderingλμ§ μμ μ μμΌλ―λ‘SEOμ΅μ νμ μ΄λ €μμ΄ μ‘΄μ¬νλ€- λλ¦° μλ΅ μκ°:
serverλ‘μ μλ³΅μ΄ μκΈ° λλ¬Έμ μλ΅μκ°μ΄ λ리λ€. μΉνμ΄μ§κ°clientμΈ‘μμ μ½ν μΈ λ₯Ό μ²μμΌλ‘renderingνλ €λ©΄javascriptκ° λ¨Όμ loadλκ³ , μ²λ¦¬κ° μμλ λκΉμ§ κΈ°λ€λ €μΌνλ€. λνapiνΈμΆλ‘ λ°μ΄ν°λ₯Ό κ°μ Έμ¬ κ²½μ° μλ΅μκ°μ΄ 걸릴 μ μλ€
ISR (Incremental Static Regeneration)
ISRμ κ°λ¨ν λ§ν΄, μ μ μμ±(static generation)μΌλ‘ 미리 λ§λ€μ΄λμ νμ΄μ§λ μ
λ°μ΄νΈκ° κ°λ₯νλ€λ κ²μ΄λ€. κ·Έλ κ² λλ©΄ μ μ μμ±μ μ₯μ μ κ°μ Έκ°λ©΄μ λ¨μ μ 보μν μ μλ€. ISRμ μΌμ μ£ΌκΈ°λ§λ€ μ
λ°μ΄νΈλ λ°μ΄ν°λ‘ μ μ νμ΄μ§λ₯Ό λ€μ μμ±ν΄μ£Όλ λ°©μμ΄λ€.
ꡬνλ°©μμ nextjs κΈ°μ€μΌλ‘ 보μμλ, getStaticPropsμ revalidateλ₯Ό μΆκ°νκ³ κ·Έ κ°μΌλ‘ κ°±μ μ£ΌκΈ°(μ΄λ¨μ)λ₯Ό μ λ¬ν΄μ£Όλ©΄ λλ€.
export async function getStaticProps(context) {
const data = await fetch(api);
return {
props: { data },
revalidate: 20, // (μλ²μκ° κΈ°μ€ 20μ΄λ§λ€ dataμ μ
λ°μ΄νΈλ₯Ό κ²μ¬)
};
}revalidate timeμ μ§μ νκΈ° λλ¬Έμ, μ
λ°μ΄νΈλ μ 보μ μμ΄ revalidate κ°λ§νΌμ λλ μ΄κ° λ°μνκ² λλ€. μ¦, μ€μ λ‘ λ°μ΄ν°κ° μ
λ°μ΄νΈ λμλλΌλ μΌμ μκ°λμμ μ
λ°μ΄νΈλμ§ μμ νμμλ λ΄μ©μ μ¬μ©μλ€μ΄ λ³΄κ² λλ€λ κ²μ΄λ€. λν μ€μ μ
λ°μ΄νΈ μ¬λΆμλ κ΄κ³μμ΄ revalidateκ° μ΄λ£¨μ΄μ§κΈ° λλ¬Έμ κ·Έλ§νΌμ νλ‘ νΈμλ 리μμ€κ° μ΄μ©λλ€λ λ¨μ μ΄ μ‘΄μ¬νλ€. μ΄λ¬ν λ¨μ μ 극볡ν μ μλ μλ‘μ΄ κΈ°λ₯μ΄ λ°λ‘ on-demand revalidateμ΄λ€.
on-demand revalidateλ°©μμ nextjs 12.2.0 λΆν° μ§μνκ³ , μ§μ ν interval time μ΄μΈμλ μ
λ°μ΄νΈ μ΄λ²€νΈλ₯Ό μ λ¬ν΄μ£Όμ΄ revalidateλ₯Ό μν€λ λ°©μμ΄λ€. apiλ₯Ό μ΄μ΄λ λ€μ μλμ²λΌ ꡬνμ΄ κ°λ₯νλ€. 곡μλ¬Έμμ°Έμ‘°
export default async function handler(req, res) {
// Check for secret to confirm this is a valid request
if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
return res.status(401).json({ message: 'Invalid token' })
}
try {
// this should be the actual path not a rewritten path
// e.g. for "/blog/[slug]" this should be "/blog/post-1"
await res.revalidate('/path-to-revalidate')
return res.json({ revalidated: true })
} catch (err) {
// If there was an error, Next.js will continue
// to show the last successfully generated page
return res.status(500).send('Error revalidating')
}
}- https://en.wikipedia.org/wiki/Content_management_system
- https://levelup.gitconnected.com/spa-ssg-ssr-and-jamstack-a-front-end-acronyms-guide-6add9543f24d
- https://www.patterns.dev/react/client-side-rendering/
- https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration
- https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration#using-on-demand-revalidation