Next.js: ์ •์  ์ƒ์„ฑ / SSG ๊ฐœ์„ 

์— ๋งŒ๋“  2019๋…„ 11์›” 25์ผ  ยท  250์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: vercel/next.js

์š”์•ฝ

ํŽ˜์ด์ง€๋ณ„๋กœ ์ •์  ์ƒ์„ฑ๊ณผ ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•˜์—ฌ Next.js๊ฐ€ ์™„์ „ํžˆ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ๊ฐ€ ๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

  • ๋‘ ๊ฐœ์˜ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋‹น ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐฉ๋ฒ•

    • getStaticProps - next build ์‹œ๊ฐ„์— SSG(์ •์  ์ƒ์„ฑ)๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

    • getServerSideProps - ์˜จ๋””๋งจ๋“œ๋กœ ๋ Œ๋”๋งํ•˜๋Š” SSR(์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง)์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

  • ๋™์  ์†Œ์Šค์—์„œ ๊ฒฝ๋กœ ์ง‘ํ•ฉ์„ ์ •์ ์œผ๋กœ ์ƒ์„ฑ(SSG)ํ•˜๋Š” ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•

    • getStaticPaths - ์ •์  ์ƒ์„ฑ(SSG)์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋™์  ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก ๋ฐ˜ํ™˜

์ด RFC๋Š” API ์ถ”๊ฐ€์— ๋Œ€ํ•ด ๋…์ ์ ์œผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์€ ์ด์ „ ๋ฒ„์ „๊ณผ ์™„์ „ํžˆ ํ˜ธํ™˜๋˜๋ฉฐ ์ ์ง„์ ์œผ๋กœ ์ฑ„ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด RFC๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฐฐ๊ฒฝ

์›น ์‚ฌ์ดํŠธ ๋˜๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•  ๋•Œ ์ผ๋ฐ˜์ ์œผ๋กœ ์ •์  ์ƒ์„ฑ(SSG) ๋˜๋Š” ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง(SSR)์˜ ๋‘ ๊ฐ€์ง€ ์ „๋žต ์ค‘์—์„œ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋Œ€์‹  Next.js๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‚ฌ์šฉ๋˜๋Š” ์ „๋žต์„ ํŽ˜์ด์ง€๋ณ„๋กœ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Next.js 9๋ถ€ํ„ฐ getInitialProps ๊ฐ€ ์—†๋Š” ํŽ˜์ด์ง€๋Š” ์ •์ ์œผ๋กœ ์ตœ์ ํ™” ๋˜๊ณ  next build ์‹œ .html ํŒŒ์ผ๋กœ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•œ ์ •์  ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋™์•ˆ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด CMS ๋˜๋Š” ์‚ฌ์ดํŠธ์˜ ๋ธ”๋กœ๊ทธ ์„น์…˜์—์„œ ์ •์ ์œผ๋กœ ๋งˆ์ผ€ํŒ… ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ getInitialProps ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด SSR์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Next.js์—๋Š” ํ˜„์žฌ next export ๋ช…๋ น์ด ์žˆ์–ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์™„์ „ํžˆ SSG๋กœ ๋งŒ๋“ค๊ณ  Next.js์˜ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ํŠน์„ฑ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

next export ๋ฅผ getInitialProps ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. getInitialProps ๋Š” ๋นŒ๋“œ ์‹œ ํ˜ธ์ถœ๋˜์ง€๋งŒ(ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค) next/link ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŽ˜์ด์ง€ ์‚ฌ์ด๋ฅผ ์ด๋™ํ•  ๋•Œ getInitialProps ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ํด๋ผ์ด์–ธํŠธ ์ธก์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค next export ๊ฒฐ๊ณผ.

์ด๊ฒƒ์€ ๋˜ํ•œ ๋ฐ์ดํ„ฐ ์†Œ์Šค(CMS/API ๋์ )๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์ธก ์ „ํ™˜์—์„œ ์ง์ ‘ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ์†Œ์Šค๊ฐ€ ๋‹ค์šด๋œ ๊ฒฝ์šฐ ํŽ˜์ด์ง€ ๊ฐ„์— ์ด๋™ํ•˜๋Š” ๋™์•ˆ ํด๋ผ์ด์–ธํŠธ ์ธก ์ „ํ™˜์ด ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” HashiCorp์™€ ๊ฐ™์€ Next.js์—์„œ SSG ๋ฐ next export ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž์™€ ํ˜‘๋ ฅํ–ˆ์œผ๋ฉฐ(@jescalan์—๊ฒŒ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค) ๋‘ ๊ฐ€์ง€ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐฉ๋ฒ•์ธ getStaticProps ๋ฐ getServerSideProps ๋„์ž…์— ๋Œ€ํ•œ ์˜ฌ๋ฐ”๋ฅธ ์ œ์•ฝ ์กฐ๊ฑด์„ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ์กฐ์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค getStaticPaths (ํŽ˜์ด์ง€๋‹น exportPathMap ๋Œ€์ฒด).

์ด๋Ÿฌํ•œ ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์€ getInitialProps ๋ชจ๋ธ์— ๋น„ํ•ด ๋งŽ์€ ์ด์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. SSG์™€ SSR์ด ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

  • getStaticProps ๋Š” ํŽ˜์ด์ง€๊ฐ€ ๋นŒ๋“œ ์‹œ ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋„๋ก ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค( next build ).
  • getStaticPaths ๋Š” ๋™์  ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ๋นŒ๋“œ ์‹œ ์ƒ์„ฑํ•  ๋งค๊ฐœ๋ณ€์ˆ˜ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • getServerSideProps ๋Š” ๋ชจ๋“  ์š”์ฒญ์—์„œ ํŽ˜์ด์ง€๊ฐ€ ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง๋˜๋„๋ก ํ‘œ์‹œํ•˜๋ฉฐ ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์˜ ํ˜„์žฌ getInitialProps ๋™์ž‘๊ณผ ๊ฐ€์žฅ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด TypeScript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” ์˜ฌ๋ฐ”๋ฅธ ์ปจํ…์ŠคํŠธ ๊ฐœ์ฒด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠน์ • ๋ Œ๋”๋ง ์ „๋žต์„ ์„ ํƒํ•˜๋ฉด ํ˜„์žฌ getInitialProps ์˜ฌ๋ฐ”๋ฅธ ๊ฐ’์„ ์–ป์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ TypeScript๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ SSG ๋Œ€ SSR์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์„ ์ถ”์ธกํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•์„ ๋ช…์‹œ์ ์œผ๋กœ ์ง€์ •ํ•˜๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์ ˆ์ถฉ์•ˆ์„ ๋ณด๋‹ค ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฌธ์„œํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„

์ด๋Ÿฌํ•œ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๋Š” ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ ํŒŒ์ผ์˜ ์ตœ์ƒ์œ„ ์ˆ˜์ค€์ด๋ฉฐ getInitialProps ์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์ค‘์ฒฉ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

getStaticProps

getStaticProps ์‚ฌ์šฉํ•˜๋ฉด ํŽ˜์ด์ง€๊ฐ€ ๋นŒ๋“œ ์‹œ๊ฐ„(SSG)์— ์ •์ ์œผ๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

์ด ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด next build ์‹œ๊ฐ„์— .html ํŒŒ์ผ๋กœ ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋  ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Next.js๋Š” ๋˜ํ•œ next build ์‹œ๊ฐ„์— getStaticProps ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์œ ํ•˜๋Š” JSON ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

next/link ๋˜๋Š” next/router ํ†ตํ•œ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ… ์‹œ Next.js๋Š” ์ด JSON ํŒŒ์ผ์„ ๊ฐ€์ ธ์™€ ํด๋ผ์ด์–ธํŠธ ์ธก ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์†Œํ’ˆ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

์†์„ฑ์€ props ํ‚ค ์•„๋ž˜์— ๋ฐ˜ํ™˜๋˜๋ฏ€๋กœ ๋‚˜์ค‘์— ๋‹ค๋ฅธ ์˜ต์…˜์ด ๋„์ž…๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// pages/index.js

// getStaticProps is only called server-side
// In theory you could do direct database queries
export async function getStaticProps(context) {
  return {
    // Unlike `getInitialProps` the props are returned under a props key
    // The reasoning behind this is that there's potentially more options
    // that will be introduced in the future.
    // For example to allow you to further control behavior per-page.
    props: {}
  };
}

context ์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

  • params - ๋™์  ๊ฒฝ๋กœ์— ์žˆ์„ ๋•Œ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค.

getStaticPaths

์ด๊ฒƒ์€ ๋™์  ๊ฒฝ๋กœ์— ๋Œ€ํ•œ getStaticProps ์‚ฌ์šฉ์— ๋Œ€ํ•œ ํ™•์žฅ์ž…๋‹ˆ๋‹ค.

getStaticPaths ๋Š” exportPathMap ๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋Š” ํ•„์š”์„ฑ์„ ๋Œ€์ฒดํ•˜๊ณ  ํŽ˜์ด์ง€๋ณ„๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

slug ์•„๋ž˜์˜ ์˜ˆ์™€ ๊ฐ™์ด ๋™์  ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” URL ๋ชฉ๋ก์„ ์ •์ ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. Next.js๋Š” URL ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋Š” getStaticPaths ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. async ๋ฐฉ๋ฒ•์ด๋ฏ€๋กœ CMS์™€ ๊ฐ™์€ ๋ฐ์ดํ„ฐ ์†Œ์Šค์—์„œ ํ•ด๋‹น ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

// pages/blog/[slug].js

// `getStaticProps` gets a `params` object holding the dynamic parameters
// For `/blog/hello-world` it would look like `{ slug: 'hello-world }`
export async function getStaticProps({ params }) {
  return {
    props: {}
  };
}

// `getStaticPaths` allows the user to return a list of parameters to
// render to HTML at build time.
export async function getStaticPaths() {
  return {
    paths: [
      // This renders /blog/hello-world to HTML at build time
      { params: { slug: "hello-world" } }
    ]
  };
}

๋Œ€์ฒด

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋นŒ๋“œ ์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๊ฒฝ๋กœ๋ฅผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ์ˆ˜๋ฐฑ๋งŒ ๊ฐœ์˜ ์ œํ’ˆ์ด ์žˆ๋Š” ๊ฒฝ์šฐ). ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ Next.js๋Š” ํŽ˜์ด์ง€๊ฐ€ ์•„์ง ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์„ ๋•Œ ๋ฐ์ดํ„ฐ ์—†์ด ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” fallback ํŽ˜์ด์ง€๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค(๋กœ๋“œ ์ƒํƒœ๊ฐ€ ํ‘œ์‹œ๋  ์ˆ˜ ์žˆ๋„๋ก).

์ •ํ™•ํ•œ ์„œ๋น™ ๋™์ž‘์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ

    • Next.js๋Š” ๋นŒ๋“œ ์‹œ ๊ฒฝ๋กœ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

    • ๊ฒฝ๋กœ๊ฐ€ ์ƒ์„ฑ๋œ ๊ฒฝ์šฐ



      • ์ง์ ‘ ๋ด‰์‚ฌํ•˜๋‹ค



    • ๊ฒฝ๋กœ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ



      • ๋Œ€์ฒด ์ œ๊ณต


      • Next.js๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํŽ˜์ด์ง€(๋ฐ์ดํ„ฐ ํฌํ•จ)๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.


      • ๋™์ผํ•œ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ํ›„์† ์š”์ฒญ์€ ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


      • ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ํ•ญ์ƒ ๋น ๋ฅธ ๊ฒฝํ—˜์„ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋น ๋ฅธ ๋นŒ๋“œ ๋ฐ ์ •์  ์ƒ์„ฑ ์†์„ฑ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์„œ๋ฒ„ ๋ Œ๋”๋ง์—์„œ ๋Š๋ฆฐ TTFB๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.



๋นŒ๋“œ ์‹œ ์ƒ์„ฑ๋˜์ง€ ์•Š์€ ๊ฒฝ๋กœ๊ฐ€ fallback: false ์—์„œ getStaticPaths fallback: false ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ๊ฐ€๋Šฅํ•œ 404๊ฐ€ ๋˜๋„๋ก ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ

// `getStaticPaths` allows the user to return a list of parameters to
// render to HTML at build time.
export async function getStaticPaths() {
  return {
    // Opt-out of the described fallback behavior
    fallback: false,
    paths: [
      // This renders /blog/hello-world to HTML at build time
      { params: { slug: "hello-world" } }
    ]
  };
}

getServerSideProps

getServerSideProps ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํŽ˜์ด์ง€๋Š” ์ •์ ์œผ๋กœ ์ƒ์„ฑ(SSG)๋˜์ง€ ์•Š๊ณ  ๋Œ€์‹  ์„œ๋ฒ„์— ๋Œ€ํ•œ ๋ชจ๋“  ์š”์ฒญ(SSR)์— ๋Œ€ํ•ด ์˜จ๋””๋งจ๋“œ๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

Next.js๋Š” getServerSideProps ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” API ๋์ ๋„ ์ž๋™์œผ๋กœ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

next/link ๋˜๋Š” next/router ํ†ตํ•œ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ… ์‹œ Next.js๋Š” ์ด ๋…ธ์ถœ๋œ API ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ฐ€์ ธ์™€ ํŽ˜์ด์ง€ ํด๋ผ์ด์–ธํŠธ ์ธก์„ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์†Œํ’ˆ์œผ๋กœ ๋ณ€ํ™˜๋˜๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

์ด ๋ฐฉ๋ฒ•์€ ํ˜„์žฌ getInitialProps ์™€ ๊ฐ€์žฅ ์œ ์‚ฌํ•˜๋ฉฐ, ์ฃผ๋œ ์ฐจ์ด์ ์€ getServerSideProps ๊ฐ€ ํ•ญ์ƒ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์•„๋‹Œ ์„œ๋ฒ„ ์ธก์—์„œ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง ๋˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ… ์‹œ API ๊ฐ€์ ธ์˜ค๊ธฐ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

getStaticProps ์™€ ์œ ์‚ฌํ•˜๊ฒŒ ์†์„ฑ์€ props ํ‚ค ์•„๋ž˜์— ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.

// pages/index.js

// getServerSideProps is only called server-side
// In theory you could do direct database queries
export async function getServerSideProps(context) {
  return {
    // Unlike `getInitialProps` the props are returned under a props key
    // The reasoning behind this is that there's potentially more options
    // that will be introduced in the future.
    // For example to allow you to further control behavior per-page.
    props: {}
  };
}

context ์—๋Š” ๋‹ค์Œ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.

  • params - ๋™์  ๊ฒฝ๋กœ์˜ ๋งค๊ฐœ๋ณ€์ˆ˜
  • req - HTTP ์š”์ฒญ ๊ฐ์ฒด
  • res - HTTP ์‘๋‹ต ๊ฐ์ฒด
  • query - ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด(์ด๊ฒƒ์€ ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ์•„๋งˆ๋„ ํ•„์š”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค)

@timneutkens , @Timer , @ijjk , @lfades๊ฐ€ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. @rauchg , @jescalan ๋ฐ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ๊ณต๋™ ์ž‘์—… ๐Ÿš€

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

Next.js 9.3์—์„œ ์ฐจ์„ธ๋Œ€ SSG(์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ) ์ง€์›์ด ์•ˆ์ •์ ์œผ๋กœ ๋ฆด๋ฆฌ์Šค๋˜์—ˆ์Šต๋‹ˆ๋‹ค!

์ด ๋ฆด๋ฆฌ์Šค๋Š” ๋˜ํ•œ "๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชจ๋“œ"์— ๋Œ€ํ•œ ์ง€์›, ๋˜๋Š” ์ •์ ์œผ๋กœ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋œ ํŽ˜์ด์ง€ ์šฐํšŒ ํ•  ์ˆ˜์žˆ๋Š” ๊ธฐ๋Šฅ์„ ํฌํ•จํ•˜๊ณ  ์ฃผ๋ฌธํ˜• ๊ถŒํ•œ์ด ๋ถ€์—ฌ ๋œ ์‚ฌ์šฉ์ž์˜ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๋ฌธ์„œ ๋กœ ๋ฐ”๋กœ ์ด๋™ํ•˜์‹ญ์‹œ์˜ค!

๋ชจ๋“  250 ๋Œ“๊ธ€

export async function getStaticProps(context) {
  return {
    // Unlike `getInitialProps` the props are returned under a props key
    // The reasoning behind this is that there's potentially more options
    // that will be introduced in the future.
    // For example to allow you to further control behavior per-page.
    props: {}
  };
}

props ๋‚ด์— ํฌํ•จ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ์ด์™ธ์˜ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์„ ํ™•์ธํ•˜๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. "ํŽ˜์ด์ง€๋‹น ๋™์ž‘์„ ์ถ”๊ฐ€๋กœ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•œ" ์ธ๋ผ์ธ ์„ค๋ช…์ด ์•ฝ๊ฐ„ ๋ชจํ˜ธํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.

๋งค์šฐ ํฅ๋ฏธ๋กญ๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค! getInitialProps ๋Œ€์‹ ํ•  ๊ฒƒ์ธ๊ฐ€ ์•„๋‹ˆ๋ฉด ํ•จ๊ป˜ ํ•  ๊ฒƒ์ธ๊ฐ€? ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ API๋Š” ๊ณต๊ณต ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํด๋ผ์ด์–ธํŠธ ์ธก ํƒ์ƒ‰์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ API ๊ณ„์ธต์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ˜๋ฉด SSR์—์„œ๋Š” ์„œ๋ฒ„๊ฐ€ ํ˜ธ์ถœํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์ด์ „ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ณ„์† ํ•ด๊ฒฐ๋ฉ๋‹ˆ๊นŒ?

props ๋‚ด์— ํฌํ•จ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ์ด์™ธ์˜ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์„ ํ™•์ธํ•˜๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค. "ํŽ˜์ด์ง€๋‹น ๋™์ž‘์„ ์ถ”๊ฐ€๋กœ ์ œ์–ดํ•˜๊ธฐ ์œ„ํ•œ" ์ธ๋ผ์ธ ์„ค๋ช…์ด ์•ฝ๊ฐ„ ๋ชจํ˜ธํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.

๋‚˜์ค‘์— ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฐฉ๋ฒ•์„ ๋ฏธ๋ž˜์— ์ฆ๋ช…ํ•˜๋Š” ๊ฒƒ์ด ๋” ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๋งค์šฐ ํฅ๋ฏธ๋กญ๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค! getInitialProps ๋Œ€์‹ ํ•  ๊ฒƒ์ธ๊ฐ€ ์•„๋‹ˆ๋ฉด ํ•จ๊ป˜ ํ•  ๊ฒƒ์ธ๊ฐ€? ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ API๋Š” ๊ณต๊ณต ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํด๋ผ์ด์–ธํŠธ ์ธก ํƒ์ƒ‰์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ API ๊ณ„์ธต์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ˜๋ฉด SSR์—์„œ๋Š” ์„œ๋ฒ„๊ฐ€ ํ˜ธ์ถœํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์ด์ „ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ณ„์† ํ•ด๊ฒฐ๋ฉ๋‹ˆ๊นŒ?

์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ๋™์ž‘์—๋Š” ์ „ ์„ธ๊ณ„์˜ ํŠน์ • ์ง€์—ญ์—์„œ ๋Š๋ฆด ์ˆ˜ ์žˆ๋Š” ํญํฌ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ์™€ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. getServerProps ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์‘๋‹ต์„ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ์บ์‹ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ •๋ง ํฅ๋ฏธ๋กญ๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค! ๋ฉ‹์ง„ ์•„์ด๋””์–ด!

๋ฐฐํฌ์— ๋Œ€ํ•œ ์šฐ๋ ค๊ฐ€ ์žˆ์ง€๋งŒ...

๋‚ด๊ฐ€ Now๋ฅผ ํ˜ธ์ŠคํŒ…ํ•œ๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ด…์‹œ๋‹ค.
์ฒซ ๋ฒˆ์งธ ๋ฐฐํฌ์˜ ๊ฒฝ์šฐ ์ „์ฒด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ๋ฐฐํฌ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์ถ•๋œ๋‹ค๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ CMS์—์„œ ์ผ๋ถ€ ์ฝ˜ํ…์ธ ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  SSG ํŽ˜์ด์ง€์˜ ์žฌ๊ตฌ์ถ•๋งŒ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ ค๊ณ  ํ•˜์ง€๋งŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์ฆ‰์‹œ ์•Œ๋žŒ์ด ์šธ๋ฆฝ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๋นŒ๋“œ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋ฉด ๋‘ ๊ฐ€์ง€ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.

1) ๋ชจ๋“  ๊ฒƒ์ด ์บ์‹œ๋˜๋ฏ€๋กœ ์•„๋ฌด ๊ฒƒ๋„ ๋‹ค์‹œ ๋นŒ๋“œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜์œผ๋ฉฐ blabla.
2) --force , ์ด์ œ "๋ชจ๋“  ๊ฒƒ"์ด ๋‹ค์‹œ ๋นŒ๋“œ๋˜์ง€๋งŒ SSG ํŽ˜์ด์ง€๋งŒ ๋‹ค์‹œ ๋นŒ๋“œํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

_์ด๊ฒƒ์€ ๋นŒ๋“œ ์‹œ์Šคํ…œ ์ž์ฒด์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋ฏ€๋กœ ๊ฐ€์„ค์ผ ๋ฟ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋‹ค๋ฅธ ํ˜ธ์ŠคํŒ… ์†”๋ฃจ์…˜์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ ์ž์ฒด์—๋Š” .next/cache ... ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@joltmode ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ˜„์žฌ ๋ชจ๋“  ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ๊ธฐ์˜ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. .next/cache ๋Š” Now์˜ ๋ฐฐํฌ์™€ ์žฌ์‚ฌ์šฉ ๊ฐ„์— ๋ณด์กด๋ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ์ด ๊ฒฝ์šฐ์— ์บ์‹ฑ(https://zeit.co/blog/serverless-pre-rendering)๊ณผ ํ•จ๊ป˜ getInitialProps๋ฅผ ์‚ฌ์šฉ ์ค‘์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ๋ช…์‹ฌํ•˜์‹ญ์‹œ์˜ค. ์ด ์บ์‹ฑ์€ ์„œ๋ฒ„๋ฆฌ์Šค ๊ธฐ๋Šฅ์—์„œ ๋™์ ์œผ๋กœ ๋ Œ๋”๋งํ•œ ๋‹ค์Œ CDN์— ์บ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋™์ž‘์€ ์—ฌ์ „ํžˆ โ€‹โ€‹๊ดœ์ฐฎ์œผ๋ฉฐ getServerProps ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ณ„์† ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ •๋ง ๊ต‰์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ณ ๊ฐ ํ”„๋กœ์ ํŠธ์— Next๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ์ž˜ ๋งž๊ณ  ๋ณต์‚ฌํ•˜๋Š” ์ผ๋ถ€ ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ๊ณ ๋ คํ•ด์•ผ ํ•  ์‚ฌํ•ญ์€ getStaticProps ๋ฐ getServerProps์˜ ์ด๋ฆ„ ์ง€์ •์ž…๋‹ˆ๋‹ค. { props } ๋ฐ ํ–ฅํ›„ ์ž ์žฌ์ ์ธ ๋‹ค๋ฅธ ์˜ต์…˜์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ *Props๊ฐ€ ํ˜ผ๋™๋˜์ง€ ์•Š์„๊นŒ์š”? getStaticConfiguration, getStaticSetup, getStaticOptions๊ฐ€ ๋” ์ผ๋ฐ˜์ ์ผ๊นŒ์š”?

@kibs ๋ฐ˜ํ™˜ ๊ฐ’์€ ํ•ญ์ƒ ์†Œํ’ˆ์ด ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฐฉ์‹๊ณผ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋„ค์ด๋ฐ์ด ์ข‹๋‹ค.

์ด๊ฒƒ์€ ๋‹จ์ˆœํžˆ ๊ต‰์žฅํ•ฉ๋‹ˆ๋‹ค! ์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ์ตœ๊ทผ์— ๊ฐ€์ง€๊ณ  ์žˆ๊ฑฐ๋‚˜ ๊ฐœ์ธ ๋ฐ ์ „๋ฌธ ์›น ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๋Š” ๋™์•ˆ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๋ชจ๋“  ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ํ•„์š”๋ฅผ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์€ ๋‚ด๊ฐ€ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์‚ฌ์ดํŠธ ์ƒ์„ฑ๊ธฐ๋ฅผ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์•˜์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‚˜๋Š” ๋˜ํ•œ ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์ด ์ด์ „ getInitialProps() ๋ฐ exportPathMap() ๋ณด๋‹ค ๋‚ซ๋‹ค๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ฒ˜์Œ์— Next.js๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๊ณ  SSR/SSG๋ฅผ ํŒŒํ—ค์ณค์„ ๋•Œ ์•ฝ๊ฐ„ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ๋“ค๋ ธ์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋‹น ์ ‘๊ทผ ๋ฐฉ์‹์ด ๋‚˜์—๊ฒŒ๋„ ๋” ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ์‹œ๋„ํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค!

์ฐธ๊ณ  ์‚ฌํ•ญ: ๋งˆ์ง€๋ง‰ ์˜ˆ์—์„œ getServerProps() ์— context ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋ˆ„๋ฝ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ  ์‚ฌํ•ญ: ๋งˆ์ง€๋ง‰ ์˜ˆ์ œ์—์„œ getServerProps()์— ์ปจํ…์ŠคํŠธ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ์ •๋œ!

์ด๊ฒƒ์€ ์ข‹์€ ์†Œ๋ฆฌ์ž…๋‹ˆ๋‹ค! TypeScript ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ getStaticProps , getStaticPaths ๋ฐ getServerProps ๋ฅผ ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ •์  ๋ฉ”์„œ๋“œ(์˜ˆ getInitialProps )๋กœ ์‚ฌ์šฉํ•˜๋ฉด ๋” ์‰ฝ๊ฒŒ ์ž…๋ ฅ/์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const Page: NextPage<Props> = (props) => ...

// Explicit types needed here
export const getStaticPaths: NextGetStaticPaths<Params> = () => ...
export const getStaticProps: NextGetStaticProps<Props, Params> = (context) => ...
export const getServerProps: NextGetServerProps<Props> = (context) => ...

export default Page

// vs.

const Page: NextPage<Props, Params> = (props) => ...

// Static method types come from NextPage<Props, Params>
Page.getStaticPaths = () => ...
Page.getStaticProps = (context) => ...
Page.getServerProps = (context) => ..

export default Page

@herrstucki ๊ทธ ์ ‘๊ทผ ๋ฐฉ์‹์˜ ๋ฌธ์ œ๋Š” ๋‚˜๋ฌด๋ฅผ ํ”๋“œ๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ์–ด๋ ค์›Œ์ง„๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค(์ฝ๊ธฐ: ๋ถˆ๊ฐ€๋Šฅ์— ๊ฐ€๊น์Šต๋‹ˆ๋‹ค). ์ด๋Š” ๋ถˆํ•„์š”ํ•œ ์ฝ”๋“œ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ์ „๋‹ฌ๋  ๊ฒƒ์ž„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

@timneutkens ์ข‹์€ ์ง€์  ... ํ•˜์ง€๋งŒ ๋ณ„๋„์˜ ํŒŒ์ผ์ด ๋” ์˜๋ฏธ๊ฐ€ ์—†์„๊นŒ์š”? ์•„๋‹ˆ๋ฉด ์ด์™€ ๊ฐ™์€ ๊ฒƒ์ด _์•ˆ์ •์ ์œผ๋กœ_ ๋‚˜๋ฌด๋ฅผ ํ”๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

// This should all be removed in client-side code โ€ฆ
import {fetchQuery, queryTag} from 'big-data-fetching-lib';
const query = queryTag`...`
export const getStaticProps = async () => ({ props: await fetchQuery(query) })

// Only this should be included client-side
export default (props) => ...

@herrstucki ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ ์•ˆ์ •์ ์œผ๋กœ ํ”๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ, ์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ๋ณ„๋„์˜ ํŒŒ์ผ์„ ๊ฐ–๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ๋‹จ์ผ ํŒŒ์ผ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

๋งค์šฐ ํฅ๋ฏธ๋กญ๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค! getInitialProps ๋Œ€์‹ ํ•  ๊ฒƒ์ธ๊ฐ€ ์•„๋‹ˆ๋ฉด ํ•จ๊ป˜ ํ•  ๊ฒƒ์ธ๊ฐ€? ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ API๋Š” ๊ณต๊ณต ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํด๋ผ์ด์–ธํŠธ ์ธก ํƒ์ƒ‰์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ API ๊ณ„์ธต์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ˜๋ฉด SSR์—์„œ๋Š” ์„œ๋ฒ„๊ฐ€ ํ˜ธ์ถœํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์ด์ „ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ณ„์† ํ•ด๊ฒฐ๋ฉ๋‹ˆ๊นŒ?

์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ๋™์ž‘์—๋Š” ์ „ ์„ธ๊ณ„์˜ ํŠน์ • ์ง€์—ญ์—์„œ ๋Š๋ฆด ์ˆ˜ ์žˆ๋Š” ํญํฌ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ์™€ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. getServerProps ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์‘๋‹ต์„ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ์บ์‹ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก , ํ•˜์ง€๋งŒ ๋ฐ˜์‘ ์„œ๋ฒ„์— ๋Œ€ํ•œ RTT๋ฅผ ์ „ํ˜€ ํ”ผํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„์˜ SSR ์ถœ๋ ฅ์ด CDN/์บ์‹œ ์„œ๋ฒ„ ํ”„๋ก์‹œ์— ์บ์‹ฑ๋˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด ๋ณด์ž. ๋‹ค๋ฅธ API ๋ ˆ์ด์–ด(์›น/์•ฑ/๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์— ๊ณตํ†ต)๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ํƒ์ƒ‰์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์€ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ Next.js ์„œ๋ฒ„ ๋ ˆ์ด์–ด๋ฅผ ํ™•์žฅํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

ํญํฌ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ์˜ ์š”์ ์„ ์ดํ•ดํ•˜์ง€๋งŒ ์†Œ๋น„์ž์—๊ฒŒ ๋‹ค์Œ ์„œ๋ฒ„๋ฅผ ๋ฐ์ดํ„ฐ ์†Œ์Šค์™€ ๋น„๊ตํ•˜์—ฌ SSR ๊ณ„์ธต์œผ๋กœ ์ทจ๊ธ‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฉด ํ›จ์”ฌ ๋” ๋‚˜์€ ํ™•์žฅ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๋งค์šฐ ํฅ๋ฏธ๋กญ๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค! getInitialProps ๋Œ€์‹ ํ•  ๊ฒƒ์ธ๊ฐ€ ์•„๋‹ˆ๋ฉด ํ•จ๊ป˜ ํ•  ๊ฒƒ์ธ๊ฐ€? ์˜ˆ๋ฅผ ๋“ค์–ด ์šฐ๋ฆฌ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ API๋Š” ๊ณต๊ณต ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํด๋ผ์ด์–ธํŠธ ์ธก ํƒ์ƒ‰์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ API ๊ณ„์ธต์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ˜๋ฉด SSR์—์„œ๋Š” ์„œ๋ฒ„๊ฐ€ ํ˜ธ์ถœํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์ด์ „ ๋ฐฉ๋ฒ•์œผ๋กœ ๊ณ„์† ํ•ด๊ฒฐ๋ฉ๋‹ˆ๊นŒ?

์ผ๋ฐ˜์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ๋™์ž‘์—๋Š” ์ „ ์„ธ๊ณ„์˜ ํŠน์ • ์ง€์—ญ์—์„œ ๋Š๋ฆด ์ˆ˜ ์žˆ๋Š” ํญํฌ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ์™€ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. getServerProps ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์‘๋‹ต์„ ๋ณด๋‹ค ํšจ์œจ์ ์œผ๋กœ ์บ์‹ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก , ํ•˜์ง€๋งŒ ๋ฐ˜์‘ ์„œ๋ฒ„์— ๋Œ€ํ•œ RTT๋ฅผ ์ „ํ˜€ ํ”ผํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„์˜ SSR ์ถœ๋ ฅ์ด CDN/์บ์‹œ ์„œ๋ฒ„ ํ”„๋ก์‹œ์— ์บ์‹ฑ๋˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด ๋ณด์ž. ๋‹ค๋ฅธ API ๋ ˆ์ด์–ด(์›น/์•ฑ/๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ์— ๊ณตํ†ต)๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ ํƒ์ƒ‰์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์€ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ Next.js ์„œ๋ฒ„ ๋ ˆ์ด์–ด๋ฅผ ํ™•์žฅํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

ํญํฌ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ์˜ ์š”์ ์„ ์ดํ•ดํ•˜์ง€๋งŒ ์†Œ๋น„์ž์—๊ฒŒ ๋‹ค์Œ ์„œ๋ฒ„๋ฅผ ๋ฐ์ดํ„ฐ ์†Œ์Šค์™€ ๋น„๊ตํ•˜์—ฌ SSR ๊ณ„์ธต์œผ๋กœ ์ทจ๊ธ‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฉด ํ›จ์”ฌ ๋” ๋‚˜์€ ํ™•์žฅ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ด ์ƒˆ๋กœ์šด ๋™์ž‘์€ CDN์ด ๋™์  ์‘๋‹ต์„ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ ์‹ค์ œ๋กœ ์ „์ฒด ๊ฒฐ๊ณผ๋ฅผ CDN์— ์บ์‹œํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์˜คํ•ดํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด์ „์— getInitialProps๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ˆ์ •์ ์œผ๋กœ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

@timneutkens babel-plugin-preval ์ฝ”๋“œ๋ฅผ getStaticProps ๋กœ ์ด์‹ํ•˜๋ ค๊ณ  ํ•˜๋Š” ์นด๋‚˜๋ฆฌ์•„๋ฅผ ๊ฐ€์ง€๊ณ  ๋†€์•˜์Šต๋‹ˆ๋‹ค. fs ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

๋‚ด ./pages/blog/ ๋””๋ ‰ํ† ๋ฆฌ์˜ .md ํŒŒ์ผ์„ ์ฝ๊ณ  ๋ฃจํ”„๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์ด ํฌํ•จ๋œ ๋ธ”๋กœ๊ทธ ์ƒ‰์ธ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

import React from 'react';
import Link from 'next/link';
import fs from 'fs-extra';

const Index = ({ posts }) => (
  <div>
    Hello World. <Thing msg="hello" />
    <Link href="/thing">
      <a>About</a>
    </Link>
    {posts.map(p => (
      <div key={p.title}>{p.title}</div>
    ))}
  </div>
);

Index.getStaticProps = async () => {
  const items = await fs.readdir('./pages/blog');
  items.forEach(path => /* .... do some stuff ... */ )
  return { props: { posts: items } };
};

export default Index;

์ด ์ฝ”๋“œ๋Š” ๋‹ค์Œ ์˜ค๋ฅ˜๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

Module not found: Can't resolve 'fs' in '/Users/jared/Downloads/nextjs-typescript-template/node_modules/fs-extra/lib'

Razzle์˜ IIRC์— ๋”ฐ๋ฅด๋ฉด ์ด ์˜ค๋ฅ˜๋Š” webpack์˜ ํŒŒ์ผ ์‹œ์Šคํ…œ ์Šคํ…(๋˜๋Š” ๊ทธ ๋ถ€์กฑ)๊ณผ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์„ webpack ๊ตฌ์„ฑ์— ์ถ”๊ฐ€ํ•˜์—ฌ Razzle๋กœ ํ•œ ๋ฒˆ ์ด๊ฒƒ์„ ์ˆ˜์ •ํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

node: {
  fs: "empty";
}

์ด next.config.js๋ฅผ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์˜ค๋ฅ˜๊ฐ€ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค. fs / fs-extra ๊ฐ€ ์‹ค์ œ๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ž‘๋™ํ•˜์ง€๋งŒ ์•„๋งˆ๋„ ๊ฒฝ๋กœ๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค(๋‚˜์—๊ฒŒ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Œ). ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ์ƒ๊ฐ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

๋” ์ผ๋ฐ˜์ ์œผ๋กœ ๋‚ด ๋‹ค๋ฅธ ์งˆ๋ฌธ์€ getStaticProps ์—์„œ import ๋Œ€ require๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ฒ” ์‚ฌ๋ก€๊ฐ€ ๋ฌด์—‡์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋Š”์ง€์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ‹€๋ฆฌ์ง€ ์•Š์•˜๋‹ค๋ฉด ์œ„์˜ ์Šค๋‹ˆํŽซ์€ fs-extra ๋ฅผ React์—์„œ ๋™ํ˜•์ ์œผ๋กœ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค??. ๋”ฐ๋ผ์„œ ์ด์™€ ๊ฐ™์ด ์ธ๋ผ์ธ ์š”๊ตฌ ์‚ฌํ•ญ์œผ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ์Šต๋‹ˆ๊นŒ?

js Index.getStaticProps = async () => { const fs = require('fs-extra'); // only require when needed at SSG const props = await fs.readdir('./pages/blog'); return { props: { posts } }; };

์ด ์ƒˆ๋กœ์šด ๋™์ž‘์€ CDN์ด ๋™์  ์‘๋‹ต์„ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ ์‹ค์ œ๋กœ ์ „์ฒด ๊ฒฐ๊ณผ๋ฅผ CDN์— ์บ์‹œํ•  ์ˆ˜ ์žˆ์Œ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์˜คํ•ดํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ด์ „์— getInitialProps๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ˆ์ •์ ์œผ๋กœ ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

์•„, ๋ฌด์Šจ ๋ง์ธ์ง€ ์•Œ ๊ฒƒ ๊ฐ™์•„์š”. ๊ทธ๊ฒƒ์€ ์ฒซ ๋ฒˆ์งธ SSR ์ƒ์„ฑ์˜ getServerProps ๊ฐ€ ๊ณ ์œ ํ•œ ๋์ ์„ ์ƒ์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? ์ฝ˜ํ…์ธ  ์ฃผ์†Œ ์ง€์ • ๊ฐ€๋Šฅํ•œ ํ•ด์‹œ์—์„œ ์•„๋งˆ๋„ URL์— ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ทธ๋Ÿฐ ๋‹ค์Œ CDN์— ์บ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์ด๊ฒƒ์˜ ์œ ์ผํ•œ ๋‹จ์ ์€ ์บ์‹œ๊ฐ€ ๋น„ Next ์•ฑ(android/ios)๊ณผ Next ์•ฑ ๊ฐ„์— ๊ณต์œ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์†Œ์Šค์˜ ๊ฒฝ์šฐ ์บ์‹œ ์ œ์–ด ์ง€์‹œ๋ฌธ์ด ์—…์ŠคํŠธ๋ฆผ์ด์ง€๋งŒ Next๊ฐ€ ๋ฐ์ดํ„ฐ ์ œ๊ณต์„ ๋‹ด๋‹นํ•˜๋ฏ€๋กœ ์ƒ์„ฑ๋œ ๋ฐ์ดํ„ฐ ๋์ ์— ๋Œ€ํ•œ API ๋˜๋Š” ์†Œํ’ˆ์„ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด API ๋˜๋Š” ์†Œํ’ˆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

@jaredpalmer ๋‚˜๋Š” https://github.com/zeit/next.js/issues/9524#issuecomment -558628066 ( ์•ˆ์ •์ ์ธ ํŠธ๋ฆฌ ํ”๋“ค๋ฆผ ๊ฐ€๋Šฅ์„ฑ์— ๋Œ€ํ•œ ๋‚ด ์šฐ๋ ค ํฌํ•จ)์ด ์™„์ „ํžˆ ๋ณ„๋„๋กœ ์ปดํŒŒ์ผ๋˜๋Š” ๋ณ„๋„์˜ ํŒŒ์ผ์„ ๊ฐ€์ง์œผ๋กœ์จ ํ•ด๊ฒฐ๋  ๊ฒƒ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ๋ฒˆ๋“ค ์ฝ”๋“œ? ์˜ˆ

pages/
    foo.js
    foo.data.js (<- exports getStaticProps etc.)

or:

pages/
    foo.js
pages-data/
    foo.js (<- exports getStaticProps etc.)

@jaredpalmer ํŠธ๋ฆฌ ์‰์ดํ‚น์€ ์นด๋‚˜๋ฆฌ์•„์—์„œ ์•„์ง ๊ตฌํ˜„๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

ํ•ญ์ƒ ๊ทธ๋ ‡๋“ฏ์ด ๋ชจ๋“  ์ผ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. Next.js๋Š” ์ž‘์—…ํ•˜๋Š” ๋ฐ ์žˆ์–ด ์ ˆ๋Œ€์ ์ธ ๊ธฐ์จ์„ ๋ˆ„๋ ธ์Šต๋‹ˆ๋‹ค. ์•ž์„œ ๋ง์”€๋“œ๋ฆฐ ๊ฒƒ์ฒ˜๋Ÿผ ๊ฑฐ์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ ๋ฆด๋ฆฌ์Šค๋ฅผ ํ†ตํ•ด ์ œ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋ฒ ์ด์Šค์˜ ํฌ๊ธฐ๋ฅผ _๊ฐ์†Œ_์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋†€๋ž๋‹ค.

์ด RFC๋Š” ์ž‘์„ฑ๋œ ๋Œ€๋กœ ๋งŽ์€ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ์ฆ‰์‹œ ์œ ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด RFC๋ฅผ ๋น„ํŒํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๋‚ด๊ฐ€ ๋™์˜ํ•˜๋Š”์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†๋Š” ํ•œ ์ค„์„ ๋งํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

" getStaticPaths ๋Š” exportPathMap ๊ฐ€ ์žˆ์–ด์•ผ ํ•˜๋Š” ํ•„์š”์„ฑ์„ ๋Œ€์ฒดํ•˜๊ณ  ํŽ˜์ด์ง€๋ณ„๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค."

์ผ๋ถ€ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ๋Š” ๋นŒ๋“œ ์‹œ ๊ฒฝ๋กœ๋ฅผ ์•„๋Š” ๊ฒƒ์ด ๋น„ํ˜„์‹ค์ ์ด๊ฑฐ๋‚˜ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ํŽ˜์ด์ง€
  • ์ œํ’ˆ ํŽ˜์ด์ง€(์žฌ๊ณ ๊ฐ€ ๋น ๋ฅด๊ฒŒ ๋ณ€ํ™”ํ•˜๋Š” ํšŒ์‚ฌ์˜ ๊ฒฝ์šฐ)
  • ํŒ๋งค ์ฃผ๋ฌธ ์„ธ๋ถ€ ์ •๋ณด ํŽ˜์ด์ง€

์ด์™€ ๊ฐ™์€ ํŽ˜์ด์ง€์˜ ๊ฒฝ๋กœ๋Š” /entity-name/entity-id ๊ฒƒ์ด๋ฉฐ Next์˜ ๋™์  ๊ฒฝ๋กœ๋Š” router.push('/customers/[customerId]', '/customers/baer') ์™€ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ง ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์•„์ง ํ•จ์ •์ด ์žˆ์Šต๋‹ˆ๋‹ค. Serve, Netlify, NGINX ๋“ฑ๊ณผ ๊ฐ™์€ ๊ฒƒ์œผ๋กœ ์ด๋Ÿฌํ•œ ํŒŒ์ผ์„ ์ •์ ์œผ๋กœ ์ œ๊ณตํ•  ๊ณ„ํš์ด๋ผ๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€ ์ƒˆ๋กœ ๊ณ ์นจ์—์„œ 404๋ฅผ ์–ป์ง€ ์•Š๋„๋ก ๋ฆฌ๋””๋ ‰์…˜ ์„ธํŠธ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋ฉฐ ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ์—ฌ์ „ํžˆ exportPathMap ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋‚ด๊ฐ€ ์ •๊ธฐ์ ์œผ๋กœ ์ž‘์—…ํ•˜๋Š” ์ฝ”๋“œ๋ฒ ์ด์Šค์—์„œ ๊ฑฐ์˜ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌ๋ฉ๋‹ˆ๋‹ค.

const buildServeConfig = redirects => {
  const config = {
    public: `dist`,
    trailingSlash: true,
    rewrites: redirects
  };

  const outputPath = `${__dirname}/serve.json`;

  fs.writeFile(outputPath, JSON.stringify(config, null, 2), err => {
    if (err) {
      throw err;
    }
    // eslint-disable-next-line no-console
    console.log(`Generated: ${outputPath}`);
  });
};

...

exportPathMap: function(defaultPathMap, { dev, outDir }) {
  const redirects = Object.entries(defaultPathMap)
    // No need to create a redirect rule for `/dirname/` or `/dirname/index.html`
    .filter(([url]) => url !== `/` && url !== `/index`)
    .map(([url, { page }]) => ({
      // Replaces /[customerId] with /:customerId
      source: url.replace(/]/g, ``).replace(/\[/g, `:`),
      destination: `${page}/index.html`
    }));

  // By default, the routes are sorted such that a route like `/order/:orderId`
  // comes before `/order/new`. Since the `:orderId` portion of `/order/:orderId` 
  // is a wildcard, the route `/order/new` will be a match and consider `new` 
  // as a value for `:orderId`. To get past this, we sort the redirects by the 
  // number of parameters in ascending order.
  const sortedRedirects = [...redirects].sort(
    (currentRedirect, nextRedirect) =>
      currentRedirect.source.split(`:`).length >
      nextRedirect.source.split(`:`).length
  );

  buildServeConfig(sortedRedirects);

  return defaultPathMap;
}

๋‚˜๋Š” ์ด RFC๊ฐ€ API๋ฅผ ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜๊ณ  ๋นŒ๋“œ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ˆœํšŒํ•˜์—ฌ ์ด๋Ÿฌํ•œ ๋ฆฌ๋””๋ ‰์…˜์„ ๋นŒ๋“œํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋„ ๋ฉ‹์ง„ ํƒˆ์ถœ ํ•ด์น˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ " getStaticPaths ๋Œ€ํ•œ ํ•„์š”์„ฑ์„ ์ œ๊ฑฐ"ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ํ•œ ๋ฒˆ, ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•ด ์‚ฌ๋ ค ๊นŠ๊ฒŒ ์ƒ๊ฐํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

getStaticProps / getStaticPaths ๋ฐ getServerProps ์ƒํ˜ธ ๋ฐฐํƒ€์ ์ž…๋‹ˆ๊นŒ? ์ฆ‰, ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง๋œ ๋ถ€ํ’ˆ๊ณผ ๋™์  ๋ถ€ํ’ˆ์„ ๋™์‹œ์— ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ, ํ•˜๋‚˜๋Š” ์ •์  ์ƒ์„ฑ์ด๊ณ  ํ•˜๋‚˜๋Š” ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์šฐ๋ฆฌ๊ฐ€ Next๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ธฐ ์ „์— Gatsby์—์„œ ๋†“์นœ ํฐ ๊ฒƒ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ชจ๋†€๋ฆฌ์‹(100kbs) JSON ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Gatsby์—์„œ JSON ํŒŒ์ผ์„ GraphQL ์Šคํ‚ค๋งˆ์— ๋กœ๋“œํ•˜๊ณ  ์ด์— ๋Œ€ํ•ด ์ฟผ๋ฆฌํ•˜์—ฌ ์ฃผ์–ด์ง„ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค. Next๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ์‰ฝ๊ณ  ๊นจ๋—ํ•œ ๋ฐฉ๋ฒ•์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ „์ฒด JSON ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•ด์•ผ ํ•˜๋Š” import monolith from './monolith.json' ์ž…๋‹ˆ๋‹ค.

์ด RFC 100%๋Š” ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  Gatsby๊ฐ€ ๋น›๋‚˜๋Š” ์˜์—ญ์—์„œ Gatsby์™€ ๋™๋“ฑํ•œ ์ˆ˜์ค€์— ํ•œ ๊ฑธ์Œ ๋” ๋‹ค๊ฐ€๊ฐ€๋„๋ก ํ•ฉ๋‹ˆ๋‹ค(๋ถ„๋ช…ํžˆ Gatsby๋Š” ๋Ÿฐํƒ€์ž„ SSR์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ์ •์  ๋นŒ๋“œ ํƒ€์ž„ ๋ Œ๋”์— ๋Œ€ํ•ด์„œ๋งŒ ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค).

@timneutkens , RFC์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

์ตœ๊ทผ์— @rauchg์™€ ๋…ผ์˜ํ•œ Next.js์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Next.js๋Š” ๋งค์šฐ ๋ถ€๋“œ๋Ÿฌ์šด DX์™€ ๋ช‡ ๊ฐ€์ง€ ํ•ฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ’์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ €๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก ์ „์šฉ ๋ Œ๋”๋ง ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ธ Smart TV ์•ฑ์— Next.js๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ๊ด€์‹ฌ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์Šค๋งˆํŠธ TV ์•ฑ์€ TV์˜ ๋ธŒ๋ผ์šฐ์ € ์—”์ง„์—์„œ ์‹คํ–‰๋˜๋Š” ๊ฑฐ์˜ ๊ณ ์ „์ ์ธ ์›น ์•ฑ์ž…๋‹ˆ๋‹ค.

  1. ์•ฑ์€ ์Šคํƒ€์ผ, ์Šคํฌ๋ฆฝํŠธ, ์ด๋ฏธ์ง€, _index.html_, ์ธ์ฆ์„œ ๋ฐ TV ๊ตฌ์„ฑ ํŒŒ์ผ๊ณผ ๊ฐ™์€ ๋ฒˆ๋“ค๋กœ ํŒจํ‚ค์ง•๋ฉ๋‹ˆ๋‹ค.
  2. ๋ฒˆ๋“ค์€ ๊ฒ€ํ† ๋ฅผ ์œ„ํ•ด ํ”Œ๋žซํผ์˜ ์•ฑ ์Šคํ† ์–ด์— ์ œ์ถœ๋ฉ๋‹ˆ๋‹ค.
  3. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋ฒˆ๋“ค์€ ์Šคํ† ์–ด์—์„œ ์•ฑ์œผ๋กœ ์„ค์น˜๋˜๊ณ  ์‚ฌ์šฉ์ž๊ฐ€ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ๋ฒˆ๋“ค์ด TV ์žฅ์น˜ ์ž์ฒด์— ์˜ํ•ด ์ •์ ์œผ๋กœ ํ˜ธ์ŠคํŒ…๋˜๊ณ  ์„œ๋ฒ„์—์„œ ๋กœ๋“œ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ SSR ์˜ต์…˜์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค(Node.js๋Š” ์ด๋Ÿฌํ•œ ๋ชฉ์ ์œผ๋กœ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋…ธ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค). ๊ทธ๋Ÿฌ๋‚˜ ์•ฑ ์ž์ฒด๋Š” ๋™์ ์ž…๋‹ˆ๋‹ค(์˜ˆ: Netflix).

๋”ฐ๋ผ์„œ ์ •์  ์›น ์„œ๋ฒ„์—์„œ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” SPA๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

getServerProps (๋˜๋Š” getInitialProps )๋ฅผ ์„ ํƒ ํ•ด์ œํ•˜๋ฉด SSR์„ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ์™„์ „ํžˆ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋™์  ๋ Œ๋”๋ง์€ ์–ด๋–ป๊ฒŒ ๋ฉ๋‹ˆ๊นŒ? ์ด ๊ฒฝ์šฐ ๋ผ์šฐํŒ…์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ? ์ด RFC ์— ๋”ฐ๋ฅด๋ฉด ๋ฌธ์ œ๋Š” ์•„์ง ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. @timneutkens ,

์ถ”์‹ : ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ๋ณ„๋„๋กœ ๋…ผ์˜ํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๊ฒฝ์šฐ ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•œ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@grushetsky ๋Š” ๋‹ค๋ฅธ ๋ฌธ์ œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ RFC์—์„œ ๋…ผ์˜๋˜๋Š” ๊ฒƒ๊ณผ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค ๐Ÿ‘

@timneutkens ์ด RFC์˜ ์•ฝ์†์€ ์ œ๊ฐ€ Next! ๊ทธ๋ž˜๋„ ๋ช…ํ™•ํžˆ ํ•˜์ž๋ฉด getInitialProps ๋„ ์—ฌ์ „ํžˆ ์กด์žฌํ•˜๊ฒ ์ฃ ?

์˜ฌ๋ฐ”๋ฅธ @outdooricon -- getInitialProps ๋Š” ๋‹น๋ถ„๊ฐ„ ๊ณ„์† ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

RFC์— ๋”ฐ๋ผ:

์ด RFC๋Š” API ์ถ”๊ฐ€์— ๋Œ€ํ•ด ๋…์ ์ ์œผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์€ ์ด์ „ ๋ฒ„์ „๊ณผ ์™„์ „ํžˆ ํ˜ธํ™˜๋˜๋ฉฐ ์ ์ง„์ ์œผ๋กœ ์ฑ„ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด RFC๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ›Œ๋ฅญํ•œ RFC, ์ด์— ๋Œ€ํ•ด ๋งค์šฐ ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค!

ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€์™€ ๊ด€๋ จํ•˜์—ฌ getServerProps ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์ €์žฅํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด API-endpoint๋กœ ๋ฐ”๋€Œ๊ณ  ๊ทธ ๊ฒฐ๊ณผ๊ฐ€ props๋กœ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌ๋˜๊ธฐ ๋•Œ๋ฌธ์— Redux, GraphQL-cache ๋“ฑ๊ณผ ๊ฐ™์€ ์™ธ๋ถ€ ์บ์‹œ์— ๊ฒฐ๊ณผ๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ธก์œผ๋กœ ๋„ฃ๋Š” ๊ทœ์ •๋œ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

getInitialProps ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•˜๋ฉด ์ •์  ๋ฐ ๋น„๋™๊ธฐ์‹์ด๋ฏ€๋กœ Next๋Š” ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ฒ˜์Œ์œผ๋กœ ๋ Œ๋”๋งํ•˜๊ธฐ ์ „์— ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์™ธ๋ถ€ ์บ์‹œ์— ๋ฌผ๊ฑด์„ ๋„ฃ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. getServerProps ๋Š” ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ํ•ด๋‹น๋˜์ง€ ์•Š์œผ๋ฉฐ ๊ตฌ์„ฑ ์š”์†Œ ์ˆ˜๋ช… ์ฃผ๊ธฐ์˜ ์บ์‹œ์— ํ•ญ๋ชฉ์„ ๋„ฃ๋Š” ๊ฒƒ์€ ์•„์ง ์บ์‹œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๋ Œ๋”๋ง์ด ์žˆ์–ด์•ผ ํ•จ์„ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. , props์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋”๋ผ๋„?

์ด๊ฒƒ์€ ๋ฌผ๋ก  ์˜๋„์ ์ผ ์ˆ˜๋„ ์žˆ๊ณ  ์ ‘๊ทผ ๋ฐฉ์‹์„ ๋†“์น˜๊ณ  ์žˆ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๊ณ ๋ คํ•œ ์‚ฌํ•ญ์ธ์ง€ ๋ฌป๊ณ  ์‹ถ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘: getStaticProps ์—๋„ ์ ์šฉ๋˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๐Ÿ˜„

์–ด๋”˜๊ฐ€์—์„œ ๋†“์ณค์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ์ฝ˜ํ…์ธ ๊ฐ€ ์บ์‹œ๋˜์—ˆ์ง€๋งŒ db์—์„œ ์—…๋ฐ์ดํŠธ๋˜๊ฑฐ๋‚˜ ์ƒˆ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์ด ์ƒ์„ฑ๋˜๋Š” ์ƒํ™ฉ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๊นŒ? ์ƒˆ ๋นŒ๋“œ๋ฅผ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋Ÿฐ ๊ฒƒ ๊ฐ™์•„์š”.

๊ฐ€์žฅ ๋จผ์ €! ํ›Œ๋ฅญํ•œ ์ œ์•ˆ์ž…๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ๋žŒ๋“ค์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ exportPathMaps ๋ณด๋‹ค ํฌ๊ฒŒ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธด ํ•œ๋ฐ, ๋‚˜๋Š” ์šฐ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ๊ทธ๊ฒƒ์„ ๊ฒฝ๋กœ ๊ตญ์ œํ™”์™€ ํ•จ๊ป˜ ์ž‘๋™์‹œํ‚ฌ ์ˆ˜ ์žˆ์„์ง€ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ๊ตฐ๋ถ„ํˆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

i18n ์ ‘๋‘์‚ฌ ๊ฒฝ๋กœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ œ์•ˆ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚ด ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ๋‹ค๋ฅธ ๊ตญ๊ฐ€ ์–ธ์–ด ์ ‘๋‘์‚ฌ ๋ฐ URL์ด ์žˆ๋Š” ํŽ˜์ด์ง€์— ์ˆ˜์ฒœ ๊ฐœ๋ฅผ ๊ตฌ์ถ•ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

/nl/brillen
/gb/glasses
/es/gafas
...

getStaticPaths ๋Š” ๊ท€ํ•˜์˜ ์˜ˆ( /blog/[id].js )์™€ ๊ฐ™์ด url์˜ ์ ‘๋‘์‚ฌ๊ฐ€ ์ž˜ ์•Œ๋ ค์ ธ ์žˆ์„ ๋•Œ ์ •๋ง ๋„์›€์ด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋™์  ์ ‘๋‘์‚ฌ(country-lang)์™€ ๋™์  ๊ฒฝ๋กœ๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜์—ฌ ๋ฃจํŠธ ์ˆ˜์ค€์—์„œ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ getStaticPaths ๊ตฌํ˜„์ด ์–ด๋–ป๊ฒŒ ๋ณด์ผ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๊นŒ?

@reaktivo pages/[lang]/blog/[id].js -> getStaticPaths ์—์„œ ์ •์ ์œผ๋กœ ๋ Œ๋”๋งํ•  ๋ชจ๋“  URL์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

@timneutkens ์ด๊ฒƒ์ด ์–ธ์ œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ฑฐ๋‚˜ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” ์†”๋ฃจ์…˜์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ๋•์…˜ ์•ฑ์— ๋Œ€ํ•ด ๊ธฐ๋Šฅ์„ ๊ด‘๋ฒ”์œ„ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ETA๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ๊ฐœ์„  ์‚ฌํ•ญ์œผ๋กœ ์ธํ•ด "์œ ์ง€๋˜์ง€ ์•Š๋Š”" ํ˜„์ƒ์  ํ”„๋กœ์ ํŠธ(๋‚˜ ์™ธ์—๋Š” ์•„๋ฌด๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” react ssg)๊ฐ€ ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๋ˆ„๋ฝ๋œ ๋ถ€๋ถ„์„ ์ถ”๊ฐ€ํ•˜๋Š” Next.js๋ฅผ ๋ณด๋‹ˆ ์ •๋ง ๊ธฐ์ฉ๋‹ˆ๋‹ค!

๊ถ๊ธˆ์ฆ์„ ํ•ด์†Œํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. WordPress์™€ ๊ฐ™์€ CMS ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค. ๋‚ด๊ฐ€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ getStaticPaths ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐ€์ ธ์˜ค๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ชฉ๋ก์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

export async function getStaticPaths () {
  return [
ย ย   // This renders / blog / hello-world to HTML at build time
    {params: {slug: "hello-world"}}
  ];
}

๊ฐ ๊ฒŒ์‹œ๋ฌผ์˜ ์Šฌ๋Ÿฌ๊ทธ๋Š” ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด getStaticProps ๋ฉ”์„œ๋“œ์—์„œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ npm ๋นŒ๋“œ์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
๋‚ด ์งˆ๋ฌธ์€ ๋นŒ๋“œ ํ›„์— ์ถ”๊ฐ€๋  ์ƒˆ ๊ฒŒ์‹œ๋ฌผ์— ๊ด€ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
getStaticProps ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ์ƒˆ ๊ฒŒ์‹œ๋ฌผ์„ ์Šฌ๋Ÿฌ๊ทธ๋กœ ๊ฐ€์ ธ์˜ค๋‚˜์š”?
์ด ์ƒˆ ๊ฒŒ์‹œ๋ฌผ์— ์ด์ „ ๋นŒ๋“œ์˜ ํŒŒ์ผ๊ณผ ๊ฐ™์€ .html ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๊นŒ?
๋‚˜๋Š” ๋‹ค์Œ๊ณผ ํ•จ๊ป˜ ์ผํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•˜๊ณ  ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ์—์„œ ์ด๊ฒƒ์ด ๋งค์šฐ ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ง์ ‘์ ์ธ ๊ด€๋ จ์€ ์—†์ง€๋งŒ ์ง€์›ํŒ€์—์„œ ๋‚ด ์งˆ๋ฌธ๊ณผ ์ผ์น˜ํ•˜๋Š” ๋‹ต๋ณ€์„ ์ œ๊ณตํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ์ œ์•ˆํ•˜๋Š” ๊ฒƒ์ด ํ•ด๊ฒฐ์ฑ…์ด ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ ๋™์•ˆ webhook ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ธฐ๋ฐ˜์œผ๋กœ JAMSTACK์„ ๋นŒ๋“œํ•˜๋„๋ก nextJS๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

getInitialProps๊ฐ€ ์žˆ์œผ๋ฉด ์„œ๋ฒ„์—์„œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.
๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋‚˜๋Š” ๋‹จ์ง€ CDNํ™”๋˜์ง€๋งŒ ์‚ฌ์ „ ๋ Œ๋”๋ง ์—†์ด๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ๊ทธ๋ฆฌ๊ณ  XHR์ด ๋ฐ˜ํ™˜๋˜์ง€ ์•Š๋Š” ํ•œ ํŽ˜์ด์ง€๋Š” ์ฝ˜ํ…์ธ ๊ฐ€ ์—†์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค(์•ˆ๋…•ํ•˜์„ธ์š” SEO)

nextJS๊ฐ€ ํฌํ•จ๋œ Jamstack์˜ ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์˜ˆ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? netlify์—์„œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌ ํ•ด์š”,
์•ˆ๋“œ๋ ˆ์•„์Šค

Hey @ScreamZ - ์ด ๋ณ€ํ™”๊ฐ€ next export ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ nextjs ์‚ฌ์ดํŠธ๋ฅผ ์ •์ ์œผ๋กœ ์ปดํŒŒ์ผํ•  ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ getInitialProps ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ธก ๊ฒฝ๋กœ ์ „ํ™˜์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. getStaticProps ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ ๋„ ํด๋ผ์ด์–ธํŠธ ์ธก ์ „ํ™˜์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. getStaticProps ์—์„œ ๊ฐ€์ ธ์˜จ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋Š” ๋นŒ๋“œ ์‹œ ํ•œ ๋ฒˆ๋งŒ ๊ฐ€์ ธ์˜ค๊ณ  ๋‹ค์‹œ ๊ตฌ์ถ•ํ•˜์ง€ ์•Š๋Š” ํ•œ ๋ผ์ด๋ธŒ ์‚ฌ์ดํŠธ. ์ด๊ฒƒ์€ ๋ฐ์ดํ„ฐ ๊ธฐ๋ฐ˜ ์ •์  ์‚ฌ์ดํŠธ์˜ ๊ณ ์ „์ ์ธ ์•„ํ‚คํ…์ฒ˜์ด๋ฉฐ ์›นํ›…์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ํ˜ธ์ŠคํŠธ์— ์—ฐ๊ฒฐํ•˜๊ณ  ๋ฐ์ดํ„ฐ ์†Œ์Šค๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ํ˜ธ์ŠคํŠธ์—๊ฒŒ ์‚ฌ์ดํŠธ๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๋„๋ก ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค.

์™„์ „ํžˆ ์ •์ ์ธ nextjs ์›น์‚ฌ์ดํŠธ์˜ ๊ธฐ์กด ์˜ˆ์ œ๊ฐ€ ๋งŽ์ด ์žˆ์œผ๋ฉฐ netlify์—์„œ nextjs ์‚ฌ์ดํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ํšŒ์‚ฌ์˜ ์›น์‚ฌ์ดํŠธ ๋Š” ํ˜„์žฌ nextjs์—์„œ ์‹คํ–‰๋˜๊ณ  ์žˆ์œผ๋ฉฐ netlify์—์„œ ํ˜ธ์ŠคํŒ…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์ข‹์€ ์˜ˆ๊ฐ€ ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

zeit์˜ ํ˜ธ์ŠคํŒ… ์„œ๋น„์Šค๋„ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๊ณ ๋ คํ•ด์•ผ ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์€ ์ฃผ๋ชฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๊ฒฉ์€ ๋งค์šฐ ๋น„์Šทํ•˜๊ณ  nextjs ์‚ฌ์ดํŠธ์™€์˜ ํ†ตํ•ฉ์€ ํƒ€์˜ ์ถ”์ข…์„ ๋ถˆํ—ˆํ•ฉ๋‹ˆ๋‹ค. ๋ง ๊ทธ๋Œ€๋กœ ์•„๋ฌด ๊ฒƒ๋„ ๊ตฌ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. github์— ์—ฐ๊ฒฐํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด zeit์˜ ํ˜ธ์ŠคํŒ…์ด nextjs๋ฅผ ์‹คํ–‰ ์ค‘์ž„์„ ์ธ์‹ํ•˜๊ณ  ์ž๋™์œผ๋กœ ๊ตฌ์„ฑ ๋ฐ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ.

์ด๊ฒƒ์€ ๊ฒฐ์ฝ” ๊ด‘๊ณ ๊ฐ€ ์•„๋‹ˆ๋ฉฐ, ๋‚˜๋Š” zeit๋ฅผ ์œ„ํ•ด ์ผํ•˜์ง€ ์•Š์œผ๋ฉฐ, ๋‹จ์ง€ ์ง„์ •ํ•œ ๋ณด์ฆ์ž…๋‹ˆ๋‹ค. netlify๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ ˆ๋Œ€์ ์œผ๋กœ ์ž‘๋™ํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ฐœ์ธ์ ์œผ๋กœ ์—ฌ๋Ÿฌ ์‚ฌ์ดํŠธ์— ๋Œ€ํ•œ ์ฆ๊ฑฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ nextjs๊ฐ€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ฒ ์ €ํžˆ ์ดํ•ดํ•ด์•ผ ํ•˜๋ฉฐ netlify์—์„œ ์›ํ™œํ•˜๊ฒŒ ์‹คํ–‰๋˜๋„๋ก ๋ชจ๋“  ๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. nextjs ์‚ฌ์ดํŠธ๋ฅผ ์œ„ํ•œ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ํ™•์‹คํ•œ ํ˜ธ์ŠคํŒ…์„ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด zeit's ํ˜ธ์ŠคํŒ…์„ ์‹œ๋„ํ•ด ๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@jescalan ์ข‹์€ ๋‚˜๋ˆ” ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๐Ÿ™๐Ÿป

Publish directory ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ out ํด๋”๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Netlify์™€ ํ•จ๊ป˜ NextJS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ง€๊ธˆ์€ SSR์„ ์‚ฌ์šฉํ•˜์ง€ ๋ง๊ณ  next export ์‚ฌ์šฉํ•˜์—ฌ ์™„์ „ํžˆ ๊ณ ์ •ํ•˜์‹ญ์‹œ์˜ค.

@ScreamZ ์ด๊ฒƒ์€ ์ผ์ข…์˜ ์‚ฌ์‹ค์ด์ง€๋งŒ "์ „์ฒด ์ •์ " ์‚ฌ์ดํŠธ๋ฅผ ์ •ํ™•ํžˆ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋”ฐ๋ผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. zeit์˜ ํ˜ธ์ŠคํŒ… ์„œ๋น„์Šค๊ฐ€ ์žˆ๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€์— getStaticProps ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด next export ์‹คํ–‰ํ•˜์ง€ ์•Š๋”๋ผ๋„ ์‹ค์ œ๋กœ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์ •์  ์‚ฌ์ดํŠธ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค getStaticProps ๋Š” ์‚ฌ์ดํŠธ๊ฐ€ ๋ฐฐํฌ๋  ๋•Œ๋งŒ ๊ตฌ์ถ•๋˜๋ฉฐ ๊ทธ ์ดํ›„์—๋Š” CDN์—์„œ ์ง์ ‘ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

๋”” ์ฐจ์ด ํŠธ ์ตœ๊ทผ์— ์ด๋ ‡๊ฒŒ ํฌํ•จ ๋œ ์„ค์ • ์–ด๋–ค ์‚ฌ์ดํŠธ๊ฐ€ ์žˆ์Œ์„ ๋ณ€๊ฒฝ : ๊ฐ€์žฅ ํฐ ์ฐจ์ด์ ์€ ๋‚˜๋Š” ๋”” ์ฐจ์ด ํŠธ์˜ ํ˜ธ์ŠคํŒ…์— ์ •์ ์œผ๋กœ ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ๊ฐ•์ œ ํ•  ์ˆ˜์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ๋ฉ€๋ฆฌ๋กœ (ํŽธ์ง‘์ด๋‹ค exportPathMap ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค ์™„์ „ํžˆ ์ •์  ์‚ฌ์ดํŠธ์ด๋ฏ€๋กœ ๋” ์ด์ƒ ์‚ฌ์‹ค์ด ์•„๋‹™๋‹ˆ๋‹ค.) getStaticProps ๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€๋Š” next export ์˜ํ•ด ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€์™€ ์ •ํ™•ํžˆ ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํŽ˜์ด์ง€์˜ ๋‹จ์ผ ์ •์  ์‚ฌ๋ณธ์€ ๋ชจ๋“  ์กฐํšŒ์— ๋Œ€ํ•ด CDN์—์„œ ์ง์ ‘ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ getServerProps ๋˜๋Š” getInitialProps ์ผ๋ถ€ ํŽ˜์ด์ง€๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜๋„ ์žˆ์œผ๋ฉฐ ์„œ๋ฒ„ ๋ Œ๋”๋ง ํŽ˜์ด์ง€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ์ธ์ ์œผ๋กœ ์ €๋Š” ์ด๊ฒƒ์„ ์ด์ ์œผ๋กœ ๋ด…๋‹ˆ๋‹ค. SSR ๊ฒฝ๋กœ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋‹จ์ˆœํžˆ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ•ด๋‹น ๋‹จ์ผ ๊ฒฝ๋กœ๋Š” ์ด์ œ SSR์ด๊ณ  ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒฝ๋กœ๋Š” ์ •์ ์œผ๋กœ ์œ ์ง€๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@jescalan ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ด๊ฒƒ์ด ๊ตฌํ˜„๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋™์•ˆ ์ •์ ์— netlify๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

SSG ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ํŠนํžˆ ์šฐ๋ฆฌ๋Š” ๊ณต์œ  ๋นŒ๋“œ ์•„ํ‹ฐํŒฉํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€๋งŒ QA/์ œํ’ˆ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ ๊ตฌ์„ฑ์œผ๋กœ next export ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ ๊ฐ’์€ getStaticProps ์—์„œ๋งŒ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. serverRuntimeConfig ๋˜๋Š” publicRuntimeConfig ๋˜๋Š” process.env ์ง์ ‘ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?

@ScreamZ @jescalan ์ €๋Š” ์˜ค๋Š˜ @Timer ์™€ ํ•จ๊ป˜ Now์—์„œ ์ œ๋กœ ๊ตฌ์„ฑ next export ์ง€์›์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค (๊ทธ๋Š” ๋ชจ๋“  ํฌ๋ ˆ๋”ง์„ ๋ฐ›์„ ์ž๊ฒฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค). ๋„Œ ํ•  ์ˆ˜์žˆ์–ด:

"build": "next build && next export"

๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์€ ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”๐Ÿ™

๋„ค, ์ €๋Š” ์ง€์›์„ ์š”์ฒญํ•œ ์‚ฌ๋žŒ์ด์—ˆ๊ณ  ๊ทธ๋“ค์€ ์ด๊ฒƒ์ด ์•„์ง ๊ตฌํ˜„๋˜์—ˆ๋‹ค๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ˜… ์ œ๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋Š” ํ•œ, ๊ตฌ์„ฑ์—์„œ ๋‚ด๋ณด๋‚ด๊ธฐ ๋งต์„ ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@ScreamZ ์•„๋‹ˆ์š” ์œ„์— ํ‘œ์‹œ๋œ ๋Œ€๋กœ next build && next export ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

@timneutkens getInitialProps ๋ฅผ getServerProps ๋ฐ”๊พธ๋ฉด Server Pre Rendering ๋ฅผ ํ™œ์„ฑํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์„ฑ ํŒŒ์ผ์— target: 'serverless' ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๊ฐ์‚ฌ ํ•ด์š”.

์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด ๋ชจ๋“  ๋ฐฉ๋ฒ•์ด ํ˜„์žฌ ์ธ์‹๋˜๋ ค๋ฉด unstable_ ์ ‘๋‘์‚ฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ: unstable_getStaticProps

@timneutkens

@ScreamZ @jescalan ์ €๋Š” ์˜ค๋Š˜ @Timer ์™€ ํ•จ๊ป˜ Now์—์„œ ์ œ๋กœ ๊ตฌ์„ฑ next export ์ง€์›์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค (๊ทธ๋Š” ๋ชจ๋“  ํฌ๋ ˆ๋”ง์„ ๋ฐ›์„ ์ž๊ฒฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค). ๋„Œ ํ•  ์ˆ˜์žˆ์–ด:

"build": "next build && next export"

๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์€ ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”๐Ÿ™

๋‚ด ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ๋Š” ๋” ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์ง€๋งŒ ๋งค๋ ฅ์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

"build": "graphql codegen && next build && npm run export",

๊ฒŒ๋‹ค๊ฐ€ ๋Œ€๋‹จํ•ด! ๋‚ด๊ฐ€ ์ฐพ๋˜ ๋ฐ”๋กœ ๊ทธ๊ฑฐ์•ผ ๐Ÿ˜‚ (Goodbye GatsbyJS, ๋‚ด๊ฐ€ ๊ฐ€์žฅ ์ข‹์•„ํ•˜๋Š” ํ”„๋ ˆ์ž„ ์›Œํฌ๋Š” ์ด์ œ ๋‹น์‹ ๋งŒํผ ๊ฐ•๋ ฅํ•ฉ๋‹ˆ๋‹ค!)

๊ทธ๋Ÿฌํ•œ ๋ฐ˜์‘์— ๋Œ€ํ•ด ๋Œ€๋‹จํžˆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ €๋„ 9.1.6 ์—…๊ทธ๋ ˆ์ด๋“œํ–ˆ๋Š”๋ฐ ๋†€๋ž๊ฒŒ๋„
Screenshot 2019-12-21 at 19 25 43

๋‚˜๋Š” ๊ทธ ์“ฐ๋ ˆ๋“œ๊ฐ€ RFC๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ, ๊ทธ๊ฒƒ์€ ์ด๋ฏธ ์šฐ๋ฆฌ์—๊ฒŒ ์—ด๋ฆฐ ๊ฒƒ ๊ฐ™๋‹ค ์•„์•„, ๊ทธ๋ ‡์ง€?
๊ทธ๋Ÿฌ๋‚˜ Typescript ์œ ํ˜•์€ 9.1.6์—์„œ ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์  ์žฅ, ๋‚˜ ์ง€๊ธˆ ๋„ˆ๋ฌด ํฅ๋ถ„๋ผ! ๐Ÿคฃ

๋งˆ์ง€๋ง‰ ์งˆ๋ฌธ:

  • ๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์„ ์–ป๋Š”๋‹ค๋ฉด, getInitialProps ๋Š” ๋ฏธ๋ž˜์— ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ์—ฌ์ „ํžˆ ๊ด€๋ จ์„ฑ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด?
  • next export ๋Š” getStaticProps ๋ฐ next build ๋งŒ ์žˆ๋Š” ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•ด ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ข‹์€ ๋„๊ตฌ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค๐Ÿ™๐Ÿป

๋‚ด๊ฐ€ ๊ทธ๊ฒƒ์„ ์–ป๋Š”๋‹ค๋ฉด, getInitialProps๋Š” ๋ฏธ๋ž˜์— ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ์—ฌ์ „ํžˆ ๊ด€๋ จ์„ฑ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด?

์ดˆ๊ธฐ RFC์—์„œ ๋งํ–ˆ๋“ฏ์ด :

์ด RFC๋Š” API ์ถ”๊ฐ€์— ๋Œ€ํ•ด ๋…์ ์ ์œผ๋กœ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์€ ์ด์ „ ๋ฒ„์ „๊ณผ ์™„์ „ํžˆ ํ˜ธํ™˜๋˜๋ฉฐ ์ ์ง„์ ์œผ๋กœ ์ฑ„ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด RFC๋Š” ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ ์“ฐ๋ ˆ๋“œ๊ฐ€ RFC๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋Š”๋ฐ, ๊ทธ๊ฒƒ์€ ์ด๋ฏธ ์šฐ๋ฆฌ์—๊ฒŒ ์—ด๋ฆฐ ๊ฒƒ ๊ฐ™๋‹ค ์•„์•„, ๊ทธ๋ ‡์ง€?

๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ZEIT ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—์„œ ๊ทธ๊ฒƒ์„ ์‹œ๋„ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ๊ฐ€์‹œ์„ฑ ํ‘œ๋ฉดํ™”์˜ ์ผ๋ถ€๋Š” ์ด๋ฏธ ์ฐฉ๋ฅ™ํ–ˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ๋ณธ ํŽ˜์ด์ง€ ํŠธ๋ฆฌ).

๋‹ค์Œ ๋‚ด๋ณด๋‚ด๊ธฐ๋Š” getStaticProps ๋ฐ ๋‹ค์Œ ๋นŒ๋“œ๋งŒ ์žˆ๋Š” ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•ด ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋งž์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ next export ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด์ „ ๋ฒ„์ „๊ณผ์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ์œ ์ง€๋˜์ง€๋งŒ ์ผ๋ฐ˜์ ์œผ๋กœ API ๊ฒฝ๋กœ์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๊ณ  ์ผ๋ถ€ ํŽ˜์ด์ง€์— ๋Œ€ํ•ด ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์„ ์„ ํƒํ•˜์—ฌ ๋‚ด๋ณด๋‚ด๊ธฐ์˜ ๋ชจ๋“  ์ด์ ์„ ์ œ๊ณตํ•˜๋ฏ€๋กœ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•ฑ์„ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ด ๋ชจ๋“  ๋ฐฉ๋ฒ•์ด ํ˜„์žฌ ์ธ์‹๋˜๋ ค๋ฉด unstable_ ์ ‘๋‘์‚ฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ: unstable_getStaticProps

์•„์ง ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์‹คํ—˜์ ์ด๋ฉฐ ๋ฆด๋ฆฌ์Šค ์‚ฌ์ด์— ์ค‘๋‹จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ €๋Š” ์ด ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ๋†€์•˜๊ณ  ํŽ˜์ด์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” JSON ํŒŒ์ผ์€ ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ SSG ํŽ˜์ด์ง€์— ์•ก์„ธ์Šคํ•œ ํ›„ ํ•ญ์ƒ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์„ ๊ด€์ฐฐํ–ˆ์Šต๋‹ˆ๋‹ค.

JSON ํŒŒ์ผ์— ๋Œ€ํ•œ ์‚ฌ์ „ ๋กœ๋“œ ์ตœ์ ํ™” ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ?
์•„๋งˆ๋„ ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋ ค๊ณ  ํ•  ๋•Œ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•˜๊ฑฐ๋‚˜(์ฆ‰, ์‚ฌ์šฉ์ž๊ฐ€ SSG ๋งํฌ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์„ ๋•Œ) ๋งํฌ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์ฐธ์กฐ๋˜๋Š” ๋‹ค๋ฅธ js ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฑด ๊ทธ๋ ‡๊ณ  ๊ทธ ๊ธฐ๋Šฅ์„ ์‚ฌ๋ž‘ ํ•ด์š”!

JSON ํŒŒ์ผ์— ๋Œ€ํ•œ ์‚ฌ์ „ ๋กœ๋“œ ์ตœ์ ํ™” ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ.

๊ทธ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ €๋Š” ๋ณ„๋„์˜ ํŒŒ์ผ๋ณด๋‹ค๋Š” ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜์˜ ํŠธ๋ฆฌ ํ”๋“ค๋ฆผ ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์˜ ์ƒํƒœ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๊ทธ๊ฒƒ์˜ ์ฐจ๋‹จ์ œ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@mikestopcontinues ์ด RFC๋Š” ํ˜„์žฌ ์šฐ๋ฆฌ ํŒ€๊ณผ ์ผ๋ถ€ ์„ ๋ณ„๋œ ํŒŒํŠธ๋„ˆ์— ์˜ํ•ด ๋‚ด๋ถ€์ ์œผ๋กœ ๊ณผ์ค‘ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ unstable_ ์ ‘๋‘์‚ฌ ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ ๋„๋กœ ์‹คํ—˜์ ์ธ ๋™์ž‘ ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ˜„

API๋ฅผ ๊ณ„์†ํ•ด์„œ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํ”„๋กœ๋•์…˜ ์›Œํฌ๋กœ๋“œ๋ฅผ ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.

๊ฐœ์ธ์ ์œผ๋กœ 8~20K ํŽ˜์ด์ง€์˜ ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(์ผ๋ถ€ ํŽ˜์ด์ง€์— ๋™์  ์š”์ฒญ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Œ). ๋งค์šฐ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค(Now์˜ 10K ํŒŒ์ผ ์ œํ•œ ์ œ์™ธ). ๋‚ด๊ฐ€ ๋ถ€๋„๋Ÿฝ๊ฒŒ ์ƒ๊ฐํ•˜๋Š” ์œ ์ผํ•œ ๊ฒƒ์€ getStaticPaths ๋ฉ”์„œ๋“œ๊ฐ€ ์—†์œผ๋ฉด ๋‹ค์‹œ ๋กœ๋“œํ•  ๋•Œ๋งˆ๋‹ค getStaticProps๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ข‹์€ ๋™์ž‘ ์ค‘ ํ•˜๋‚˜๋Š” ์ฒซ ๋ฒˆ์งธ ํ˜ธ์ถœ์—์„œ json ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋‹ค์Œ ํ˜ธ์ถœ์—์„œ ์ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฆ๋ถ„ ๋นŒ๋“œ๊ฐ€ ๊ณ„ํš๋˜์–ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ž˜์„œ ์ƒˆ๋กœ์šด/๋ณ€๊ฒฝ๋œ ์ฝ˜ํ…์ธ ๋งŒ ์žฌ๊ตฌ์ถ•๋ฉ๋‹ˆ๊นŒ?

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ unstable_ ์ ‘๋‘์‚ฌ ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ ๋„๋กœ ์‹คํ—˜์ ์ธ ๋™์ž‘ ์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

unstable_getServerProps ๋ฉ”์„œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹ถ์ง€๋งŒ ํ˜„์žฌ๋กœ์„œ๋Š” ๋ฌด์‹œ๋˜๊ณ  zeit/next.js ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์•„์ง ๊ตฌํ˜„๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์ œ๊ฐ€ ์ž˜๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์ฆ๋ถ„ ๋นŒ๋“œ๊ฐ€ ๊ณ„ํš๋˜์–ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ž˜์„œ ์ƒˆ๋กœ์šด/๋ณ€๊ฒฝ๋œ ์ฝ˜ํ…์ธ ๋งŒ ์žฌ๊ตฌ์ถ•๋ฉ๋‹ˆ๊นŒ?

๊ตฌํ˜„์€ ์ฆ๋ถ„ ์žฌ๊ตฌ์ถ•์„ ์—ผ๋‘์— ๋‘๊ณ  ์„ค๊ณ„๋˜์—ˆ์ง€๋งŒ ์•„์ง ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(์ด RFC์—์„œ๋„ ๋‹ค๋ฃจ์ง€ ์•Š์Œ).

์•ˆ์‹ฌํ•˜์‹ญ์‹œ์˜ค. ์•„ํ‚คํ…์ฒ˜๊ฐ€ ์ค€๋น„๋˜์—ˆ์œผ๋ฉฐ ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์ด ์•ˆ์ •ํ™”๋œ ํ›„ ์ด๋ฅผ ํƒ์ƒ‰ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด๊ฒƒ์ด getStaticProps ๊ฐ€ ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด ํ•œ ๋ฒˆ์ด ์•„๋‹ˆ๋ผ ํŽ˜์ด์ง€๋‹น ์ •์˜๋˜๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค!

๋ถˆ์•ˆ์ •ํ•œ_getServerProps ๋ฉ”์„œ๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹ถ์ง€๋งŒ ํ˜„์žฌ๋กœ์„œ๋Š” ๋ฌด์‹œ๋˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค [...]

getServerProps ์€(๋Š”) ์•„์ง ๋ฏธ๋ฆฌ ๋ณด๊ธฐ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

getServerProps ์€(๋Š”) ์•„์ง ๋ฏธ๋ฆฌ ๋ณด๊ธฐ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ํ™•์‹คํžˆ ์ด ์Šค๋ ˆ๋“œ๋ฅผ ๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ทธ ๋•…์— ๋„์ฐฉํ•˜๋ฉด ๋‹จ์ผ ํ•จ์ˆ˜์˜ ์ด๋ฆ„์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ์œผ๋กœ ๋Œ€์ฒดํ•  ์ˆ˜ ์žˆ๋Š” _๋‹ค๋ฐœ_ ์ฝ”๋“œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค! ๐Ÿ˜

getServerProps / getStaticProps ๋ฅผ ํ˜„์žฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€๋Š” 100% ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ์Šค๋ ˆ๋“œ ๊ธฐ๋ฐ˜: ์•„๋‹ˆ์š”

๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋ ‡๋‹ค๋ฉด next build ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ๋‚ด ํ„ฐ๋ฏธ๋„์ด ์•„์ง ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ์ด๋ฅผ ์–ธ๊ธ‰ํ•œ ์ด์œ ๊ฐ€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๊ณ  ์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•์ด ํ”„๋กœ๋•์…˜ ๋‹จ๊ณ„์— ์žˆ๋‹ค๋Š” ์ดˆ๊ธฐ ์ž‘์—… ๊ฐ€์ •์ด ๋‚จ์•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ์ด์œ ๊ฐ€ ๊ถ๊ธˆํ•˜๊ฑฐ๋‚˜ ์ œ๊ฐ€ ์ž˜๋ชป ์ดํ•ดํ•˜๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

ฮป  (Server)  server-side renders at runtime (uses getInitialProps or getServerProps)
โ—‹  (Static)  automatically rendered as static HTML (uses no initial props)
โ—  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

(๋‹ค์Œ ๋ฒ„์ „ 9.1.6์—์„œ)

๊ฐ์‚ฌ ํ•ด์š”

@stevenjchang pages/**/*.js ์—์„œ ๋‹ค์Œ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export function unstable_getStaticPaths() {} // return [{params: {...}}, ...]
export function unstable_getStaticProps({params: {...}) {} // return {props: {...}}

๊ทธ๋ฆฌ๊ณ  ์ถ”๊ฐ€ํ•ด์•ผ ํ•  ๊ฒƒ์€ ํ›Œ๋ฅญํ•˜์ง€๋งŒ dev ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์—ฌ์ „ํžˆ ๊ฐ€์žฅ์ž๋ฆฌ๊ฐ€ ์•ฝ๊ฐ„ ๊ฑฐ์น ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

dev ์„œ๋ฒ„๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์—ฌ์ „ํžˆ ๊ฐ€์žฅ์ž๋ฆฌ๊ฐ€ ์•ฝ๊ฐ„ ๊ฑฐ์น ์ง€๋งŒ.
@mikestopcontinues

์ด์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ๋‹ค๋ฅธ ๋ˆ„๊ตฌ๋„ dev ์„œ๋ฒ„ ๊ฒฝํ—˜์— ๋Œ€ํ•ด ๋ถ€์ •์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜์ง€ ์•Š์•˜์œผ๋ฉฐ ์šฐ๋ฆฌ๋Š” ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค!

@Timer ์ƒˆ๋กœ์šด API๊ฐ€ ์ •๋ง ๋งˆ์Œ์—

"๋ชจ๋“  ๋กœ๋“œ ์‹œ"๋Š” ํŽ˜์ด์ง€ ๋กœ๋“œ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์žฌ๊ฑด? ๋˜๋Š”...?

@mmmeff ๊ฐ™์€ ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•  ๋•Œ๋งˆ๋‹ค json์„ ๋‹ค์‹œ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋‘ ํŽ˜์ด์ง€ ์‚ฌ์ด๋ฅผ ์•ž๋’ค๋กœ ํด๋ฆญํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋ฐ ๋งŽ์€ ์‹œ๊ฐ„์„ ํ• ์• ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

@mikestopcontinues ์ด๊ฒƒ์€ ๊ฐ€์žฅ ์ตœ์‹  ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐœ๋ฐœ ๋‹จ๊ณ„์—์„œ ์„ ํ˜ธ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๊ธฐ ๋•Œ๋ฌธ์— ์˜๋„๋œ ๋™์ž‘์ž…๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฌธ์ œ์—์„œ ๋” ๋‚˜์€ ๋ฐœ๊ฒฌ์  ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋…ผ์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

@timneutkens ์ด RFC๋Š” ๋งค์šฐ ์œ ๋งํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋ณด์•ˆ๊ณผ ์ •ํ™•ํžˆ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ์งˆ๋ฌธ/์šฐ๋ ค ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

SSR๊ณผ SSG ๋ชจ๋‘์— ์˜์กดํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋น„์ฆˆ๋‹ˆ์Šค ์‚ฌ๋ก€๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฌธ๋งฅ

์šฐ๋ฆฌ๋Š” ์›น์‚ฌ์ดํŠธ(์ผ๋ช… "์•ฑ")์— ์ผ๋ถ€ ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.
์ด๋Ÿฌํ•œ ์ •๋ณด๋Š” GraphQL API๋ฅผ ํ†ตํ•ด ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋Š” BDD์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.
์ด๋Ÿฌํ•œ ์ •๋ณด ์ค‘ ์ผ๋ถ€๋Š” ๊ณต๊ฐœ๋˜๊ณ  ์ผ๋ถ€๋Š” ๋น„๊ณต๊ฐœ์ž…๋‹ˆ๋‹ค(์˜ˆ: ์‚ฌ์šฉ์ž ์ด๋ฉ”์ผ/๋น„๋ฐ€๋ฒˆํ˜ธ).

์•ฑ์€ ๋‘ ๋‹จ๊ณ„๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ๊ณ ๊ฐ์ด ์Šคํ…Œ์ด์ง• ์•ฑ์—์„œ ์‹ค์‹œ๊ฐ„ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š” "์Šคํ…Œ์ด์ง•" ๋‹จ๊ณ„(๋ฐฑ์˜คํ”ผ์Šค ๋“ฑ์„ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธํ•จ)
  • ๊ณ ๊ฐ์ด ์•ก์„ธ์Šค ๊ถŒํ•œ์ด ์—†๊ณ  ์Šค์Šค๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์—†๋Š” "ํ”„๋กœ๋•์…˜" ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ์•ฑ์„ ์—…๋ฐ์ดํŠธํ•˜๋ ค๋ฉด ์ƒˆ๋กœ ๋ฐฐํฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. (๋ฐฑ์˜คํ”ผ์Šค์—์„œ ์ƒˆ๋กœ์šด ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ๋ฅผ ์š”์ฒญํ•จ)

์ด ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” SSR๊ณผ SSG๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • ์Šคํ…Œ์ด์ง• ์•ฑ์€ GraphQL API์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์— SSR์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค(ํŽ˜์ด์ง€ ๋นŒ๋“œ ์‹œ).
  • ํ”„๋กœ๋•์…˜ ์•ฑ์€ SSG๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ฐฐํฌ๊ฐ€ ์ด๋ฃจ์–ด์ง€๋ฉด GraphQL API์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ •์  ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋Ÿฐํƒ€์ž„ ์‹œ(์ ์–ด๋„ ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•  ๋•Œ๋Š” ์•„๋‹˜))

์ด ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์ถฉ๋ถ„ํžˆ ์ผ๋ฐ˜์ ์ด์–ด์•ผ ํ•˜๋ฉฐ (IMHO) SSG ์‚ฌ์šฉ์˜ ์ฃผ์š” ์‚ฌ์šฉ ์‚ฌ๋ก€ ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ํ”„๋กœ๋•์…˜ ์•ฑ์€ ์Šคํ…Œ์ด์ง• ์•ฑ์˜ ์Šค๋ƒ…์ƒท์— ๋ถˆ๊ณผํ•ฉ๋‹ˆ๋‹ค.

๋ช‡ ๊ฐ€์ง€ ์งˆ๋ฌธ:

  1. ์ด RFC๋กœ ๊ฐ€๋Šฅ ํ•ฉ๋‹ˆ๊นŒ? ๋™์ผํ•œ ์•ฑ์ด ์ฃผ์–ด์ง„ "๋‹จ๊ณ„"(ํ”„๋กœ๋•์…˜/์Šคํ…Œ์ด์ง•)์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ
  2. GraphQL API์—์„œ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋Š” ์–ด๋–ป๊ฒŒ ์ฃผ์ž…๋ฉ๋‹ˆ๊นŒ?

    • ์Šคํ…Œ์ด์ง•์—์„œ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ํƒ์ƒ‰ํ•  ๋•Œ SSR ๋˜๋Š” CSR์„ ํ†ตํ•ด ๋™์ ์œผ๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค(CSR ์ค‘์— ๊ฐ€์ ธ์˜จ ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ).

    • ํ”„๋กœ๋•์…˜์—์„œ๋Š” ๋นŒ๋“œ ์‹œ ๊ฐ€์ ธ์˜ค์ง€๋งŒ JS ์ „์—ญ ๋ณ€์ˆ˜์— ์ €์žฅ๋˜๋ฏ€๋กœ ๋ˆ„๊ตฌ๋‚˜ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? (๋ณด์•ˆ ๋ฌธ์ œ, CSR์„ ์‚ฌ์šฉํ•  ๋•Œ ์ˆ˜ํ–‰๋˜๋Š” ๋ฐฉ์‹๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•จ)

  3. ํ˜ผํ•ฉ SSR/SSG๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด ์ ‘๊ทผ ๋ฐฉ์‹์— ๋Œ€ํ•ด ์šฐ๋ ค ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๊นŒ? (๋ณด์•ˆ, ์„ฑ๋Šฅ, ์œ ์ง€๋ณด์ˆ˜์„ฑ ๋“ฑ)

์ด๊ฑฐ ์–ธ์ œ ์ถœ์‹œํ•  ์˜ˆ์ •์ธ๊ฐ€์š”? ์ฃผ์š” ์—…๋ฐ์ดํŠธ(v10)๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์ด์ „ ๋ฒ„์ „๊ณผ ํ˜ธํ™˜๋˜๋Š” ์—…๋ฐ์ดํŠธ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๊นŒ?

์ด๋ด,

์‚ฌ์šฉ์ž ์ •์˜ ์„œ๋ฒ„๋กœ ์ด ์†”๋ฃจ์…˜์„ ์‹œ๋„ํ•˜๊ณ  ์ž‘๋™์‹œํ‚ค๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ์‹œ:

// server.js

const express = require('express');
const next = require('next');

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = express();

  server.get('/blog/:id', (req, res) => {
    console.log('My params needed be passed to page:', req.params);
    return app.render(req, res, '/blogDetail', { id: req.params.id });
  });

  server.listen(port, err => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${port}`);
  });
});

// blogDetail.js
export async function unstable_getStaticProps(props) {
  console.log('What is passed', props);

  return {};
}

const BlogPostPage = ({ post }) => {
  return <div>Hey</div>;
}

export default BlogPostPage;
# Terminal output

My params needed be passed to page: { id: 'test' }
What is passed { params: undefined }

getStaticProps ์— ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ ํฌํ•จํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ํ˜„์žฌ ๋‹ค์‹œ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ  ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด SSR์„ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•˜๋Š” ํŽ˜์ด์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. useRouter ํ›„ํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฟผ๋ฆฌ๊ฐ€ ์ฒ˜์Œ์— ๋นˆ ๊ฐœ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ๋ฒˆ ๋‹ค์‹œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ „ํ™˜ ์ถ”์ ์— ์‚ฌ์šฉ๋˜๋Š” ํŽ˜์ด์ง€์ด๋ฏ€๋กœ ๋‹น์—ฐํžˆ ์‹œ์ž‘ ๋‹จ๊ณ„๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

@pjaws RFC๋Š” getStaticProps ๊ฐ€ ์ •์  ์ƒ์„ฑ์„ ์œ„ํ•œ ๊ฒƒ์ด๋ผ๊ณ  ๊ตฌ์ฒด์ ์œผ๋กœ ์–ธ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค. ์ •์  HTML์€ ์ฟผ๋ฆฌ ๋ฌธ์ž์—ด์„ ๋ฐ›์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ๋™์  URL ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ˆ˜์‹ ํ•  ์ˆ˜ ์žˆ๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๊ทธ๊ฒŒ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ๊ฐ€์š”?

2020๋…„ 1์›” 14์ผ ํ™”์š”์ผ ์˜ค์ „ 1์‹œ 30๋ถ„ Tim Neutkens [email protected]
์ผ๋‹ค:

@pjaws https://github.com/pjaws ํŠน๋ณ„ํžˆ ์–ธ๊ธ‰ํ•˜๋Š” RFC
getStaticProps๋Š” ์ •์  ์ƒ์„ฑ์„ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ •์  HTML์€ ์ˆ˜์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
์ฟผ๋ฆฌ ๋ฌธ์ž์—ด.

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธ
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=AMVRRIQCKDJNF4MPWSLYNV3Q5WA2NA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVREXG43VMXHJ63LDNMV
๋˜๋Š” ๊ตฌ๋… ์ทจ์†Œ
https://github.com/notifications/unsubscribe-auth/AMVRRIRJXLYC4MC4U7DH7NDQ5WA2NANCNFSM4JRPBELQ
.

getStaticPaths ์—์„œ๋Š” ๋นŒ๋“œ ์‹œ ๋ Œ๋”๋ง๋  ํŽ˜์ด์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ณ€ํ™”๋Š” ์–ธ์ œ๋‚˜์ฒ˜๋Ÿผ ๋งค์šฐ ์œ ๋งํ•˜๊ณ  ํ›Œ๋ฅญํ•œ ์ž‘์—…์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค! ๐Ÿ‘

ํŽ˜์ด์ง€ ๊ฐ„์— ๊ณต์œ ๋˜๋Š” ๋ฐ์ดํ„ฐ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด getInitialProps in _app.js ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ(์˜ˆ: ์ปจํ…์ŠคํŠธ ์ œ๊ณต์ž ์„ค์ •)์— ๋Œ€ํ•ด ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ getStaticProps ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ๊ฐœ๋ณ„ ํŽ˜์ด์ง€์—์„œ๋งŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

ํŽ˜์ด์ง€ ๊ฐ„์— ๊ณต์œ ๋˜๋Š” ๋ฐ์ดํ„ฐ ์š”๊ตฌ ์‚ฌํ•ญ(์˜ˆ: ์ปจํ…์ŠคํŠธ ๊ณต๊ธ‰์ž ์„ค์ •)์„ ์ถฉ์กฑํ•˜๊ธฐ ์œ„ํ•ด _app.js์— getInitialProps๊ฐ€ ์žˆ๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. getStaticProps๋ฅผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ๊ฐœ๋ณ„ ํŽ˜์ด์ง€์—์„œ๋งŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋งž์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ๊ฐœ๋ณ„ ํŽ˜์ด์ง€์—๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ๋‹ค์‹œ ์ƒ๊ฐํ•ด ๋ณผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. _app์˜ getInitialProps๋Š” ์ •์  HTML๋กœ ๋‚ด๋ณด๋‚ผ ๋•Œ ๊ณ„์† ํ˜ธ์ถœ๋˜๋ฏ€๋กœ getStaticProps๋กœ ์ ์ง„์ ์œผ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„, ๊ด€๋ จ ์งˆ๋ฌธ ํ•˜๋‚˜ - ์ž์‚ฐ์€ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๊นŒ? ํ—ค๋“œ๋ฆฌ์Šค CMS(์‹ฌ์ง€์–ด wordpress ๋˜๋Š” graphcms ๋“ฑ)๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ž์‚ฐ URL์ด ์ •์  html์—์„œ ์‚ฌ์šฉ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์ง€๊ธˆ ๋ณด๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—๋Š” ์ž์‚ฐ ๋งํฌ๊ฐ€ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋‘ ๊ฐ€์ง€ ๊ธฐ๋ณธ ์„ค์ •์ด ์žˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๋” ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค. ์ž์‚ฐ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  html์„ ๋นŒ๋“œ(๋กœ์ปฌ๋กœ ๋งํฌ)ํ•œ ๋‹ค์Œ ์•ž์— CDN์„ ๊ณ„์ธตํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํ›จ์”ฌ ๋” ์ˆ˜์šฉ ๊ฐ€๋Šฅํ•œ ๊ด€ํ–‰์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๋˜ํ•œ Netlify์™€ ๊ฐ™์€ ๋ฐฐํฌ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ๋„ ๋งค์šฐ ์ž˜ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. Netlify๋Š” DatoCMS ๋˜๋Š” Graphcms์™€ ๊ฐ™์€ ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๋” ์ ํ•ฉํ•œ ์ „ ์„ธ๊ณ„์ ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ธํ”„๋ผ๋ฅผ ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Netlify๋ฅผ ๋ฐฐํฌ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ Netlify ๋„๋ฉ”์ธ์—์„œ ๋ชจ๋“  ๊ฒƒ์ด ์ œ๊ณต๋˜๊ณ  ๋งˆ๋ฒ•์ด ์ž‘๋™ํ•˜๋„๋ก ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

@sandys https://github.com/zeit/next.js/issues/9054#issuecomment -570427085์—์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ–ˆ๋‹ค๋ฉด ์ž์‚ฐ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  .next/static ์•„๋ž˜์— ์ €์žฅํ•˜๊ณ  ๋งํฌ๋ฅผ ๊ตฌ์ถ•ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. getStaticProps ์žˆ์Šต๋‹ˆ๋‹ค.

์ •์  API ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋‹ค๋Š” ์•„์ด๋””์–ด๋„ ์žˆ์ง€๋งŒ ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ € ์บ์‹ฑ ๋™์ž‘์„ ์ œ์–ดํ•˜๋Š” โ€‹โ€‹๋ฐฉ๋ฒ•์„ ์ •ํ™•ํžˆ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

@Janpot ๋งํฌ

์ด ๊ธฐ๋ณธ ์ œ๊ณต์— ๋‚ด ์š”์ฒญ์„ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค. ์•„๋งˆ๋„ #9054๊ฐ€ ๋” ์ผ๋ฐ˜์ ์ด์ง€๋งŒ SSG์˜ ๊ด€์ ์—์„œ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ด๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

์–ธ๊ธ‰ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์—ˆ์ง€๋งŒ ์ž์‚ฐ ํ•ด์‹ฑ๋„ SSG์— ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค.

@homoky , ๊ทธ ๋™์•ˆ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๊นŒ?

@homoky , ๊ทธ ๋™์•ˆ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๊นŒ?

๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ  ๊ณ„ํš๋„ ์—†์Šต๋‹ˆ๋‹ค: #10071

๐Ÿ˜ข

@sandys ์‹ค์ œ๋กœ ์†”๋ฃจ์…˜์€ https://github.com/zeit/next.js/issues/9081 ์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ๋ฅผ ๋“ค์–ด /images ์—์„œ CMS๋กœ ์žฌ์ž‘์„ฑ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ํ›จ์”ฌ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ: ZEIT์—์„œ ์ด์ œ ์˜ฌ๋ฐ”๋ฅธ ํ—ค๋”๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฏธ ์บ์‹œํ•˜๋ฏ€๋กœ ์ถ”๊ฐ€ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋นŒ๋“œ ์‹œ ๋ง‰๋Œ€ํ•œ ์˜ค๋ฒ„ํ—ค๋“œ).

@timneutkens ๋‹ต๋ณ€
๋‹น์‹ ์ด ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋ฅผ ์™„์ „ํžˆ ํ™•์‹ ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” netlify๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. CMS URL์„ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๊ณ  ๊ทธ ์œ„์— CDN ๋ ˆ์ด์–ด๋ฅผ ์•ž์— ๋‘๋ผ๋Š” ์ œ์•ˆ์ž…๋‹ˆ๊นŒ?
netlify(์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ํด๋ผ์šฐ๋“œํ”„๋ก ํŠธ)๊ฐ€ ์ด๋Ÿฌํ•œ ๋ชจ๋“  ์„œ๋น„์Šค์™€ ์›ํ™œํ•˜๊ฒŒ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€๊ฐ€ ๋‹ค์šด๋กœ๋“œ๋˜์–ด ๋ฐฐํฌ์˜ ์ผ๋ถ€๊ฐ€ ๋˜๋ฉด ์ด ์ „์ฒด ๋ฌธ์ œ๊ฐ€ ํฌ๊ฒŒ ๋‹จ์ˆœํ™”๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ URL(๋‚ด ๊ฒฝ์šฐ์—๋Š” s3์—์„œ ์ œ๊ณต๋จ)์—์„œ ์บ์‹œํ•˜๋„๋ก CDN์„ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

Zeit NOW๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ท€ํ•˜์˜ ์†”๋ฃจ์…˜์ด ์ €์—๊ฒŒ ๊ทผ๊ฑฐํ•œ ๊ฒƒ์ธ์ง€ ์™„์ „ํžˆ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด๋ฏธ์ง€๊ฐ€ ๋‹ค์šด๋กœ๋“œ๋˜์–ด ๋ฐฐํฌ์˜ ์ผ๋ถ€๊ฐ€ ๋˜๋ฉด ์ด ์ „์ฒด ๋ฌธ์ œ๊ฐ€ ํฌ๊ฒŒ ๋‹จ์ˆœํ™”๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ URL(๋‚ด ๊ฒฝ์šฐ์—๋Š” s3์—์„œ ์ œ๊ณต๋จ)์—์„œ ์บ์‹œํ•˜๋„๋ก CDN์„ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค๋ฅผ ํ›จ์”ฌ ๋” ๋ณต์žกํ•˜๊ณ  10๋ฐฐ ๋” ๋Š๋ฆฌ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ํ™•์‹คํžˆ ๋‹จ์ˆœํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

Zeit NOW๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ท€ํ•˜์˜ ์†”๋ฃจ์…˜์ด ์ €์—๊ฒŒ ๊ทผ๊ฑฐํ•œ ๊ฒƒ์ธ์ง€ ์™„์ „ํžˆ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ „ ์„ธ๊ณ„์˜ ๋ชจ๋“  ํ”„๋ก์‹œ์™€ ํ•จ๊ป˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์šฐ๋“œ ํ”„๋ก ํŠธ ํฌํ•จ.

@timneutkens ์šฐ๋ฆฌ๋Š” ์‹ค์ œ๋กœ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ์‹œ๊ฐ„์— ๋ถˆ๊ฐ€์ง€๋ก ์ ์ž…๋‹ˆ๋‹ค. ๋” ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋”๋ผ๋„ ์ƒ๊ด€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ด์œ ๋กœ(์•Œ๋ ค์ง„ ๊ธฐ๋ณธ URL์—์„œ ์ œ๊ณต๋˜๋Š” ๋ชจ๋“  ์ž์‚ฐ์„ ํฌํ•จํ•˜์—ฌ) ์ด๋ฅผ ๋นŒ๋“œ์—์„œ ๊ตฝ๋Š” ๊ฒƒ์ด ๋งค์šฐ ๋ฐ”๋žŒ์งํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์‚ฌ๋žŒ์„ ์œ„ํ•ด ์ด ๊ธฐ๋Šฅ์„ ์ผœ์•ผ ํ•œ๋‹ค๊ณ  ์ฃผ์žฅํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด CMS๋กœ์˜ ๋”ฅ๋งํ‚น์— ๋งŒ์กฑํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์€ ์‚ฌ์ดํŠธ๋ฅผ ์šด์˜ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์ด๊ฒƒ์€ ํ™•์‹คํžˆ ์šฐ๋ฆฌ์™€ ๊ฐ™์€ ์‚ฌ์ดํŠธ์— ํ•„์š”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ ๋‚˜๋ฅผ ์šฉ์„œํ•˜์ง€๋งŒ ๋‚˜๋Š” ๋‹น์‹ ์˜ ํ•ด๊ฒฐ์ฑ…์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? CMS๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” URL์„ ์ œ์–ดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, Datocms๋Š”์—์„œ ์ œ๊ณต ์‹œ์ž‘ www.datocms-assets.com/ . #9081์˜ ์†”๋ฃจ์…˜์„ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๊นŒ?

์šฐ๋ฆฌ๋Š” ์‹ค์ œ๋กœ ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ์‹œ๊ฐ„์— ๋ถˆ๊ฐ€์ง€๋ก ์ ์ž…๋‹ˆ๋‹ค. ๋” ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋”๋ผ๋„ ์ƒ๊ด€์—†์–ด

์ด๊ฒƒ์€ ๊ท€ํ•˜์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ํ•ด๋‹น๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—๋Š” ํ•ด๋‹น๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ด์œ ๋กœ(์•Œ๋ ค์ง„ ๊ธฐ๋ณธ URL์—์„œ ์ œ๊ณต๋˜๋Š” ๋ชจ๋“  ์ž์‚ฐ์„ ํฌํ•จํ•˜์—ฌ) ์ด๋ฅผ ๋นŒ๋“œ์—์„œ ๊ตฝ๋Š” ๊ฒƒ์ด ๋งค์šฐ ๋ฐ”๋žŒ์งํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ๋งํ•œ ๋Œ€๋กœ์ผ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. /images/* ๋ฅผ cms URL๋กœ ํ”„๋ก์‹œํ•˜๋Š” ์žฌ์ž‘์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ www.datocms-asset.com/* ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ). ๊ทธ๋Ÿฐ ๋‹ค์Œ /images ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ์ด๋ฏธ์ง€๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚˜๊ธฐ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

@sandys ์‹ค์ œ๋กœ ์†”๋ฃจ์…˜์€ #9081์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ๋ฅผ ๋“ค์–ด /images์—์„œ CMS๋กœ ๋‹ค์‹œ ์“ฐ๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ ํ›จ์”ฌ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ: ZEIT์—์„œ ์ด์ œ ์˜ฌ๋ฐ”๋ฅธ ํ—ค๋”๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๊ฒฐ๊ณผ๋ฅผ ์ด๋ฏธ ์บ์‹œํ•˜๋ฏ€๋กœ ์ถ”๊ฐ€ ๋‹ค์šด๋กœ๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋นŒ๋“œ ์‹œ ๋ง‰๋Œ€ํ•œ ์˜ค๋ฒ„ํ—ค๋“œ).

@timneutkens ๋‚˜๋ฅผ ์œ„ํ•ด ๋ช…ํ™•ํ•˜๊ฒŒํ•˜๊ธฐ ์œ„ํ•ด. ์ด์ƒ์ ์ธ ์ƒํ™ฉ์—์„œ๋Š” ์ด๋ฏธ์ง€๋ฅผ ํ•ด์‹œํ•˜๊ณ  ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ณ ์œ ํ•œ URL๋กœ ์˜๊ตฌ์ ์œผ๋กœ ์บ์‹œํ•˜๊ณ  ์ฝ˜ํ…์ธ  ์ž‘์„ฑ์ž๋Š” CMS์—์„œ ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ์›ํ•  ๋•Œ๋งˆ๋‹ค ํŒŒ์ผ์„ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ œ์•ˆํ•œ ์„ค์ •์—์„œ CMS๊ฐ€ ๋‹ค์Œ์„ ๋‹ด๋‹นํ•ด์•ผ ํ•จ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  1. ์ด๋ฏธ์ง€ ์ตœ์ ํ™”
  2. ์ด๋ฏธ์ง€๋ฅผ ํ•ด์‹ฑํ•˜๊ณ  ์ด ํ•ด์‹œ๋กœ ์ œ๊ณต
  3. ์ด๋ฏธ์ง€ URL์—์„œ getStaticProps ์—์„œ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋Š” ํ•ด์‹œ๋œ ์ด๋ฏธ์ง€ URL๋กœ์˜ ๋งต์„ ์ œ๊ณตํ•˜์—ฌ ์ด๋ฏธ์ง€ URL์„ CMS์˜ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ๋Œ€์‘๋ฌผ์— ๋‹ค์‹œ ๋งคํ•‘ํ•ฉ๋‹ˆ๋‹ค.

๋ถˆ๊ฐ€๋Šฅํ•˜์ง€๋Š” ์•Š์€ ๊ฒƒ ๊ฐ™์•„์š”. ์ด๊ฒƒ์ด ์ œ์•ˆ๋œ ์„ค์ •์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์‹ถ์„ ๋ฟ์ž…๋‹ˆ๋‹ค.

@Janpot CMS ์ œ๊ณต์—…์ฒด๋Š” ์ด๋ฏธ ์ด๋ฏธ์ง€ ๋“ฑ์— ๊ณ ์œ ํ•œ URL์„ ์ œ๊ณตํ•˜์—ฌ ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ๊ท€ํ•˜์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ํ•ด๋‹น๋  ์ˆ˜ ์žˆ์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—๋Š” ํ•ด๋‹น๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๋‚˜๋Š” ์—ฌ๊ธฐ ํ˜ผ์ž๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋น„์Šทํ•œ ์š”์ฒญ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹น์‹ ์ด ์ด๊ฒƒ์„ ๊ณ ๋ คํ•˜๊ธฐ๋ฅผ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

https://spectrum.chat/next-js/general/how-would-you-handle-importing-remote-images-on-nextjs-static-export~30b2ba84-bc27-4da7-9ec8-21e4d5d287a3

๊ฐœ์ธ ๋น„ ์ธก์—์„œ๋„ - https://github.com/gatsbyjs/gatsby/issues/14076

https://spectrum.chat/gatsby-js/general/adding-remote-images-during-node-creation~e704e6fb-24b2-46c6-b1fc-93189d2e28a4

https://github.com/njosefbeck/gatsby-source-stripe/#๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ

@sandys ์ด๊ฒƒ์€ SSG RFC์™€ ๊ด€๋ จ์ด ์—†์œผ๋ฏ€๋กœ ๋ฆด๋ฆฌ์Šค๋˜๋ฉด ์ƒˆ๋กœ์šด ๋ฌธ์ œ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์ƒ์„ฑํ•˜์‹ญ์‹œ์˜ค.

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ์˜ ๋ชจ๋“  ์ƒ๊ฐ์—์„œ ์ด๊ฒƒ์€ SSG์™€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ด€๋ จ๋˜์–ด ์žˆ์Œ์„ ์–ธ๊ธ‰ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์ƒ์ ์ธ ๊ฒฝ์šฐ๋Š” SSG ๋‚ด๋ณด๋‚ด๊ธฐ ๋ช…๋ น์ด ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๊ฐ€์žฅ ์ข‹์€ ๊ฒฝ์šฐ๋Š” ์ด๊ฒƒ์ด ๋‹ค์Œ ๋‚ด๋ณด๋‚ด๊ธฐ ๋™์•ˆ ์„ ํƒ์  ๊ธฐ๋Šฅ์ธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์›ํ•˜๋Š”๋Œ€๋กœ ๊ฒฐ์ •์„ ์กด์ค‘ํ•˜์‹ญ์‹œ์˜ค.

ํ•˜์ง€๋งŒ ์ง€๊ธˆ์€ next export ํ•˜์ง€ ์•Š๋Š” ์ผ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๊ฒƒ์ด ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ๊ฒƒ์ด๊ณ  ์ด RFC์™€ ๊ด€๋ จ์ด ์—†๋Š” ์ด์œ ์ž…๋‹ˆ๋‹ค.

๋˜ํ•œ getServerProps ๋ฐ ์ฃผ๋ฌธํ˜• ๋ Œ๋”๋ง์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

@Janpot CMS ์ œ๊ณต์—…์ฒด๋Š” ์ด๋ฏธ ์ด๋ฏธ์ง€ ๋“ฑ์— ๊ณ ์œ ํ•œ URL์„ ์ œ๊ณตํ•˜์—ฌ ์ด๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘ ๋„ค, ๋งž์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” ๋˜ํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ตœ์ ํ™” ๋ฐ ์บ์‹œํ•˜๋ ค๋Š” ๊ฒฝ์šฐ 2๊ฐ€์ง€ ์„ ํƒ์ด ์žˆ์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

  1. ์‚ฌ์šฉ์ž ์ •์˜ ์›นํŒฉ ์„ค์ • ๋นŒ๋“œ
  2. ์™ธ๋ถ€ CMS ์‚ฌ์šฉ

ํŽธ์ง‘ํ•˜๋‹ค:

๊ทธ๋ฆฌ๊ณ  ๋‚ด๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•œ๋‹ค๋ฉด file-loader ๋Š” ์ด๋ฏธ CSS์— ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. JS์—์„œ๋„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋Š”๊ฒŒ ๋ฌธ์ œ ์•„๋‹Œ๊ฐ€์š”?

@Janpot Sandeep์ด ์–ธ๊ธ‰ํ•œ ํŠน์ • ์š”์ ์€ URL์ด ํ”„๋กœ์ ํŠธ ์ž์ฒด๊ฐ€ ์•„๋‹Œ ์™ธ๋ถ€ ์†Œ์Šค์—์„œ ์ œ๊ณต๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ํŒŒ์ผ ๋กœ๋”๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์€ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ ์š”์ฒญ์ž…๋‹ˆ๋‹ค.

ZEIT Now์— ๋ฐฐํฌ๋œ ์‚ฌ์ดํŠธ์˜ ๊ฒฝ์šฐ ์ƒˆ๋กœ์šด ์ •์  API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋™์  URL์ด ์žˆ๋Š” ํŽ˜์ด์ง€๊ฐ€ ์žˆ์„ ๋•Œ unstable_getStaticPaths ์‚ฌ์šฉํ•˜์—ฌ ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋˜์ง€ ์•Š์€ ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ unstable_getStaticProps ๋Š” 404๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  ๋Ÿฐํƒ€์ž„์— ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด getStaticPaths ๊ฐ€ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” /blog/[slug].js ํŽ˜์ด์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

[{ params: { slug: 'hello' } }]

๋‚ด getStaticProps ์—๋Š” ์Šฌ๋Ÿฌ๊ทธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํŒŒ์ผ์„ ์ฝ๋Š” ๋…ผ๋ฆฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. /blog/hello ๋ฐฉ๋ฌธํ•˜๋ฉด ํŽ˜์ด์ง€๊ฐ€ ์˜ˆ์ƒ๋Œ€๋กœ ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง๋˜์ง€๋งŒ /blog/doesnt-exist ์™€ ๊ฐ™์€ ์ž˜๋ชป๋œ ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด ๋Ÿฐํƒ€์ž„์— getStaticProps ๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์˜ค๋ฅ˜ 500์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. a 404. ๋˜๋Š” ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด getStaticPaths ์˜ ์ถœ๋ ฅ์— ๋‚˜์—ด๋˜์ง€ ์•Š์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ํŽ˜์ด์ง€๊ฐ€ 404๊ฐ€ ์•„๋‹Œ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

์ด ๋…ผ๋ฆฌ๊ฐ€ ์˜๋„๋œ ๊ฒƒ์ž…๋‹ˆ๊นŒ?

์ด๊ฒƒ์€ ํ›Œ๋ฅญํ•œ ๊ฐœ์„  ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ์‚ฌ์ „ ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.
Next 9.2์—์„œ ์‚ฌ์ดํŠธ ์ค‘ ํ•˜๋‚˜๋ฅผ unstable_getStaticPaths ๋ฐ unstable_getStaticProps ์ด๋™ํ•˜๋Š” ๊ฒƒ์„ ํ…Œ์ŠคํŠธํ–ˆ๋Š”๋ฐ ์ž˜ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค.

exportPathMap ๋น„ํ•ด ํšŒ๊ท€๊ฐ€ ํ•˜๋‚˜ ์žˆ์Šต๋‹ˆ๋‹ค. exportPathMap ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฝ๋กœ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{
 "/path/to/page": {page: "/index", query: { pageId: 123 } }
}

์ •์  ๋นŒ๋“œ๊ฐ€ ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค.

/path
   /to
     /page
       index.html

[slug].jsx ํ…œํ”Œ๋ฆฟ์˜ unstable_getStaticPaths ์—์„œ ์ด์— ์ƒ์‘ํ•˜๋Š” ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด

[{ slug: '/path/to/page' }]

๋‹ค์Œ 9.2๋Š” ์ค‘์ฒฉ๋œ ๋””๋ ‰ํ„ฐ๋ฆฌ ๋Œ€์‹  '%2Fpath%2Fto%2Fpage'๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

/%2Fpath%2Fto%2F
   index.html

๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์ถ•(๊ธฐ์กด exportPathMap ๋™์ž‘๊ณผ ์ผ์น˜)์€ ํŽ˜์ด์ง€ ๊ตฌ์ถ• ๋ฐฉ์‹์— ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ์ผ ํ…œํ”Œ๋ฆฟ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ ๊ฒŒ์‹œ๋œ ๊ฒฝ๋กœ๋Š” ์ž„์˜๋กœ ์ค‘์ฒฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@dpfavand ์ด ๊ฒฝ์šฐ ํฌ๊ด„ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. https://nextjs.org/blog/next-9-2#catch -all-dynamic-routes

์Šฌ๋ž˜์‹œ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ ค๊ณ  ํ•  ๋•Œ ์ž ์žฌ์ ์œผ๋กœ ๊ฒฝ๊ณ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ [slug].js ์‚ฌ์šฉํ•  ๋•Œ ๋™์ž‘์€ ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ฒฝ์šฐ์—๋Š” [...slug].js ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค.

์–ธ์ œ ์ฐฉ๋ฅ™ํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ๋ฉ๋‹ˆ๊นŒ? 9.2 ํŒจ์น˜์— ํฌํ•จ๋ฉ๋‹ˆ๊นŒ ์•„๋‹ˆ๋ฉด ์ž์ฒด ๋งˆ์ด๋„ˆ ๋ฒ„์ „์— ํฌํ•จ๋ฉ๋‹ˆ๊นŒ?

์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ธฐ๋Œ€์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๊ณณ์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด ์šฐ๋ฆฌ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๊ธฐ๋Šฅ์ด ์˜ฌ๋ฐ”๋ฅธ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜, ์ œ์•ฝ ์กฐ๊ฑด ๋ฐ ๋ฏธ๋ž˜ ๋ณด์žฅ์„ฑ์„ ๊ฐ–๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ผ์ •์„ ๊ณต์œ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์ด๋„ˆ๊ฐ€ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ˆ, ์ผ๋ฐ˜์ ์œผ๋กœ ์ดํ•ดํ•˜์ง€๋งŒ 9.1.7 ๋ธ”๋กœ๊ทธ๋Š”
๊ทธ๊ฒƒ์€ ์ด๋ฏธ ์•ผ์ƒ์— ์žˆ์—ˆ๋‹ค.

2020๋…„ 1์›” 17์ผ ๊ธˆ์š”์ผ ์˜คํ›„ 5:05 Tim Neutkens [email protected]
์ผ๋‹ค:

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

โ€”
๋‹น์‹ ์ด ๋Œ“๊ธ€์„ ๋‹ฌ์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธ
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=ADKINGF724256WCEFHBFIH3Q6ITRXA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVEXG43VMVBW63LN
๋˜๋Š” ๊ตฌ๋… ์ทจ์†Œ
https://github.com/notifications/unsubscribe-auth/ADKINGBVCG6MFMOG5U2FGMDQ6ITRXANCNFSM4JRPBELQ
.

>

๋ผ์‹œํ„ฐ ๊ทธ๋ ˆ๊ทธ
[email protected] [email protected]
์…€ (832) 495-9903

getStaticProps ๊ฒƒ์ด ์žˆ์ง€๋งŒ ํŽ˜์ด์ง€๋‹น์ด ์•„๋‹ˆ๋ผ ์ „์ฒด ์•ฑ์— ๋Œ€ํ•ด ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋‚˜์š”?

๋‚ด ์‚ฌ์šฉ ์‚ฌ๋ก€๋Š” ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉ๋˜๋Š” React Context( PricingPlansContext )๊ฐ€ ์žˆ๊ณ  ๋นŒ๋“œ ์‹œ( next export ์™ธ๋ถ€ ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ(๊ฐ€๊ฒฉ ์ฑ…์ • ๊ณ„ํš)๋ฅผ ํ•œ ๋ฒˆ๋งŒ ๊ฒ€์ƒ‰ํ•˜๊ธฐ๋ฅผ ์›ํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. getStaticProps ์— ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

ํŽธ์ง‘: https://github.com/zeit/next.js/issues/9524#issuecomment -574179540์—์„œ ๊ด€๋ จ ๋Œ“๊ธ€์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์ด ๊ณ ๋ ค๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์œ„ํ•ด babel plugin-preval`์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
next.config.js๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ exportPathMa() ๋‚ด์˜ json ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
๊ทธ๋“ค์˜ ์ฝ”๋“œ ๋‚ด์—์„œ.

์ง€๊ธˆ์€ npm ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ json ํŒŒ์ผ์„ ์ž‘์„ฑํ–ˆ์ง€๋งŒ exportPathMap์„ ์ œ์•ˆํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

@dpfavand ์ด ๊ฒฝ์šฐ ํฌ๊ด„ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. https://nextjs.org/blog/next-9-2#catch -all-dynamic-routes

์Šฌ๋ž˜์‹œ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ ค๊ณ  ํ•  ๋•Œ ์ž ์žฌ์ ์œผ๋กœ ๊ฒฝ๊ณ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ [slug].js ์‚ฌ์šฉํ•  ๋•Œ ๋™์ž‘์€ ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๊ฒฝ์šฐ์—๋Š” [...slug].js ๋ฅผ ์›ํ•ฉ๋‹ˆ๋‹ค.

@timneutkens ํ›„์† getStaticPaths , ๊ทธ๊ฒƒ์€์„ ํ†ตํ•ด ์ „๋‹ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค getStaticProps ์ „ํ˜€. ์Šฌ๋Ÿฌ๊ทธ ๊ฐ’์„ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•  ๋•Œ ๊ฐ’์ด ๋ฌธ์ž์—ด์ด์–ด์•ผ ํ•˜๋ฏ€๋กœ ๋นŒ๋“œ๊ฐ€ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ๋ก€ 1, pages/[...slug].jsx ํŒŒ์ผ์„ ๋ฌธ์ž์—ด๋กœ ๊ฐ€์ •:

export async function unstable_getStaticPaths() {
    return [{ params: { slug: 'en/about' } }];
}

export async function unstable_getStaticProps({ params }) {
    console.log('params', params);
    return { slug: params.slug };
}

์œ„์˜ ๊ฒฝ์šฐ params ์˜ getStaticProps ๋Š” slug ํ‚ค๊ฐ€ ์—†๋Š” ๋นˆ ๊ฐœ์ฒด์ž…๋‹ˆ๋‹ค.

์‚ฌ๋ก€ 2, pages/[...slug].jsx , ์Šฌ๋Ÿฌ๊ทธ๋ฅผ ๋ฐฐ์—ด๋กœ,

export async function unstable_getStaticPaths() {
    const allPaths = Object.keys(pathMap).map(slug => ({ params: { slug } }));
    return [{ params: { slug: ['en', 'about'] } }];
}
export async function unstable_getStaticProps({ params }) {
    console.log('params', params);
    return { slug: params.slug };
}

๊ฒฝ์šฐ 2์˜ ๊ฒฝ์šฐ ๋นŒ๋“œ๊ฐ€ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

> Build error occurred
{ Error: A required parameter (slug) was not provided as a string.
    at _validParamKeys.forEach.validParamKey (/project/node_modules/next/dist/build/utils.js:21:569)
    at Array.forEach (<anonymous>)
    at toPrerender.forEach.entry (/project/node_modules/next/dist/build/utils.js:21:495)
    at Array.forEach (<anonymous>)
    at Object.isPageStatic (/project/node_modules/next/dist/build/utils.js:17:122)
    at process._tickCallback (internal/process/next_tick.js:68:7) type: 'Error' }

์œ„์˜ getStaticPaths ์˜ˆ์ œ์—๋Š” ๊ฒฝ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํฌํ•จํ•˜๋Š” SSG ๊ฒฝ๋กœ์— ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด:

/store/widgets/circles-n-squares?sort=price&minWeight=2&color=black

์ €๋Š” ํŠนํžˆ URL์˜ pathname ์—์„œ ์ œํ’ˆ ๊ฒ€์ƒ‰์˜ ๋ชจ๋“  ์ธก๋ฉด์„ ๋‹ค๋ฃจ๊ธฐ ์–ด๋ ค์šด ์ „์ž ์ƒ๊ฑฐ๋ž˜ ์‚ฌ์ดํŠธ์˜ ๊ด€์ ์—์„œ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ตœ๊ทผ์— ์—ฌ๊ธฐ์— ๋ฉ”์‹œ์ง€๋ฅผ ๊ฒŒ์‹œํ–ˆ์ง€๋งŒ ๋‹ต์žฅ์„ ๋ฐ›์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ณธ์งˆ์ ์œผ๋กœ getStaticProps ๋Š” ์‚ฌ์ดํŠธ๊ฐ€ ZEIT Now์— ๋ฐฐํฌ๋  ๋•Œ getServerProps ์ฒ˜๋Ÿผ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: getStaticPaths ๋ฌด์‹œํ•˜๊ณ  ์š”์ฒญ ์ฒ˜๋ฆฌ ๋™์ ์œผ๋กœ) - ์ด๊ฒƒ์ด ๋ฒ„๊ทธ๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๊นŒ?

@dpfavand ์ €๋„ ์ •ํ™•ํ•œ ๊ฒฝํ—˜์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! CMS์˜ ํŽ˜์ด์ง€๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋™์  ํŽ˜์ด์ง€ ๋ผ์šฐํŒ…์„ ์‚ฌ์šฉํ•˜์—ฌ agilitycms ๋ฐ nextjs ๋ฅผ

@timneutkens ํ›„์† getStaticPaths , ๊ทธ๊ฒƒ์€์„ ํ†ตํ•ด ์ „๋‹ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค getStaticProps ์ „ํ˜€.

์‚ฌ๋ก€ 1, pages/[...slug].jsx ํŒŒ์ผ์„ ๋ฌธ์ž์—ด๋กœ ๊ฐ€์ •:

export async function unstable_getStaticPaths() {
  return [{ params: { slug: 'en/about' } }];
}

export async function unstable_getStaticProps({ params }) {
  console.log('params', params);
  return { slug: params.slug };
}

์œ„์˜ ๊ฒฝ์šฐ params ์˜ getStaticProps ๋Š” slug ํ‚ค๊ฐ€ ์—†๋Š” ๋นˆ ๊ฐœ์ฒด์ž…๋‹ˆ๋‹ค.

BTW, ์ž‘์€ ์„ธ๊ณ„! fastr_conf์—์„œ ์ด์•ผ๊ธฐํ•ด์ฃผ์…”์„œ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @timneutkens ์ž…๋‹ˆ๋‹ค .

next.js๊ฐ€ ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ๊ธฐ์ฒ˜๋Ÿผ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋Š” ์•„์ด๋””์–ด์— ๋Œ€ํ•ด ๋งค์šฐ ํฅ๋ถ„๋ฉ๋‹ˆ๋‹ค.

๋งŽ์€ ์–‘์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ ์š”์ฒญํ•œ ๋‹ค์Œ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ getStaticProps ๋ฐ getStaticPaths ๋ฉ”์„œ๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ฌป๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๊ฐœ์ฒด๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์žˆ๋Š” API ๊ธฐ๋ฐ˜ CMS์˜ JavaScript SDK ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐœ์ฒด ์ค‘ ์ผ๋ถ€๋Š” ์‚ฌ์ดํŠธ ํŽ˜์ด์ง€๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

const entries = await cmsSdkCient.getEntries();

์ง€๊ธˆ๊นŒ์ง€ exportPathMap ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CMS์—์„œ ๋ชจ๋“  ํ•ญ๋ชฉ์„ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์™€ ์ด ํŽ˜์ด์ง€์˜ ๊ฒฝ๋กœ์™€ ํ•ด๋‹น ๋ฐ์ดํ„ฐ ์‚ฌ์ด์˜ ๋งต์„ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. exportPathMap ํ•จ์ˆ˜๋Š” ๋‘ ๊ฐ€์ง€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  1. ๋‚ด๋ณด๋‚ผ ๋•Œ getInitialProps ์— ์˜ํ•ด ์†Œ๋น„๋˜๋Š” ๋ฐ์ดํ„ฐ ๋ฐ ssr: true ๊ฐ€ ์žˆ๋Š” ํŽ˜์ด์ง€ ๋งต์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  2. ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๊ฒฝ๋กœ์™€ ์ผ์น˜ํ•˜๋Š” ํด๋”์— ์žˆ๋Š” init-props.json ํŒŒ์ผ์— ์ด๋ฒˆ์—๋Š” ssr: false ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์”๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ํด๋ผ์ด์–ธํŠธ์—์„œ getInitialProps ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์ผ์น˜ํ•˜๋Š” ํŽ˜์ด์ง€์˜ init-props.json ์—์„œ ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.


exportPathMap ์‚ฌ์šฉํ•˜๋Š” next.config.js

module.exports = {
  exportTrailingSlash: true,
  exportPathMap: (defaultPathMap, { outDir }) => {
    // load data from CMS
    const objects = await cmsSdkCient.getEntries();

    // create map between page paths and page data
    return objects.reduce((accum, object) => {

      // if the object does not have a slug, it is not a page
      if (!object.slug) return accum;

      const pagePath = '/' + object.slug;
      const ssrQueryData = Object.assign({ ssr: true }, object);
      const clientQueryData = Object.assign({ ssr: false }, object);

      // generate the map for export phase with {ssr: true}
      accum[pagePath] = {
        // using additional fields from the page object,
        // the pageFromPagePath() computes which page file should
        // be used to render the page object
        page: pageFromPagePath(object),
        query: ssrQueryData
      };

      // write json files that will be loaded by client
      if (outDir) {
        const jsonFilePath = path.join(outDir, _.trim(pagePath, '/'), 'init-props.json');
        fse.outputFileSync(jsonFilePath, JSON.stringify(clientQueryData));
      }

      return accum;
    }, {});
  }
}


getInitialProps ์‚ฌ์šฉํ•˜๋Š” ํŽ˜์ด์ง€/my_page.js

Index.getInitialProps = async (context) => {
  const ssr = _.get(context, 'query.ssr', false);
  if (ssr) {
    // we are on server, return the data
    return _.get(context, 'query', {});
  } else {
    // we are on client side, request the data through /init-props.json endpoint
    const url = context.asPath + '/init-props.json';
    return fetch(url).then(response => {
      return response.json();
    });
  }
};

getStaticProps ๋ฐ getStaticPaths ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด JSON ํŒŒ์ผ์„ ์ €์žฅํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์—์„œ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ ๋งŽ์ด ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ํฐ ์ด์ ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// pages/my_page.js
export async function getStaticProps(context) {
  const objects = await cmsSdkCient.getEntries();
  const props = _.find(object, { type: 'my_page' })
  return { props };
}

// pages/blog/[slug].js
export async function getStaticProps(context) {
  const objects = await cmsSdkCient.getEntries();
  const props = _.find(object, { type: 'post', slug: context.params.slug })
  return { props };
}

export async function getStaticPaths() {
  const objects = await cmsSdkCient.getEntries();
  return objects
    .filter(object => object.type === 'post')
    .map(object => ({ params: { slug: object.slug } }))
}

๋ฌธ์ œ๋Š” getStaticProps ๋˜๋Š” getStaticPaths ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค ํ•ญ๋ชฉ์„ ๊ฐ€์ ธ์˜ค๋Š” ๋Œ€์‹  ๋ชจ๋“  ํ•ญ๋ชฉ์„ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๋„๋ก ์›Œํฌํ”Œ๋กœ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์งˆ๋ฌธ์€ ์ด ๋ฌธ์ œ์™€ ๋ฐ˜๋“œ์‹œ ๊ด€๋ จ์ด ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ์šฐ๋ฆฌ๋Š” SSG ๋ฐ ์›๊ฒฉ ๋ฐ์ดํ„ฐ ์†Œ์Šค์˜ ์„ธ๊ณ„์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์งˆ๋ฌธํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. next.js๊ฐ€ dev ๋ชจ๋“œ์—์„œ ์‹คํ–‰๋œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ์›๊ฒฉ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ ๊ฐ€์ ธ์˜ค๊ณ  ์‚ฌ์ดํŠธ๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•˜๊ธฐ ์œ„ํ•ด ์–ด๋–ป๊ฒŒ next.js์— ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋„๋ก ์•Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@smnh "๊ทธ๋ƒฅ JavaScript"์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ๋ชฉ์„ ํ•œ ๋ฒˆ ๊ฐ€์ ธ์˜ค๊ณ  ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐฉ๋ฒ•์— ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํŽ˜์ด์ง€์˜ getStatic* ๋ฉ”์†Œ๋“œ์—์„œ ๋‹ค์‹œ ํ˜ธ์ถœ๋  ๋•Œ ๋„คํŠธ์›Œํฌ๋Š” ๋‹ค์‹œ ์ ์ค‘๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‘ ๋ฒˆ์งธ ์งˆ๋ฌธ์€ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. next dev ์‹คํ–‰ํ•˜๋ฉด ๋ฐ”๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

์œ„์˜ getStaticPaths ์˜ˆ์ œ์—๋Š” ๊ฒฝ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜๋งŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ํฌํ•จํ•˜๋Š” SSG ๊ฒฝ๋กœ์— ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด:

/store/widgets/circles-n-squares?sort=price&minWeight=2&color=black

์ €๋Š” ํŠนํžˆ URL์˜ pathname ์—์„œ ์ œํ’ˆ ๊ฒ€์ƒ‰์˜ ๋ชจ๋“  ์ธก๋ฉด์„ ๋‹ค๋ฃจ๊ธฐ ์–ด๋ ค์šด ์ „์ž ์ƒ๊ฑฐ๋ž˜ ์‚ฌ์ดํŠธ์˜ ๊ด€์ ์—์„œ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ssg์˜ ๋งฅ๋ฝ์—์„œ ์˜๋ฏธ๊ฐ€ ์—†๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. SSG๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ํŒŒ์ผ์„ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ํŒŒ์ผ ์ด๋ฆ„์˜ ์ผ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ์š”์ฒญ์„ ์‹ค์ œ ํŒŒ์ผ์— ๋‹ค์‹œ ์“ฐ๋ ค๋ฉด ์„œ๋ฒ„ ๊ณ„์ธต์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. (์œ„์˜ ์˜ˆ์—์„œ ์ •์  ํŒŒ์ผ ์ด๋ฆ„์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?) ๊ธฐ๋ณธ ๋ณด๊ธฐ(ํŒจ์‹ฏ์ด ์—†๋Š” ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ)๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•˜๊ณ  ์š”์ฒญ์— ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๊ฒƒ์€ ์ด SSG RFC๋ฅผ ๋„˜์–ด์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

@dpfavand ์ €๋„ ์ •ํ™•ํ•œ ๊ฒฝํ—˜์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค! CMS์˜ ํŽ˜์ด์ง€๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ๋™์  ํŽ˜์ด์ง€ ๋ผ์šฐํŒ…์„ ์‚ฌ์šฉํ•˜์—ฌ agilitycms ๋ฐ nextjs ๋ฅผ

@timneutkens ํ›„์† getStaticPaths , ๊ทธ๊ฒƒ์€์„ ํ†ตํ•ด ์ „๋‹ฌ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค getStaticProps ์ „ํ˜€.
์‚ฌ๋ก€ 1, pages/[...slug].jsx ํŒŒ์ผ์„ ๋ฌธ์ž์—ด๋กœ ๊ฐ€์ •:

export async function unstable_getStaticPaths() {
    return [{ params: { slug: 'en/about' } }];
}

export async function unstable_getStaticProps({ params }) {
    console.log('params', params);
    return { slug: params.slug };
}

์œ„์˜ ๊ฒฝ์šฐ params ์˜ getStaticProps ๋Š” slug ํ‚ค๊ฐ€ ์—†๋Š” ๋นˆ ๊ฐœ์ฒด์ž…๋‹ˆ๋‹ค.

BTW, ์ž‘์€ ์„ธ๊ณ„! fastr_conf์—์„œ ์ด์•ผ๊ธฐํ•ด์ฃผ์…”์„œ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ด๋ด! Nextjs ํŒ€์€ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ์œผ๋ฉฐ ํ˜„์žฌ ์นด๋‚˜๋ฆฌ์•„ ๊ตฌํ˜„๊ณผ ๊ด€๋ จ๋œ ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ํ‹ฐ์ผ“์ด ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/zeit/next.js/issues/10190

@smnh ๋‚ด๊ฐ€ ํ•˜๋Š” ์ผ์€ ๋นŒ๋“œ + ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ๊ณต์œ  ์ฝ˜ํ…์ธ ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์˜ค๊ณ  JSON์— ์ €์žฅํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ํ•ด๋‹น JSON์„ ํŽ˜์ด์ง€์—์„œ ๋ชจ๋“ˆ๋กœ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์žฌ๊ตฌ์ถ•์„ ์œ„ํ•ด ๊ด€๋ จ ์ฝ˜ํ…์ธ ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ Netlify ๋นŒ๋“œ ํ›„ํฌ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•˜๋„๋ก CMS์— ์›นํ›„ํฌ๋ฅผ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ GetStaticProps๋Š” ํŽ˜์ด์ง€ ํŠน์ • ์ฝ˜ํ…์ธ ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@zeusdeux ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค
๋‹ต์žฅ:

๋‘ ๋ฒˆ์งธ ์งˆ๋ฌธ์€ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๊ฐœ๋ฐœ์„ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“ˆ์— ์บ์‹œํ•œ ๋‹ค์Œ CMS์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์บ์‹œ๊ฐ€ ๋ฌดํšจํ™”๋˜๊ณ  dev ์˜ํ•ด ๋‹ค์‹œ ์‹คํ–‰๋˜์ง€๋งŒ next.js๋ฅผ ์ค‘์ง€ํ•˜๊ณ  ๋‹ค์‹œ ์‹คํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. :)

๋ชจ๋“ˆ์— ์บ์‹œํ•œ ๋‹ค์Œ CMS์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์บ์‹œ๊ฐ€ ๋ฌดํšจํ™”๋˜๊ณ  dev ์˜ํ•ด ๋‹ค์‹œ ์‹คํ–‰๋˜์ง€๋งŒ next.js๋ฅผ ์ค‘์ง€ํ•˜๊ณ  ๋‹ค์‹œ ์‹คํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. :)

getStaticPaths ๋Š” ํ”„๋กœ๋•์…˜ ๋นŒ๋“œ์—์„œ๋งŒ ํ˜ธ์ถœ๋˜๋ฏ€๋กœ ํ•ด๋‹น ํ•จ์ˆ˜์—์„œ ํ˜ธ์ถœ๋  ๋•Œ ๋ชจ๋“ˆ ์ƒํƒœ์—์„œ ์บ์‹œํ•˜๋„๋ก ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์„œ๋“œ๋งŒ ์•Œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ด, ๋‚˜๋Š” ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋‚˜์™€ ๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ–ˆ๋Š”์ง€ ๋ณด์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

unstable_getStaticProps ํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฒฝ๋กœ์— ๋™์ผํ•œ ํŽ˜์ด์ง€๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1. /providers/[category]/[city] 
2. /providers/[category] 

์†Œ์Šค ์ฝ”๋“œ๋Š” ๋‘ ํŽ˜์ด์ง€ ๋ชจ๋‘ ๋™์ผํ•˜๋ฏ€๋กœ ๋ณต์ œํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ฒซ ๋ฒˆ์งธ ํŒŒ์ผ์—๋Š” ๋…ผ๋ฆฌ๊ฐ€ ์žˆ๋Š” ์†Œ์Šค ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ๊ณ  ๋‘ ๋ฒˆ์งธ ํŒŒ์ผ์€ export { default } from './[city]'; ์™€ ๊ฐ™์€ ์ฒซ ๋ฒˆ์งธ ํŒŒ์ผ๋งŒ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ getStaticProps์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ •์˜๋˜์ง€ ์•Š์•˜๋‹ค๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ฝ”๋“œ๋ฅผ ๋‘ ํŒŒ์ผ์— ๋ชจ๋‘ ๋ณต์‚ฌํ•˜๋ฉด ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@homoky ๋ฉ”์†Œ๋“œ๋ฅผ ๋‹ค์‹œ ๋‚ด

export { default, unstable_getStaticProps } from './[city]';

๋‚˜๋Š” SSG๋ฅผ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์šด์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

v9.2.1์ด ํฌํ•จ๋œ ์•„๋ž˜ ์ฝ”๋“œ๋Š” SSG๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

function Page({ stars }) {
  return <div>Next stars: {stars}</div>
}

Page.unstable_getStaticProps = async ctx => {
  return { props: { stars: 5 } }
}

export default Page

next build ๋‚ด ์ฝ˜์†” ์ถœ๋ ฅ์€ ๋‹ค์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

Page                                                           Size     First Load
โ”Œ โ—‹ /                                                          354 B       72.1 kB
...
ฮป  (Server)  server-side renders at runtime (uses getInitialProps or getServerProps)
โ—‹  (Static)  automatically rendered as static HTML (uses no initial props)
โ—  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)

@joostmeijles unstable_getStaticProps ๋Š” ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ์— ์ฒจ๋ถ€๋˜๋Š” ๋Œ€์‹  ๋‚ด ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ:

export const unstable_getStaticProps = async () => {
  return {
    props: { stars: 5 }
  }
}

@joostmeijles unstable_getStaticProps ๋Š” ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ์— ์ฒจ๋ถ€๋˜๋Š” ๋Œ€์‹  ๋‚ด ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ:

export const unstable_getStaticProps = async () => {
  return {
    props: { stars: 5 }
  }
}

๋•๋ถ„์— ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ์ข…๋‹จ ๊ฐ„ ์ž‘์—… ์˜ˆ๋ฅผ ๋ณด๊ณ  ์‹ถ์€ ์‚ฌ๋žŒ์ด ์žˆ์œผ๋ฉด ํฌ๊ด„ ๊ฒฝ๋กœ ๋ฐ SSG๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์  ํŽ˜์ด์ง€(CMS์—์„œ) ์ƒ์„ฑ https://github.com/agility/agilitycms-next-starter-๋ฅผ ํ™•์ธ

๋‚˜๋Š” ๋ช‡ ๋ฒˆ ๋‹นํ™ฉํ–ˆ๊ณ  ์ด๊ฒƒ์ด ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

zeit.co/now์— ๋ฐฐํฌํ•  ๋•Œ getStaticProps ๋นŒ๋“œํ•˜๋Š” ๋™์•ˆ ๋‹ค์Œ API ๊ฒฝ๋กœ์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? Isomorphic-fetch์—๋Š” ์ ˆ๋Œ€ URL์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๋กœ์ปฌ์—์„œ๋Š” http://localhost :3000์—์„œ ์ž‘๋™ํ•˜์ง€๋งŒ ์ง€๊ธˆ ๋ฐฐํฌ์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋˜๋Š” ๋‚ด๊ฐ€ ์ž˜๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค ๐Ÿคทโ€โ™‚๏ธ). ์–ด๋–ค ์•„์ด๋””์–ด?

๋‚ด ๋ง์ด ๋งž๋‹ค๋ฉด API ๊ฒฝ๋กœ๊ฐ€ ์„œ๋ฒ„๋ฆฌ์Šค ๊ธฐ๋Šฅ์œผ๋กœ ๋ฐฐํฌ๋  ๊ฒƒ์ด๊ณ  ๋นŒ๋“œ ํ”„๋กœ์„ธ์Šค ์ค‘์— ์ค€๋น„๋˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๊นŒ?

http๋ฅผ ํ†ตํ•ด ์ด๋™ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ์ ์€ ์˜ค๋ฒ„ ํ—ค๋“œ๋กœ API ๊ฒฝ๋กœ์˜ ๊ธฐ๋Šฅ์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

http๋ฅผ ํ†ตํ•ด ์ด๋™ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ์ ์€ ์˜ค๋ฒ„ ํ—ค๋“œ๋กœ API ๊ฒฝ๋กœ์˜ ๊ธฐ๋Šฅ์„ ์ง์ ‘ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•ด๋‹น ์ฃผ์ œ์— ๋Œ€ํ•œ ๋ฌธ์„œ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ๋ฆฌ์†Œ์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ์ €๋Š” zeit.co/now๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ์ค‘์ž…๋‹ˆ๋‹ค :)

๋ง ๊ทธ๋Œ€๋กœ ํ•จ์ˆ˜๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.

import MyFunction from '../lib/somewhere'


export async function /* unstable_ */getStaticProps() {
  const result = await MyFunction()
}

๋˜ ๋‹ค๋ฅธ ์งˆ๋ฌธ: getStaticProps / getStaticPaths ๋ฐ getServerProps ๋‚˜๋ž€ํžˆ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์˜ˆ๋ฅผ ๋“ค์–ด SSG๋กœ ์ผ๋ถ€ ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ–ˆ์ง€๋งŒ CDN ์บ์‹œ์—์„œ ์ฐพ์„ ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ ์š”์ฒญ ์‹œ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด SSR๋กœ ๋Œ€์ฒด๋ฉ๋‹ˆ๊นŒ?

getStaticProps ๋Š” SSR๋กœ ๋Œ€์ฒดํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

getStaticProps ๋Š” SSR๋กœ ๋Œ€์ฒดํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

@lfades , ๋‚ด๊ฐ€ ๋‹น์‹ ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•œ๋‹ค๋ฉด ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•ด ๋งค์šฐ ๐Ÿ˜ ์™œ๋ƒํ•˜๋ฉด ๋ฏธ๋ฆฌ ์ˆ˜์ฒœ ํŽ˜์ด์ง€๋ฅผ ์ฐพ์•„ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹  ์ธ๊ธฐ์žˆ๋Š” ํŽ˜์ด์ง€ ๋ช‡ ๊ฐœ๋ฅผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•ด... /products/[productId].js ๋™์  ๊ฒฝ๋กœ ํŽ˜์ด์ง€๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ getStaticProps , ๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ณผ์˜ ์ œํ•œ๋œ ์ˆ˜์˜ getStaticPaths ๊ฒฝ์šฐ, ๋‹น์‹ ์€ ๋ง์„ํ•˜๋Š”์ง€ /products/123 CDN์— ์บ์‹œ์—์„œ ๋ฐœ๊ฒฌ๋˜์ง€๋Š” ๋…„ํ›„ ๋•Œ๋ฌธ์— '( t in getStaticPaths ), SSR๋กœ ๋Œ์•„๊ฐ€ getStaticProps ์‹คํ–‰ํ•œ ๋‹ค์Œ ๊ฒฐ๊ณผ๋ฅผ ์ •์  ํŽ˜์ด์ง€๋กœ ์บ์‹œํ•ฉ๋‹ˆ๊นŒ?

ํ›„์† ์งˆ๋ฌธ: getStaticPaths ๋ฅผ ์ „ํ˜€ ์ œ๊ณตํ•˜์ง€ ์•Š์•„๋„ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

@flintinatux ์˜ˆ, ๊ทธ๋ ‡์Šต๋‹ˆ๋‹ค ๐Ÿ‘

getStaticProps๋Š” SSR๋กœ ํด๋ฐฑํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

getStaticProps ๋Š” res ๊ฐœ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— 404๋ฅผ ์ˆ˜ํ–‰ํ•  ๋ฐฉ๋ฒ•์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ค‘์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ์œผ๋ฉด 200 ๋˜๋Š” 500์ด ๋ฉ๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ๋  ์˜ˆ์ •์ธ๊ฐ€์š”?

@davidbailey00์€ ์ •์  ์›น์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ 404 ํŽ˜์ด์ง€์— ์ด๋ฏธ 404 ์ƒํƒœ ์ฝ”๋“œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋ฌผ๋ก  ์ „์ฒด ์ •์  ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ํŒŒ์ผ์ผ ๋ฟ์ด๋ฏ€๋กœ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ์ˆ˜ํ–‰ํ•  ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค. ZEIT Now์— getStaticProps ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์‚ฌ์ดํŠธ๋ฅผ ๋ฐฐํฌํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์— ๊ด€๊ณ„์—†์ด ๋™์  ๊ฒฝ๋กœ์™€ ์ผ์น˜ํ•˜๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ๊ฐ•์ œ๋กœ ๋ Œ๋”๋งํ•˜๊ธฐ ๋ณด๋‹ค๋Š” getStaticPaths ์กด์ค‘ํ•˜๊ณ  404ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Now ์—์„œ๋งŒ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ next start ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์•ž์„œ ๋งํ•œ ๋Œ€๋กœ ๋ฐ˜๋ณตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์‹คํ—˜์  ์ด๋ฉฐ ์—ฌ์ „ํžˆ ๋™์ž‘์ด ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ getServerProps ๋˜๋Š” getInitialProps 404ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‘๋‹ต ์ฝ”๋“œ๋ฅผ ๊ณ ๋ คํ•  ๋•Œ getStaticProps ๊ฐ€ getStaticPaths ๋ฌด์‹œํ•˜๋ฉด ๊ด€์‹ฌ์„ ๊ฐ–๋Š” ์‚ฌ์ดํŠธ์—์„œ๋Š” ์™„์ „ํžˆ ์‹คํ–‰ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ข‹์€ SEO.

์ƒํƒœ ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋” ๋งŽ์€ ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•  ๊ฒƒ์ด์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ์ •์  ์‚ฌ์ดํŠธ(์˜ˆ: CRA)๋Š” /* ๋ฅผ index.html ๋กœ ๋ผ์šฐํŒ…ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ 404๋Š” ์—ฌ์ „ํžˆ 200์ž…๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„, ์งˆ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด [unstable_]getStaticProps ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ผ๋ถ€ ํŽ˜์ด์ง€๋ฅผ SSGํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์›น์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. amp ๋ฅผ ์ œ์™ธํ•˜๊ณ  ์ง€๊ธˆ๊นŒ์ง€ ๋ชจ๋“  ๊ฒƒ์ด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€์— [unstable_]getStaticProps ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉด amp ๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ v9.2.1์—์„œ ๋‹ค์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์ž…๋‹ˆ๋‹ค.

import React from "react";
import { useAmp } from "next/amp";

export const config = { amp: `hybrid` };

const AmpExample = ({ date }) => {
  const isAmp = useAmp();
  return (
    <>
      <p>
        Welcome to the {isAmp ? `AMP` : `normal`} version of the Index page!!
      </p>
      <p>date: {date}</p>
    </>
  );
};
/**
 * If I get the dynamic data from getStaticProps,
 * page is SSG render but AMP is disabled when accessing
 * with `/ampExample?amp=1`
 */
export async function unstable_getStaticProps() {
  return {
    props: {
      date: new Date().toISOString(),
    },
  };
}

/**
 * If I get the dynamic data from getInitialProps,
 * page is SSR render but AMP is disabled when accessing
 * with `/ampExample?amp=1`
 */
// AmpExample.getInitialProps = () => {
//   return { date: new Date().toISOString() }
// }
export default AmpExample;

๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” SSG ํŽ˜์ด์ง€์™€ amp ์ž‘๋™ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜์…จ๋‚˜์š”?

์•ˆ๋…•ํ•˜์„ธ์š”, App ๊ตฌ์„ฑ ์š”์†Œ( _app.tsx ), ์ฆ‰ ๋นŒ๋“œ ๋‹จ๊ณ„์—์„œ ๋ชจ๋“  ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ ๊ณตํ†ต ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด getStaticProps ๋ฅผ ์ง€์›ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์•ˆ๋…•ํ•˜์„ธ์š”, App ๊ตฌ์„ฑ ์š”์†Œ( _app.tsx ), ์ฆ‰ ๋นŒ๋“œ ๋‹จ๊ณ„์—์„œ ๋ชจ๋“  ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ ๊ณตํ†ต ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด getStaticProps ๋ฅผ ์ง€์›ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

@pkral78 ์‹ค์ œ ๊ฐœ๋ฐœ ์ƒํ™ฉ์—์„œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๋ง์”€๋“œ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

"๊ณ ์ฐจ ๊ตฌ์„ฑ ์š”์†Œ(HOC)๋กœ์„œ์˜ ๋ ˆ์ด์•„์›ƒ" ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ๋ ˆ์ด์•„์›ƒ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค(๋” ์ด์ƒ ํ•™์Šต ๋ฌธ์„œ ๐Ÿคทโ€โ™‚๏ธ์— ์—†์Œ).

์–ด์จŒ๋“  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ ˆ์ด์•„์›ƒ์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค(์˜ˆ์‹œ).

import React from "react";
import Head from "next/head";

const withSSGLayout = Page => {
  const WithSSGLayout = props => {
    return (
      <>
        <Head>
          <title>My Web Page</title>
          <link rel="icon" href="/favicon.ico" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          <link
            href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap"
            rel="stylesheet"
          />
        </Head>
        <Page {...props} />
      </>
    );
  };

  WithSSGLayout.unstable_getStaticProps = async () => {
    const pageStaticProps = Page.unstable_getStaticProps
      ? await Page.unstable_getStaticProps()
      : {};

    // Here you can make parent level queries too
    return {
      props: {
        ...pageStaticProps.props,
        parentProp: `dynamic prop-${new Date().toISOString()}`,
      },
    };
  };
  return WithSSGLayout;
};

export default withSSGLayout;

๊ทธ๋Ÿฐ ๋‹ค์Œ ์ด ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ ค๋Š” ํŽ˜์ด์ง€์—์„œ HOC๋ฅผ ๊ฐ„๋‹จํžˆ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ( [unstable_]getStaticProps ๋ฐ amp๊ฐ€ ํ•จ๊ป˜ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ช…์‹œ์ ์œผ๋กœ ๋‚ด๋ณด๋‚ด์•ผ ํ•จ) ๋†’์€ ์ˆ˜์ค€์˜ ์š”์ฒญ์„ ๊ฐ–๋Š” "์ข‹์€ ๋ฐฉ๋ฒ•"์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. ํŽ˜์ด์ง€๋‹น SSG ์ฟผ๋ฆฌ.

import React from "react";
import withSSGLayout from "../hocs/withSSGLayout";

export const config = { amp: `true` };

const Index = props => {
  const { date, parentProp } = props;
  return (
    <div>
      <h1>Example</h1>
      <h3>Local Prop?: {date}</h3>
      <h3>Parent Prop?: {parentProp}</h3>
    </div>
  );
};

// In theory you could do direct database queries
Index.unstable_getStaticProps = async () => {
  // Here you can make page level queries
  return {
    props: {
      date: new Date().toISOString(),
    },
  };
};
const IndexHOC = withSSGLayout(Index);

export const { unstable_getStaticProps } = IndexHOC;
export default IndexHOC;

์ข‹์€ ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ผ๋ฉด ์–ธ๋”ํ•ธ๋“œํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” ์ด ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ€๋ชจ์˜ ๋งํฌ์™€ ํŽ˜์ด์ง€ ์ฝ˜ํ…์ธ ์˜ ํŽ˜์ด์ง€ ์ฝ˜ํ…์ธ ๋ฅผ ์ฟผ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋„์›€์ด ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

@robertovg ์ฝ”๋“œ๊ฐ€ ํŠธ๋ฆฌ ํ”๋“ค๋ ค์„œ ๋ชจ๋“ˆ ์ˆ˜์ค€์—์„œ ๋‚ด

@timneutkens ์ด ์ž‘์€ ์˜ˆ์— ๋Œ€ํ•ด ๋” ๋‚˜์€ ์†”๋ฃจ์…˜์„ ์ œ์•ˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ์–ด๋–ค ์‹์œผ๋กœ๋“  "๋ ˆ์ด์•„์›ƒ ์ˆ˜์ค€ SSG ์ฟผ๋ฆฌ"์™€ "ํŽ˜์ด์ง€ ์ˆ˜์ค€ SSG ์ฟผ๋ฆฌ"๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ๊ณ  ์ด HOC ๋ ˆ์ด์•„์›ƒ ์ ‘๊ทผ ๋ฐฉ์‹์— ๋Œ€ํ•ด ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋ฅผ ์œ„ํ•œ ์ฃผ์š” ์ œ์•ฝ์€ SSG ํŽ˜์ด์ง€๋กœ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ํŽ˜์ด์ง€์— ์žˆ์–ด์•ผ ํ•˜๋Š” ๋ช…์‹œ์ ์œผ๋กœ "[unstable_]getStaticProps ๋‚ด๋ณด๋‚ด๊ธฐ"์˜€์Šต๋‹ˆ๋‹ค.

amp + SSG ๊ฐ€ ํ˜ธํ™˜๋˜๋Š”์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์ •๋ณด๋„ ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด์ „์— ์งˆ๋ฌธํ•œ ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๐Ÿ™

@robertovg ๋จผ์ € ๋ฐ์ดํ„ฐ์—์„œ ๋ ˆ์ด์•„์›ƒ์„ ๋ถ„๋ฆฌํ•˜๋ฏ€๋กœ ๊ณต์œ  ๋ ˆ์ด์•„์›ƒ์˜ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

import Layout from '../components/layout'

const Page = () => (
  <Layout>
    <h1>Hello World!</h1>
  </Layout>
)

export default Page

๊ทธ๋ฆฌ๊ณ  getStaticProps ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋ฏ€๋กœ ์ „์ฒด ์˜ˆ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import fetchSharedData from '../lib/fetch-shared-data'
import Layout from '../components/layout'

export const unstable_getStaticProps = async () => {
  const sharedData = await fetchSharedData()
  const pageProps = {...}

  return {  props: { ...sharedData, ...pageProps } }
}

const Page = () => (
  <Layout>
    <h1>Hello World!</h1>
  </Layout>
)

export default Page

@robertovg ๋จผ์ € ๋ฐ์ดํ„ฐ์—์„œ ๋ ˆ์ด์•„์›ƒ์„ ๋ถ„๋ฆฌํ•˜๋ฏ€๋กœ ๊ณต์œ  ๋ ˆ์ด์•„์›ƒ์˜ ๊ฒฝ์šฐ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

import Layout from '../components/layout'

const Page = () => (
  <Layout>
    <h1>Hello World!</h1>
  </Layout>
)

export default Page

๊ทธ๋ฆฌ๊ณ  getStaticProps ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋ฏ€๋กœ ์ „์ฒด ์˜ˆ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import fetchSharedData from '../lib/fetch-shared-data'
import Layout from '../components/layout'

export const unstable_getStaticProps = async () => {
  const sharedData = await fetchSharedData()
  const pageProps = {...}

  return {  props: { ...sharedData, ...pageProps } }
}

const Page = () => (
  <Layout>
    <h1>Hello World!</h1>
  </Layout>
)

export default Page

์ด ์†”๋ฃจ์…˜์„ ๋ณด๊ณ  ์ดํ•ดํ•˜์ง€๋งŒ ์ œ๊ฐ€ ์ œ๊ธฐํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ๋ฌธ์ œ๋Š” ๊ณต์œ  ๋ฐ์ดํ„ฐ ์‚ฌ์šฉ๋Ÿ‰์„ ํ™•์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์ด์—ˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฒฝ์šฐ์— ๊ฐ€์ง€๊ณ  <Header /> ์šฉ๋„ ๋œ sharedData ๋งํฌ๋ฅผ ์–ป๊ธฐ ์œ„ํ•ด ๊ทธ๊ฐ€ ํ—ค๋“œ๋ฆฌ์Šค CMS์—์„œ์˜ค๊ณ ์žˆ๋‹ค. <Header /> ๋ฅผ <Layout /> ์˜ ์ž์‹์œผ๋กœ ์†Œํ’ˆ์ด๋‚˜ ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์œผ๋กœ ์ฃผ์ž…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€์— <Header /> ์ฃผ์ž…์„ ๋ฐ˜๋ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

HOC ์ ‘๊ทผ ๋ฐฉ์‹ ์„ ์‚ฌ์šฉํ•˜๋ฉด <Header /> ํ•œ ๋ฒˆ๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๊ฐ€๋Šฅํ•œ ํ•œ ์ฝ”๋“œ ์ค‘๋ณต์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด @pkral78 ์—์„œ ์ œ๊ธฐํ•œ ๊ฒƒ์ด ์ข‹์€ ์ง€์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๊ฐ€๋Šฅํ•œ ํ•œ ์ฝ”๋“œ ์ค‘๋ณต์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด @pkral78 ์—์„œ ์ œ๊ธฐํ•œ ๊ฒƒ์ด ์ข‹์€ ์ง€์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ๋‚ด ๋งˆ์Œ์— ์žˆ์—ˆ๋‹ค. _app ํŽ˜์ด์ง€์—๋Š” ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ์ค‘์— ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋œ ๋‹ค์Œ ์ €์žฅ๋œ props ๋ฅผ ๋‹ค์Œ ๋ Œ๋”๋ง๋œ ํŽ˜์ด์ง€๋กœ ์ „๋‹ฌํ•˜๋Š” getStaticProps ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๊ณผ์—ฐ ์ ์ ˆํ•œ ๊ฐœ๋…์ธ์ง€์— ๋Œ€ํ•ด ์—ฌ์ „ํžˆ ์ƒ๊ฐํ•˜๊ณ  ์žˆ๋‹ค.

์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ๊ฒƒ์ด ์˜๋„๋œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ธ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// /pages/[...slug].jsx
import ReactDOMServer from "react-dom/server";

export async function unstable_getStaticProps({ params: { slug } }) {
  const filePath = "../content/" + slug.join("/") + ".mdx";
  const { default: Component } = await import(filePath);
  const content = ReactDOMServer.renderToStaticMarkup(<Component />);
  return {
    props: { title: slug.join(" "), content }
  };
}

export default function Page({ title, content }) {
  return (
    <div>
      <h1>{title}</h1>
      <div dangerouslySetInnerHTML={{ __html: content }} />
    </div>
  );
}

์˜๋„๋œ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์•„๋‹ˆ๋”๋ผ๋„ ์•ฝ๊ฐ„ ์˜์‹ฌ์Šค๋Ÿฌ์šด ์˜ค๋ฅ˜๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.

[ warn ]  ./pages/[...slug].jsx
Critical dependency: the request of a dependency is an expression

ํŽธ์ง‘ํ•˜๋‹ค:

์˜ค, ๊ทธ๋ž˜, ๋‚ด๊ฐ€ ํ•  ๋•Œ ํ•ด๊ฒฐ๋œ๋‹ค

const { default: Component } = await import(`../content/${slug.join("/")}.mdx`);

https://codesandbox.io/s/happy-oskar-40bug

์ด๊ฒƒ์€ ๊ฐ€์ ธ์˜ค๊ธฐ ํŒŒ์ผ ๊ฒฝ๋กœ๊ฐ€ ๋™์ ์ด๋ผ๋Š” ๋ถˆํ‰์ž…๋‹ˆ๋‹ค.

2020๋…„ 1์›” 30์ผ ๋ชฉ์š”์ผ 00:29์— Jan Potoms [email protected]์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ์ผ์ธ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š๋‹ค.
https://codesandbox.io/s/nifty-cache-jspqr ์€ ์˜๋„๋œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ด์ง€๋งŒ
์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

// /pages/[...slug].jsximport ReactDOMServer from "react-dom/server";
๋น„๋™๊ธฐ ํ•จ์ˆ˜ ๋‚ด๋ณด๋‚ด๊ธฐ ๋ถˆ์•ˆ์ •_getStaticProps({ params: { ์Šฌ๋Ÿฌ๊ทธ } }) {
// ์ด๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ์•ˆ์ „ํ•œ๊ฐ€?
const ํŒŒ์ผ ๊ฒฝ๋กœ = "../๋‚ด์šฉ/" + slug.join("/") + ".mdx";
const { ๊ธฐ๋ณธ๊ฐ’: ๊ตฌ์„ฑ ์š”์†Œ } = import(filePath)๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค.
const ๋‚ด์šฉ = ReactDOMServer.renderToStaticMarkup(๊ตฌ์„ฑ ์š”์†Œ);
๋ฐ˜ํ’ˆ {
์†Œํ’ˆ: { ์ œ๋ชฉ: slug.join(" "), ์ฝ˜ํ…์ธ  }
};
}
๊ธฐ๋ณธ ํ•จ์ˆ˜ ๋‚ด๋ณด๋‚ด๊ธฐ ํŽ˜์ด์ง€({ ์ œ๋ชฉ, ๋‚ด์šฉ }) {
๋ฐ˜ํ’ˆ (


{์ œ๋ชฉ}




);
}

์˜๋„ํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์•„๋‹ˆ๋”๋ผ๋„ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๋ฅผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
์•ฝ๊ฐ„ ์˜์‹ฌ์Šค๋Ÿฌ์šด:

[๊ฒฝ๊ณ ] ./pages/[...slug].jsx
์ค‘์š” ์ข…์†์„ฑ: ์ข…์†์„ฑ ์š”์ฒญ์€ ํ‘œํ˜„์‹์ž…๋‹ˆ๋‹ค.

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธ
https://github.com/zeit/next.js/issues/9524?email_source=notifications&email_token=AAADKRKOL34WKTG7J5QFRJ3RAIGPBA5CNFSM4JRPBEL2YY3PNVWWK3TUL52HS4DFVREXG43VMXHJKTNMV0
๋˜๋Š” ๊ตฌ๋… ์ทจ์†Œ
https://github.com/notifications/unsubscribe-auth/AAADKRIWNA2DSMWFRGD453DRAIGPBANCNFSM4JRPBELQ
.

๊ทธ๋ž˜์„œ ๊ฐ€๋Šฅํ•œ ํ•œ ์ฝ”๋“œ ์ค‘๋ณต์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด @pkral78 ์—์„œ ์ œ๊ธฐํ•œ ๊ฒƒ์ด ์ข‹์€ ์ง€์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์€ ๋‚ด ๋งˆ์Œ์— ์žˆ์—ˆ๋‹ค. _app ํŽ˜์ด์ง€์—๋Š” ์ฒซ ๋ฒˆ์งธ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ์ค‘์— ํ•œ ๋ฒˆ ํ˜ธ์ถœ๋œ ๋‹ค์Œ ์ €์žฅ๋œ props ๋ฅผ ๋‹ค์Œ ๋ Œ๋”๋ง๋œ ํŽ˜์ด์ง€๋กœ ์ „๋‹ฌํ•˜๋Š” getStaticProps ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ์ ์ ˆํ•œ ๊ฐœ๋…์ธ์ง€ ์—ฌ์ „ํžˆ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

@pkral78 , ๋‚ด๊ฐ€ ์ƒ์ƒํ•˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ SSG ์‚ฌ์ดํŠธ์—์„œ Next๋กœ ๊ตฌํ˜„

๋‚ด ์œ ์ผํ•œ ๊ด€์‹ฌ์‚ฌ๋Š” _app.js ๋„ฃ์œผ๋ฉด ํŽ˜์ด์ง€์— ๋”ฐ๋ผ ํ•˜๋‚˜ ์ด์ƒ์˜ "๊ณตํ†ต ๋ถ€๋ถ„"์„ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ”„๋กœํ† ํƒ€์ž…์„ ๋งŒ๋“ค๊ณ  ์žˆ๋‹ค๋Š” ์•„์ด๋””์–ด๋กœ ๋ ˆ์ด์•„์›ƒ์— ํฌํ•จํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ์›ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ Œ๋”๋งํ•˜๋ ค๋Š” ํŽ˜์ด์ง€ ์œ ํ˜•์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๋ ˆ์ด์•„์›ƒ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. "๊ทธ๋ž˜์„œ withSSGLayout ๋ฅผ ํ˜ธ์ถœํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด HOC๋Š” SSG ํŽ˜์ด์ง€๋ฟ๋งŒ ์•„๋‹ˆ๋ผ SSR๊ณผ ์™„์ „ํ•œ ํด๋ผ์ด์–ธํŠธ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€, ๋˜๋Š” ํ•˜๋‚˜ ์ด์ƒ์˜ SSGLayout์„ ๊ฐ€์งˆ ๊ณ„ํš์ด์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ ˆ์ด์•„์›ƒ์ด ์ƒ์œ„ getStaticProps ๋ฉ”์„œ๋“œ๋„ ๋‹ด๋‹นํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด์จŒ๋“  Next์— SSG๊ฐ€ ์žˆ์œผ๋ฉด ๋ชจ๋“  ์ข…๋ฅ˜์˜ ์›น ์‚ฌ์ดํŠธ๋ฅผ ์œ„ํ•œ ๋„๊ตฌ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค ๐Ÿ™Œ

@Janpot ๊ด€๋ จ https://github.com/zeit/next.js/issues/9524#issuecomment -580012327

import() ์—์„œ ๋™์  ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ๊ฒฝ๋กœ ์•„๋ž˜์— ์žˆ๋Š” ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ํŒŒ์ผ์„ JS ๋ฒˆ๋“ค๋กœ ๋ฌถ๊ณ  ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ๋นŒ๋“œ ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ์ €ํ•˜๋ฉ๋‹ˆ๋‹ค.

@timneutkens ๋ฌผ๋ก ์ด์ฃ . ์ดํ•ด๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. getStaticProps ๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ์ด ์•„๋‹Œ ์™ธ๋ถ€ API๋ฅผ ์ฟผ๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๊นŒ?

@Janpot ํŒŒ์ผ ์‹œ์Šคํ…œ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์ข…์ข… ์™ธ๋ถ€ API๋ฅผ ์ฟผ๋ฆฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

@timneutkens ์ข‹์•„์š”, @next/mdx ์— ์˜์กดํ•˜๋Š” ๋Œ€์‹  @mdx-js/runtime ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค.

import ReactDOMServer from "react-dom/server";
import { promises as fs } from "fs";
import MDX from "@mdx-js/runtime";

export async function unstable_getStaticProps({ params: { slug } }) {
  const mdxContent = await fs.readFile(`./content/${slug.join('/')}.mdx`, {
    encoding: "utf-8"
  });
  const content = ReactDOMServer.renderToStaticMarkup(<MDX>{mdxContent}</MDX>);
  return {
    props: { title: slug.join(" "), content }
  };
}

export default function Page({ title, content }) {
  return (
    <div>
      <h1>{title}</h1>
      <div dangerouslySetInnerHTML={{ __html: content }} />
    </div>
  );
}

@์ž”ํŒŸ ๋„ค! ์ผ๋ฐ˜ ๋งˆํฌ๋‹ค์šด์„ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์šฐ๋ฆฌ๊ฐ€ nextjs.org/docs์—์„œ ํ•˜๋Š” ์ผ์ž…๋‹ˆ๋‹ค.

https://github.com/zeit/next.js/issues/9524#issuecomment -580207073์— ๊ด€ํ•ด์„œ๋Š” ํ˜„์žฌ SSR๊ณผ ํ•จ๊ป˜ Next๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค. ๋ ˆ์ด์•„์›ƒ ์ˆ˜์ค€์—์„œ ์ˆ˜ํ–‰๋˜๋Š” GraphQL ์š”์ฒญ์ด ์žˆ์œผ๋ฉฐ ํ•ด๋‹น ์ฝ˜ํ…์ธ ๋Š” ์•ฑ์˜ ๊ณตํ†ต ๊ตฌ์„ฑ ์š”์†Œ(Navbar, ๋ฐ”๋‹ฅ๊ธ€ ๋ฐ ๋™์  ์ž์‹)์™€ ๊ณต์œ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ๋™์  ์ž์‹์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํŽ˜์ด์ง€๋ณ„ ์ฝ˜ํ…์ธ ์— ๋Œ€ํ•ด ๋˜ ๋‹ค๋ฅธ GraphQL ์š”์ฒญ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์ด๊ฒƒ์„ ์žฌ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์ค‘์š”ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ์ €๋Š” ์ด๋Ÿฌํ•œ ๊ณตํ†ต ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ๊ฐ ํŽ˜์ด์ง€์— ์ฝ”๋“œ๋ฅผ ๋ณต์ œํ•˜๊ณ  ์‹ถ์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋ด!
๋‚˜๋Š” ์—ฌ๊ธฐ์—์„œ ์•„์ฃผ ์ƒˆ๋กญ๋‹ค. ์•ฑ์„ NextJS๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ์ž‘์—…์„ ๋ง‰ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์˜ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธ ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(๋‹ค๊ตญ์–ด ๋ฒ„์ „). ๋‚ด๊ฐ€ ์ž‘์—…ํ•˜๊ณ  ์žˆ๋Š” ์›น ์•ฑ์—๋Š” ํ•˜๋ฃจ์— 100,000ํšŒ ์ด์ƒ์˜ ํŽ˜์ด์ง€ ์กฐํšŒ์ˆ˜๊ฐ€ ์žˆ๋Š” 16๊ฐœ ์–ธ์–ด ๋ฒ„์ „์ด ์žˆ์œผ๋ฉฐ ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐฉ๋ฌธ ํŽ˜์ด์ง€๋ฅผ ์ •์ ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ํ™˜์ƒ์ ์ด์ง€๋งŒ ๋ฌธ์ œ๋Š” ๋ผ์šฐํŒ…์ž…๋‹ˆ๋‹ค.

์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง์„ ์‚ฌ์šฉํ•˜๋ฉด ์š”์ฒญ ํ—ค๋” ๋˜๋Š” ์ฟ ํ‚ค๋ฅผ ์ฝ๊ณ  ์ ์ ˆํ•œ ์–ธ์–ด ๋ฒ„์ „์„ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ๊ฒƒ ์—†์ด๋Š” /en, /de, /fr ๋ฐ "/"์™€ ๊ฐ™์€ ๋ชจ๋“  ๋ฒ„์ „์— ๋Œ€ํ•œ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  NextJS๊ฐ€ ๋ฆฌ๋””๋ ‰์…˜๋งŒ ํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ์œ ์ผํ•œ ์†”๋ฃจ์…˜์ž…๋‹ˆ๊นŒ?

ReactDOMServer.renderToStaticMarkup ์— ๋Œ€ํ•ด ๋ฐฐ์šด ํ›„ ์ด๋ฅผ unstable_getStaticProps ํ•จ์ˆ˜์— ์ถ”๊ฐ€ํ–ˆ์œผ๋ฉฐ ๋Œ€ํ™”ํ˜• ์‹œ๊ฐ„ ๋ฐ ์ตœ๋Œ€ ์ž ์žฌ์ ์ธ ์ฒซ ์ž…๋ ฅ ์ง€์—ฐ ์‹œ๊ฐ„์„ ๋Œ€ํญ ๊ฐœ์„ ํ•œ ๋•๋ถ„์— (๋ชจ๋ฐ”์ผ) PageSpeed โ€‹โ€‹์ ์ˆ˜๊ฐ€ 96์—์„œ 100์œผ๋กœ ํ–ฅ์ƒ๋˜์—ˆ์Œ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. .

JavaScript ์—†์ด ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•  ์ˆ˜ ์žˆ๊ณ  ์ž˜ ๋กœ๋“œ๋˜๋ฏ€๋กœ SSG๋ฅผ ์‚ฌ์šฉํ•จ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  React๊ฐ€ ํŽ˜์ด์ง€ ๋กœ๋“œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ React์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ๋ถ€์กฑํ•œ ๊ฒƒ์ผ ์ˆ˜๋„ ์žˆ์ง€๋งŒ JavaScript๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์„ฑ๋Šฅ์€ ๋™์ผํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๊ณ  ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์ „ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์ด ๋„์›€์ด ๋  ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(SSG๊ฐ€ ํ•˜๋Š” ์ผ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค).

์˜ˆ์ƒํ•œ ๊ฒƒ์ž…๋‹ˆ๊นŒ, ๋ฒ„๊ทธ์ž…๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ์ œ๊ฐ€ ์ž˜๋ชปํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๊นŒ?

์‚ฌ์ „ ์ปค๋ฐ‹: https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2F5e310826bcf5030008a91209--josephduffynextjs.netlify.com%2Fposts%2Fgathered-1-0-1&tab=mobile
์ปค๋ฐ‹: https://github.com/JosephDuffy/josephduffy.co.uk/pull/54/commits/d23898b874e5088ebcfabf577ee396b476ed97e4
์ปค๋ฐ‹ ํ›„: https://developers.google.com/speed/pagespeed/insights/?url=https%3A%2F%2F5e3371beda1b8f0009368ef9--josephduffynextjs.netlify.com%2Fposts%2Fgathered-1-0-1&tab=mobile

@JosephDuffy

๋”ฐ๋ผ์„œ React๋Š” SSG๋ฅผ ์‚ฌ์šฉํ•จ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ํŽ˜์ด์ง€ ๋กœ๋“œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

DOM์— ์ˆ˜๋ถ„์„ ๊ณต๊ธ‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์›๋ž˜:

  1. ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ธŒ๋ผ์šฐ์ € DOM์—์„œ SSR html์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.
  2. React๋Š” ์ „์ฒด ๊ฐ€์ƒ DOM์„ ์žฌ๊ตฌ์ถ•ํ•ฉ๋‹ˆ๋‹ค.
  3. React๋Š” ์ด๋Ÿฌํ•œ DOM์„ ํƒ์ƒ‰ํ•˜๊ณ  ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค(์ˆ˜ํ™”).

๋ถ€์ž‘์šฉ์ด๋‚˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์—†๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์ฝ˜ํ…์ธ ๊ฐ€ ์ง„์ •์œผ๋กœ ์ •์ ์ด๋ผ๋ฉด 2๋‹จ๊ณ„์™€ 3๋‹จ๊ณ„๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ท€ํ•˜์˜ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ตฌ์„ฑ ์š”์†Œ ํŠธ๋ฆฌ๋ฅผ 1 ์†์„ฑ์„ ๊ฐ€์ง„ 1 ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์ค„์ž…๋‹ˆ๋‹ค. ์ด๋Š” React๊ฐ€ ๋ Œ๋”๋งํ•˜๊ณ  ์ˆ˜ํ™”ํ•˜๋Š” ๋ฐ ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค. (+ dangerouslySetInnerHTM ๋Š” ์ˆ˜ํ™” ์ค‘ ๋ฌด์‹œ)

<div dangerouslySetInnerHTML={{ __html: props.htmlContent }} />

์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์™€ ๋ถ€์ž‘์šฉ์€ ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘ํ•˜๋‹ค:

ํ•œ ๊ฐ€์ง€ ์•„์ด๋””์–ด๋Š” getStaticProps ๊ฐ€ ์ •์  html์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ ํŽ˜์ด์ง€์—์„œ ๊ธฐ๋ณธ ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰

export async function unstable_getStaticProps() {
  // ...
  return {
    props: { dangerouslySetInnerHTML: { __html: '<div>static content</div>' } }
  };
}

ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋ Œ๋”๋งํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— next.js๋Š” ํŽ˜์ด์ง€์—์„œ ๋Ÿฐํƒ€์ž„์„ ์ œ์™ธํ•˜๊ณ  getStaticProps ๋ฐ˜ํ™˜ํ•œ html์„ ์ธ๋ผ์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  next.js ๋ฃจํŠธ ๋…ธ๋“œ์—์„œ dangerouslySetInnerHTML ๊ฐ€ ์‚ฌ์šฉ๋œ ๊ฒƒ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
๋‚˜๋Š” ๊ทธ๊ฒƒ์ด ๋œ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ ๋ถ€๋ถ„์ ์ธ ์ˆ˜ํ™”๋ณด๋‹ค ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ๋” ์‰ฌ์šธ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ React ์ž์ฒด์˜ ์šฉ์–ด๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฉด ์ด ๊ธฐ๋Šฅ์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•œ ํ˜ผ๋ž€์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ •์  ์‚ฌ์ดํŠธ๋ฅผ Next.js๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋ ค๊ณ  ํ•˜๋ฉฐ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์˜ ๋ชจ๋“  .html ๋ณ€ํ˜•์„ .html๋กœ ๋๋‚˜์ง€ ์•Š๋Š” ๋ฒ„์ „์œผ๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. getStaticProps ํ˜„์žฌ ์ปจํ…์ŠคํŠธ๋ฅผ ์–ป์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ ๊ฐ™์•„์„œ ๋“ค์–ด์˜ค๋Š” ์Šฌ๋Ÿฌ๊ทธ ๋ฐ ๋ฆฌ๋””๋ ‰์…˜์„ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. getStaticProps ์— ์ „์ฒด ์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์กฐ๊ฑด๋ถ€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

@nodabladam ์‚ฌ์šฉ์ž ์ง€์ • ๊ฒฝ๋กœ RFC: #9081์„ ์ฐพ๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ•ด๋‹น RFC๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// next.config.js
module.exports = {
  redirects() {
    return [
      // Redirect from the old HTML version of a blog post
      {
        source: "/blog/:post.html",
        destination: "/blog/:post",
        permanent: true
      }
    ];
  }
};

ํ˜„์žฌ experimental ํ‚ค์—์„œ ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// next.config.js
module.exports = {
  experimental: {
    redirects() {
      // ...
    }
  }
};

๋‚ด ํ”„๋กœ์ ํŠธ(์•ฝ 8K ํŽ˜์ด์ง€)์— getStaticProps ๋ฐ getStaticPathNames๋ฅผ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ถœ๋ ฅ ํŒŒ์ผ์€ ๋ฐฐํฌ๋‹น ํŒŒ์ผ์˜ 10K ์ œํ•œ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. 8K ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ ๊ฐ ํŽ˜์ด์ง€์— json ํŒŒ์ผ๋„ ์žˆ์œผ๋ฏ€๋กœ 16K์˜ ์ถœ๋ ฅ ํŒŒ์ผ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํ•œ๋„๋ฅผ ๋Š˜๋ฆด ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์ด ์ œํ•œ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚˜๋„ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ์•ˆ๊ณ ์žˆ์–ด.
๊ทธ๋“ค์ด ๊ทธ ํ•œ๋„๋ฅผ ๋†’์ด๋ ค๊ณ  ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ดํ•ดํ•˜์ง€๋งŒ ์–ธ์ œ ๋ฐฐํฌ๋ ์ง€๋Š” ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ €๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€์—์„œ getStaticProps๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ทธ ์ค‘ ์ผ๋ถ€์—์„œ๋งŒ getStaticPaths๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค(์ œ ์ œํ’ˆ ํŽ˜์ด์ง€๋Š” ์ „์ฒด ํŽ˜์ด์ง€์˜ 70%๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ getStaticPaths๋ฅผ ๋„ฃ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค). ํ•œ๋„์— ๋จธ๋ฌผ๊ณ  ์žˆ์ง€๋งŒ ์™„๋ฒฝํ•˜์ง€ ์•Š๊ณ  ์ฒซ ๋ฒˆ์งธ๋กœ๋“œ๊ฐ€ ์ƒ๋‹นํžˆ ๊ธธ๊ณ  404 ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋‚˜๋„ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ์•ˆ๊ณ ์žˆ์–ด.
๊ทธ๋“ค์ด ๊ทธ ํ•œ๋„๋ฅผ ๋†’์ด๋ ค๊ณ  ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ดํ•ดํ•˜์ง€๋งŒ ์–ธ์ œ ๋ฐฐํฌ๋ ์ง€๋Š” ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ €๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€์—์„œ getStaticProps๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ทธ ์ค‘ ์ผ๋ถ€์—์„œ๋งŒ getStaticPaths๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค(์ œ ์ œํ’ˆ ํŽ˜์ด์ง€๋Š” ์ „์ฒด ํŽ˜์ด์ง€์˜ 70%๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ getStaticPaths๋ฅผ ๋„ฃ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค). ํ•œ๋„์— ๋จธ๋ฌผ๊ณ  ์žˆ์ง€๋งŒ ์™„๋ฒฝํ•˜์ง€ ์•Š๊ณ  ์ฒซ ๋ฒˆ์งธ๋กœ๋“œ๊ฐ€ ์ƒ๋‹นํžˆ ๊ธธ๊ณ  404 ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๋“ค์ด ๊ณง ํ•œ๋„๋ฅผ ์˜ฌ๋ฆฌ๊ธฐ๋ฅผ ํฌ๋งํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์ด 20K๊ฐ€ ์•„๋‹ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์žฅ๊ธฐ์ ์œผ๋กœ ๋‚˜์—๊ฒŒ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

getStaticPaths๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ ์‹œ๊ฐ„์„ ํ”ผํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. Zeit Now ์™ธ์— ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์„ ์ฐพ์•„์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Next.js๋Š” getServerProps ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” API ๋์ ๋„ ์ž๋™์œผ๋กœ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. [...] Next.js๋Š” ์ด ๋…ธ์ถœ๋œ API ๋์ ์„ ๊ฐ€์ ธ์™€ ํŽ˜์ด์ง€ ํด๋ผ์ด์–ธํŠธ ์ธก์„ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์†Œํ’ˆ์œผ๋กœ ๋ณ€ํ™˜๋˜๋Š” JSON ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

Next.js๋Š” ์‹ค์ œ ๊ฒฝ๋กœ ๋ณ€๊ฒฝ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋ Œ๋”๋ง ํ•˜๊ธฐ ์ „์— ์ด ๋์ ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค(์ ์–ด๋„ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์Œ). ๋”ฐ๋ผ์„œ ์‚ฌ์šฉ์ž๋Š” ํŠน์ • ํŽ˜์ด์ง€๊ฐ€ ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋˜์–ด ๋งค์šฐ ๋น ๋ฅธ ์‚ฌ์ดํŠธ๋ฅผ ๊ฒฝํ—˜ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ SSR ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ๋งํฌ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๊ฒฝ๋กœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ธฐ ์ „์— ๊ฐ‘์ž๊ธฐ ์‚ฌ์ดํŠธ๊ฐ€ ์ž ์‹œ "๋ฉˆ์ถค"๋ฉ๋‹ˆ๋‹ค.

๋กœ๋“œ ํ‘œ์‹œ๊ธฐ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ž๋ฆฌ ํ‘œ์‹œ์ž ๋“ฑ์œผ๋กœ ์ฑ„์šธ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑ ์š”์†Œ _first_๋ฅผ ๋กœ๋“œํ•˜๋Š” ๊ถŒ์žฅ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? (ํ˜„์žฌ ํŽ˜์ด์ง€์— ์ถ”๊ฐ€ํ•˜๋Š” ๋Œ€์‹ .) ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ์ƒˆ๋กœ ์ œ์•ˆ๋œ ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? render ๋ฉ”์†Œ๋“œ ๋‚ด๋ถ€์— getInitialProps์™€ hooks ์กฐํ•ฉ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ฌ์„ฑํ–ˆ์ง€๋งŒ ์ง€์ €๋ถ„ํ•œ ๋Š๋‚Œ์ด ๋“ญ๋‹ˆ๋‹ค.

๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ด UX ํŒจํ„ด(์ฆ‰์„ ํŽ˜์ด์ง€ ์ „ํ™˜)์„ ์„ ํ˜ธํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ(๋Œ€๋ถ€๋ถ„?) Next.js๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ๋Š” ์•„์ง ๋ณธ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค. ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•œ์ง€ ๋ฉฐ์น  ๋˜์ง€ ์•Š์•˜์œผ๋‹ˆ ํ‹€๋ฆฐ ๋ถ€๋ถ„์ด ์žˆ์œผ๋ฉด ์ง€์  ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ์ •๋ง ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค! ์ž‘์—…ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

@nicoqh , ํ˜„์žฌ getInitialProps ์—์„œ ์ค‘๋‹จ์ด ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŽ˜์ด์ง€ ์ „ํ™˜์— ๋Œ€ํ•œ ๊ท€ํ•˜์˜ ์šฐ๋ ค๋Š” SSG์—๋งŒ ๊ตญํ•œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” nprogress ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ ํŽ˜์ด์ง€๊ฐ€ ๋กœ๋“œ๋˜๋Š” ๋™์•ˆ ์ตœ์†Œํ•œ ๋งจ ์œ„์— ์ง„ํ–‰๋ฅ  ํ‘œ์‹œ์ค„์„ ํ‘œ์‹œํ•˜์ง€๋งŒ ์„ค๋ช…ํ•˜๋Š” ๋‚ด์šฉ์— ๋” ๊ฐ€๊น๊ฒŒ ๋“ค๋ฆฌ๋Š” ํ•ฉ๋ฒ•์ ์ธ ํŽ˜์ด์ง€ ์ „ํ™˜์ด ์žˆ๋Š” ์ด ์˜ˆ๋„ ๋ด…๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ง์ ‘ ์‹œ๋„ํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋‹น์‹ ์ด ํ•„์š”๋กœํ•˜๋Š” ๊ฒƒ์— ๋„์›€์ด๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.
https://github.com/zeit/next.js/tree/canary/examples/with-next-page-transitions

๋ฐ˜ํ™˜๋œ json ํŒŒ์ผ /_next/data/BUILD_ID/<file>.json ์ด assetPrefix๋ฅผ ์กด์ค‘ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๋‚ด ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ํŒŒ์ผ์ด 404๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋ชจ๋“  _next๊ฐ€ CDN์„ ํ†ต๊ณผํ•˜๋Š” ์ž์‚ฐ์ด ๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•˜๋Š” ์„ค์ •์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ json ํŒŒ์ผ์€ ๊ถ๊ทน์ ์œผ๋กœ assetPrefix(CDN)๋ฅผ ํ†ตํ•ด ๋ผ์šฐํŒ…๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋งž๋‚˜์š”?

๋‚˜๋„ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ์•ˆ๊ณ ์žˆ์–ด.
๊ทธ๋“ค์ด ๊ทธ ํ•œ๋„๋ฅผ ๋†’์ด๋ ค๊ณ  ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ดํ•ดํ•˜์ง€๋งŒ ์–ธ์ œ ๋ฐฐํฌ๋ ์ง€๋Š” ๋ชจ๋ฆ…๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์ €๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€์—์„œ getStaticProps๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ทธ ์ค‘ ์ผ๋ถ€์—์„œ๋งŒ getStaticPaths๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค(์ œ ์ œํ’ˆ ํŽ˜์ด์ง€๋Š” ์ „์ฒด ํŽ˜์ด์ง€์˜ 70%๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ getStaticPaths๋ฅผ ๋„ฃ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค). ํ•œ๋„์— ๋จธ๋ฌผ๊ณ  ์žˆ์ง€๋งŒ ์™„๋ฒฝํ•˜์ง€ ์•Š๊ณ  ์ฒซ ๋ฒˆ์งธ๋กœ๋“œ๊ฐ€ ์ƒ๋‹นํžˆ ๊ธธ๊ณ  404 ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๋“ค์ด ๊ณง ํ•œ๋„๋ฅผ ์˜ฌ๋ฆฌ๊ธฐ๋ฅผ ํฌ๋งํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์ด 20K๊ฐ€ ์•„๋‹ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์žฅ๊ธฐ์ ์œผ๋กœ ๋‚˜์—๊ฒŒ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

getStaticPaths๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ ์‹œ๊ฐ„์„ ํ”ผํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. Zeit Now ์™ธ์— ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์„ ์ฐพ์•„์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

@erhankaradeniz ๋ฐ @ziltosh ์šฐ๋ฆฌ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋งค์šฐ ๋น ๋ฅธ ์‹œ์ผ ๋‚ด์— ์ด๋ฅผ ์ถœ์‹œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ๋„์›€์„ ๋ฐ›๊ณ  ์‹ถ๋‹ค๋ฉด ์ €์—๊ฒŒ ์ง์ ‘ ping์„ ๋ณด๋‚ด ๊ฑฐ๋‚˜

๋‚˜๋„ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ์•ˆ๊ณ ์žˆ์–ด.
๊ทธ๋“ค์ด ๊ทธ ํ•œ๋„๋ฅผ ๋†’์ด๋ ค๊ณ  ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ์ดํ•ดํ•˜์ง€๋งŒ ์–ธ์ œ ๋ฐฐํฌ๋ ์ง€๋Š” ๋ชจ๋ฆ…๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์ €๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€์—์„œ getStaticProps๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ทธ ์ค‘ ์ผ๋ถ€์—์„œ๋งŒ getStaticPaths๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค(์ œ ์ œํ’ˆ ํŽ˜์ด์ง€๋Š” ์ „์ฒด ํŽ˜์ด์ง€์˜ 70%๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ getStaticPaths๋ฅผ ๋„ฃ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค). ํ•œ๋„์— ๋จธ๋ฌผ๊ณ  ์žˆ์ง€๋งŒ ์™„๋ฒฝํ•˜์ง€ ์•Š๊ณ  ์ฒซ ๋ฒˆ์งธ๋กœ๋“œ๊ฐ€ ์ƒ๋‹นํžˆ ๊ธธ๊ณ  404 ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ทธ๋“ค์ด ๊ณง ํ•œ๋„๋ฅผ ์˜ฌ๋ฆฌ๊ธฐ๋ฅผ ํฌ๋งํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์ด 20K๊ฐ€ ์•„๋‹ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์žฅ๊ธฐ์ ์œผ๋กœ ๋‚˜์—๊ฒŒ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
getStaticPaths๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฒซ ๋ฒˆ์งธ ๋กœ๋“œ ์‹œ๊ฐ„์„ ํ”ผํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. Zeit Now ์™ธ์— ๋‹ค๋ฅธ ์†”๋ฃจ์…˜์„ ์ฐพ์•„์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

@erhankaradeniz ๋ฐ @Ziltosh ์šฐ๋ฆฌ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ๋งค์šฐ ๋น ๋ฅธ ์‹œ์ผ ๋‚ด์— ์ด๋ฅผ ์ถœ์‹œ ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ตœ๋Œ€ํ•œ ๋นจ๋ฆฌ ๋„์›€์„ ๋ฐ›๊ณ  ์‹ถ๋‹ค๋ฉด ์ €์—๊ฒŒ ์ง์ ‘ ping์„ ๋ณด๋‚ด ๊ฑฐ๋‚˜

@kvangundy ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค
์ด ๋ฌธ์ œ์™€ ๊ด€๋ จํ•˜์—ฌ Twitter์—์„œ ์—ฐ๋ฝ์„ ๋“œ๋ ธ์Šต๋‹ˆ๋‹ค ;-)

@erhankaradeniz ๋Œ€์‹  [email protected]๋กœ ์ด๋ฉ”์ผ์„

@flintinatux , ํŒ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ์ œ๋ฅผ ๋ดค๋Š”๋ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•˜๊ธฐ ์ „์— ํŽ˜์ด์ง€ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋กœ๋“œํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํŽ˜์ด์ง€ ๋‚ด ์ž๋ฆฌ ํ‘œ์‹œ์ž ๋“ฑ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜๋„ ํฅ๋ฏธ๋กœ์šด ์˜ˆ์ž…๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

์ด ๋ฌธ์ œ์—์„œ๋Š” ๋‹ค๋ฃจ์ง€ ์•Š์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚ฌ์œผ๋ฏ€๋กœ ๋…ผ์˜ํ•  ๋‹ค๋ฅธ ๊ณณ์„ ์ฐพ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. :)

getInitialProps๋ฅผ getStaticProps & getServerProps ๋กœ ๋‚˜๋ˆ„๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์ด ํ›จ์”ฌ ๊น”๋”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค! ์ด๊ฒƒ์ด ์šฐ๋ฆฌ์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์–ด๋–ค ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š”์ง€ ์งˆ๋ฌธ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๋Š” 2๊ฐœ์˜ ๊ฐœ๋ณ„ ๋นŒ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ํ•˜๋‚˜๋Š” ํ”„๋กœ๋•์…˜ ์‚ฌ์ดํŠธ์šฉ ์ •์  ๋ฒ„์ „์ด๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ํŽธ์ง‘ ํ™˜๊ฒฝ์šฉ SSR์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฒ„์ „์ž…๋‹ˆ๋‹ค.

์กฐ๊ฑด๋ถ€๋กœ getStaticProps vs getServerProps ๋ฅผ ๋นŒ๋“œ์— ๋”ฐ๋ผ ์ •์  ๋ฉ”์„œ๋“œ๋กœ ์ฒจ๋ถ€ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค(https://github.com/zeit/next.js/issues/9524#issuecomment-์™€ ์œ ์‚ฌ). 558617056), ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด ์กฐ๊ฑด๋ถ€๋กœ ๊ทธ๋Œ€๋กœ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋นŒ๋“œ์— ๋”ฐ๋ผ ๋™์ /์ •์ ์„ ์ง€์›ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์–ด๋–ค ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์— ๊ด€ํ•ด์„œ:

RFC๋Š” ๋‚˜์ค‘์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜๋„๋ก ์—…๋ฐ์ดํŠธ๋˜๋ฉฐ ์•ฑ์—์„œ ์‹ค์ œ ์‚ฌ์šฉ์„ ๊ณ„์† ๋ฐ˜๋ณตํ•ฉ๋‹ˆ๋‹ค.

๋นŒ๋“œ ์‹œ ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒฝ๋กœ๋ฅผ ์žก๊ธฐ ์œ„ํ•ด ์ผ์ข…์˜ ์™€์ผ๋“œ ์นด๋“œ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด CMS ๋ฐ์ดํ„ฐ์—์„œ ์ •์  ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๋ฉ‹์ง„ ์ผ์ด์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€ ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ์ •์  ํŽ˜์ด์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ์˜ค๋žซ๋™์•ˆ ๋‚ด ๋จธ๋ฆฌ๋ฅผ ๊ธ์ ์ž…๋‹ˆ๋‹ค.

์ •์  ํŽ˜์ด์ง€ _pages/[slug].js_๋ฅผ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด ๋™์  ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. _getStaticPaths_๋Š” ์ •์ ์œผ๋กœ ๋ Œ๋”๋งํ•˜๋ ค๋Š” ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. _getStaticProps_๊ฐ€ ์žˆ์–ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฟผ๋ฆฌํ•˜๊ณ  ์ด๋ฅผ ๋ Œ๋” ํ•จ์ˆ˜์— ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. _getStaticPaths_์— ์ œ๊ณต๋œ ๋ชจ๋“  ํŽ˜์ด์ง€๋Š” ๋นŒ๋“œ ์‹œ _.next/server/static_ ๋‚ด๋ถ€์—์„œ HTML ํŒŒ์ผ๋กœ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ์—„์ฒญ๋‚œ!

์ด์ œ npm run start ๋ฐ ์ด ํŽ˜์ด์ง€๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ˆ„๋ฝ๋œ URL(์˜ˆ: _/foo_)์„ ์š”์ฒญํ•˜๋ฉด _.next/server/static_ ๋‚ด๋ถ€์— ์ƒˆ๋กœ์šด ์ •์  HTML ๋ฐ JSON ํŒŒ์ผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ข‹์ง€ ์•Š๋‹ค. ๋‹ค๋ฅธ ๋ชจ๋“  URL์„ _pages/_error.js_๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋„๋ก ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

https://github.com/zeit/next.js/issues/9524#issuecomment -582777067

์šฐ๋ฆฌ๋„ ๊ทธ๊ฒƒ์„ ๋‹ค๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ npm run start ๋ฐ ์ด ํŽ˜์ด์ง€๋ฅผ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ˆ„๋ฝ๋œ URL(์˜ˆ: /foo)์„ ์š”์ฒญํ•˜๋ฉด .next/server/static ๋‚ด๋ถ€์— ์ƒˆ๋กœ์šด ์ •์  HTML ๋ฐ JSON ํŒŒ์ผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ข‹์ง€ ์•Š๋‹ค. ๋‹ค๋ฅธ ๋ชจ๋“  URL์„ ํŽ˜์ด์ง€/_error.js๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋„๋ก ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์ด๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์ง„ํ–‰ ์ค‘์ด๋ฉฐ ํ˜„์žฌ๋กœ์„œ๋Š” ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋™์ž‘์ด ์•„๋‹™๋‹ˆ๋‹ค.

์‹คํ—˜์ ์ธ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ ์ค‘์ด๋ฉฐ ๋™์ž‘์€ ์–ธ์ œ๋“ ์ง€ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Œ์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์•Œ๋ ค๋“œ๋ฆฝ๋‹ˆ๋‹ค. ์•ˆ์ •์ ์ด์ง€ ์•Š์„ ๋•Œ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ ๋ชจ๋“  ๋ฒ„์ „ ๊ฐ„์— ์ƒํ™ฉ์ด ๋ณ€๊ฒฝ๋˜๊ณ  ์ž ์žฌ์ ์œผ๋กœ ์ค‘๋‹จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@timneutkens ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ๋ถˆ์•ˆ์ •ํ•จ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๊ณ  _unstable_getStaticProps_ ๋‚ด๋ถ€์— ์˜ค๋ฅ˜๋ฅผ ๋˜์ง€๋ฉด ์˜ค๋ฅ˜ ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ข‹์€ ๋ฐฉ๋ฒ•์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. _pages/_error.js_์— ์žˆ๋Š” ๊ทธ๋Œ€๋กœ ์˜ค๋ฅ˜๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. 404๋กœ ๋ณด๋‚ด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์ด์ œ 500์œผ๋กœ ๊ฐ‘๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์„ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ๊ฒŒ์‹œํ–ˆ์ง€๋งŒ "_error๋กœ ๊ฐ€๋Š” ๊ฒƒ"์€ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋™์ž‘์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ท€ํ•˜์˜ ํŽ˜์ด์ง€๋Š” 404 ์ƒํƒœ๋ฅผ ๋ Œ๋”๋งํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํžˆ if(!data.something) { return <My404Component /> } ๋ผ๊ณ  ๋งํ•œ ๋‹ค์Œ My404Component ๋Š” noindex ๋ฉ”ํƒ€ ํƒœ๊ทธ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ง„์งœ? ๋ฌธ์„œ์—๋Š” 404์— _pages/_error.js_๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ช…์‹œ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ์กฐ: https://nextjs.org/docs/advanced-features/custom-error-page

@jiv-e๋Š” ๋‹ค์Œ์œผ๋กœ ์ธํ•ด 404์ดˆ ๋™์•ˆ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

  • ํŽ˜์ด์ง€๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Œ
  • ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์—†์Œ

๋™์  ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๋‚ด๊ฐ€ ๋งํ•œ ๊ฒƒ์ฒ˜๋Ÿผ "404" ์‚ฌ๋ก€๋ฅผ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: https://nextjs.org/docs/advanced-features/custom-error-page#reusing -the-built-in-error-). ํŽ˜์ด์ง€

์•Œ์•˜์–ด์š”! ๊ฐ์‚ฌ ํ•ด์š”!

getStaticProps ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋นŒ๋“œ ์‹œ ๋ฒˆ์—ญ/์–ธ์–ด ํ‚ค๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๊ทธ๋“ค์€ ํ•œ ๋‹ฌ์— 1-2๋ฒˆ ๋˜๋Š” ์‹ฌ์ง€์–ด ๋งค๋…„ ๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ DOM ๋‚ด์—์„œ JSON/props๋กœ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌธ์ œ๋Š” ํ‚ค๋ฅผ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ์„ฑ ์š”์†Œ๋กœ ํŠธ๋ฆฌ ์•„๋ž˜๋กœ ์ „๋‹ฌํ•˜๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์‚ฌ๋ก€์— ์ ํ•ฉํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ปจํ…์ŠคํŠธ๊ฐ€ ์žˆ๋Š” useTranslation() ํ›„ํฌ(๋˜๋Š” HOC)?

AppTree ๊ฐ€ NextGetStaticProps ์ปจํ…์ŠคํŠธ( getStaticProps({ AppTree }) )์˜ ์ผ๋ถ€๊ฐ€ ๋˜๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ssg์—์„œ apollos getDataFromTree ์™€ ๊ฐ™์€ ๊ฒƒ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด ์‹œ์ ์—์„œ ์šฐ๋ฆฌ๋Š” getStaticProps์—์„œ AppTree ํƒ์ƒ‰์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์„ ๊ณ„ํš์ž…๋‹ˆ๋‹ค. ์„ฑ๋Šฅ์— ๋งค์šฐ ์ข‹์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค(ํšŒ์‚ฌ์˜ ์ผ๊ด€๋œ ํ”ผ๋“œ๋ฐฑ). ํŽ˜์ด์ง€์— getStaticProps๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์—ฌ์ „ํžˆ _app์˜ getInitialProps๋ฅผ ํ†ตํ•ด ์ ์ง„์  ์ฑ„ํƒ์„ ํ—ˆ์šฉํ•˜๋ฏ€๋กœ Apollo์™€ ์—ฌ์ „ํžˆ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

amp: 'hybrid' ์™€ SSG ๊ธฐ๋Šฅ์„ ๋™์‹œ์— ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŽ˜์ด์ง€์— ๋Œ€ํ•ด ๋‘ ๊ฐœ์˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์—ฌ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • (SSG) index.html
  • (AMP) index.amp.html

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ”„๋ก์‹œ๊ฐ€ ?amp=1 ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ amp ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

amp: 'hybrid' ์™€ SSG ๊ธฐ๋Šฅ์„ ๋™์‹œ์— ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŽ˜์ด์ง€์— ๋Œ€ํ•ด ๋‘ ๊ฐœ์˜ ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜์—ฌ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • (SSG) index.html
  • (AMP) index.amp.html

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํ”„๋ก์‹œ๊ฐ€ ?amp=1 ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ amp ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ •ํ™•ํžˆ @Dacturne , ์ด๊ฒƒ์€ ์ œ๊ฐ€ ์ด ์Šค๋ ˆ๋“œ ์‹œ๊ฐ„ ์ „์— ์–ธ๊ธ‰ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ํ”„๋กœ์ ํŠธ์—์„œ ์ด๋ฏธ SSG๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋Š” ์œ ์ผํ•œ ๋‹จ์ ์ž…๋‹ˆ๋‹ค.

๐Ÿคž

@jansedlon ๊ท€ํ•˜์˜ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์„ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

๋นŒ๋“œ ์‹œ ์•Œ ์ˆ˜ ์—†๋Š” ๊ฒฝ๋กœ๋ฅผ ์žก๊ธฐ ์œ„ํ•ด ์ผ์ข…์˜ ์™€์ผ๋“œ ์นด๋“œ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด CMS ๋ฐ์ดํ„ฐ์—์„œ ์ •์  ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๋ฉ‹์ง„ ์ผ์ด์ง€๋งŒ ๋ˆ„๊ตฐ๊ฐ€ ์ƒˆ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ๋‚˜๋Š” ๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ์ •์  ํŽ˜์ด์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ์˜ค๋žซ๋™์•ˆ ๋‚ด ๋จธ๋ฆฌ๋ฅผ ๊ธ์ ์ž…๋‹ˆ๋‹ค.

https://paqmind.com/en/blog/ssr-is-not-the-future

(๋„ˆ๋ฌด ์ปค์„œ ์—ฌ๊ธฐ์— ์˜ฌ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค)

@ivan-kleshnin ๊ฐ„๋‹จํžˆ ์‚ดํŽด๋ณด์•˜๋Š”๋ฐ ์ •๋ง ํฅ๋ฏธ์ง„์ง„ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค! ๋‹น์‹ ์€ ๋‚˜์—๊ฒŒ ์ˆ˜๋ฐฑ ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ–ˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋Š˜์€ ๋‚˜์ค‘์— ์ž์„ธํžˆ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

https://github.com/zeit/next.js/issues/9524#issuecomment -582799948

@jansedlon ์•ž์„œ ๋งํ–ˆ๋“ฏ์ด @ivan-kleshnin์˜ ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ์—์„œ ๋‹ค๋ฃจ์ง€ ์•Š์€ ์ด๊ฒƒ๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ž‘์—…ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์กฐ๋งŒ๊ฐ„ ์ด์— ๋Œ€ํ•ด ๋” ๋งŽ์€ ์ •๋ณด๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

@timneutkens ์ง€๊ธˆ๊นŒ์ง€์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค ๐Ÿ™ ์™„์ „ํ•œ ์ •์  + ๊ตญ์ œํ™”๋ฅผ ๊ฐœ์„ /์ง€์›ํ•  ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์šฐ๋ฆฌ๋Š” Gatsby์—์„œ Next.js๋กœ tinacms.org๋ฅผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•  ๋•Œ ์ƒˆ๋กœ์šด getStaticProps / getStaticPaths API๋ฅผ ์‚ฌ์šฉํ•ด ์™”์œผ๋ฉฐ ์ง€๊ธˆ๊นŒ์ง€๋Š” ํ›Œ๋ฅญํ–ˆ์Šต๋‹ˆ๋‹ค!

์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง„ ํ•œ ๊ฐ€์ง€ ๊ฑธ๋ฆผ๋Œ์€ RSS ํ”ผ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฐธ์กฐํ•˜๋Š” ์ฝ˜ํ…์ธ ๊ฐ€ ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์ƒ์ ์œผ๋กœ๋Š” ์ •์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ๋กœ์„œ๋Š” ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ์ฝ˜ํ…์ธ ๋ฅผ ์ฟผ๋ฆฌํ•˜๊ณ  ์‘๋‹ต์— XML์„ ์ž‘์„ฑํ•˜์—ฌ ์„œ๋ฒ„ ์ธก์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

HTML์ด ์•„๋‹Œ ์ฝ˜ํ…์ธ  ์œ ํ˜•์— ๋Œ€ํ•œ ์ •์  ์ƒ์„ฑ ์ง€์›์— ๋Œ€ํ•œ ๋…ผ์˜๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๊นŒ?

์ฐธ๊ณ ๋กœ ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ zeit์—์„œ getStaticProps ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๊ณ  --prod ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฆด๋ฆฌ์Šค์™€ ์ƒˆ ๋ฆด๋ฆฌ์Šค์˜ json ํŒŒ์ผ์— ๋Œ€ํ•œ ์บ์‹œ๊ฐ€ ์ง€์›Œ์ง€์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋ณ„์นญ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ”„๋กœ๋•์…˜ ๋ฆด๋ฆฌ์Šค๋ฅผ ๋‹ค์‹œ ์ „ํ™˜ํ•˜๋ฉด ์บ์‹œ๊ฐ€ ์ง€์›Œ์ง‘๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” Gatsby์—์„œ Next.js๋กœ tinacms.org๋ฅผ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•  ๋•Œ ์ƒˆ๋กœ์šด getStaticProps / getStaticPaths API๋ฅผ ์‚ฌ์šฉํ•ด ์™”์œผ๋ฉฐ ์ง€๊ธˆ๊นŒ์ง€๋Š” ํ›Œ๋ฅญํ–ˆ์Šต๋‹ˆ๋‹ค!

์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์ง„ ํ•œ ๊ฐ€์ง€ ๊ฑธ๋ฆผ๋Œ์€ RSS ํ”ผ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฐธ์กฐํ•˜๋Š” ์ฝ˜ํ…์ธ ๊ฐ€ ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ด์ƒ์ ์œผ๋กœ๋Š” ์ •์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ๋กœ์„œ๋Š” ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ์ฝ˜ํ…์ธ ๋ฅผ ์ฟผ๋ฆฌํ•˜๊ณ  ์‘๋‹ต์— XML์„ ์ž‘์„ฑํ•˜์—ฌ ์„œ๋ฒ„ ์ธก์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

HTML์ด ์•„๋‹Œ ์ฝ˜ํ…์ธ  ์œ ํ˜•์— ๋Œ€ํ•œ ์ •์  ์ƒ์„ฑ ์ง€์›์— ๋Œ€ํ•œ ๋…ผ์˜๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๊นŒ?

ํ˜ผ์ž ์ƒ๊ฐํ•˜๋‹ค๊ฐ€ ์ด๋ฒˆ์— ์•Œ๊ฒŒ ๋˜์—ˆ์–ด์š”. ๋‚ด ์Šคํฌ๋ฆฝํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

"scripts": {
    "dev": " next",
    "build": "yarn sitemap && next build",
    "start": "next start",
    "sitemap": "ts-node --project ./cli/tsconfig.spec.json ./cli/generateSitemap.ts"
  },

next build ์—๋Š” ์ •์ ์œผ๋กœ ์‚ฌ์ดํŠธ๋งต์„ ์ƒ์„ฑํ•˜๋Š” yarn sitemap ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด getStaticProps ํ•„์š”ํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ json์— ์บ์‹œํ•˜๊ธฐ ์œ„ํ•ด ๋™์ผํ•œ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์—์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์€ RFC ์—…๋ฐ์ดํŠธ, ๋ณ€๊ฒฝ getStaticPaths ๋™์ž‘์„ ์กฐ๊ธˆ (๋‹น์‹ ์ด ๋ฐ˜ํ™˜ํ•ด์•ผ paths , ์ง€๊ธˆ์ด ๊ฑฐ์šธ ํ‚ค๋ฅผ getStaticProps ๊ณณ์€ props ๋ฐ˜ํ™˜ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.์ด๋ฅผ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์€ ์•„์ง Next.js์— ์ ์šฉ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ fallback ๋™์ž‘์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค(๋นŒ๋“œ ์‹œ ๋‚ด๋ณด๋‚ด์ง€ ์•Š์€ ํŽ˜์ด์ง€์˜ ์˜จ๋””๋งจ๋“œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ƒ์„ฑ).

RFC์— ๋Œ€ํ•œ ๋˜ ๋‹ค๋ฅธ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ–ˆ์œผ๋ฉฐ Loading ์ƒํƒœ์™€ ๊ด€๋ จ๋œ ํด๋ผ์ด์–ธํŠธ ํƒ์ƒ‰ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋กœ๋”ฉ ์ƒํƒœ๊ฐ€ React ํ›„ํฌ๋ฅผ ํ†ตํ•ด ๋ Œ๋”๋ง๋˜๊ณ  ์žˆ๋Š”์ง€ ์‚ฌ์šฉ์ž๊ฐ€ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค ๐Ÿค”

์ข‹์€ ๋ฌผ๊ฑด! ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€๊ฐ€ ๋‹จ์ผ JSON ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฒฝ๋กœ ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค(์ฝ”๋“œ ๋ถ„ํ• ๊ณผ ๊ฐ™์ง€๋งŒ ๋ฐ์ดํ„ฐ์šฉ)?

๋‚˜๋Š” ์ตœ์‹  canary ๋นŒ๋“œ์— ๋ถ€๋”ช์ณค๊ณ  ์ฆ‰์‹œ ์ƒˆ๋กœ์šด Loading ์ƒํƒœ์— ๋น ์กŒ์Šต๋‹ˆ๋‹ค. ๊ณผ๊ฑฐ์—๋Š” ๋ทฐ ๋ ˆ์ด์–ด๊ฐ€ ๋ Œ๋”๋ง์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— ์ด๋ฏธ ์˜ฌ๋ฐ”๋ฅธ ๋ฐ์ดํ„ฐ๋ฅผ ์–ป์—ˆ๋‹ค๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๊ฐ€์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์•˜์Šต๋‹ˆ๋‹ค. ๊ฐ•์ œ ๋น„๋™๊ธฐ ๋กœ๋”ฉ์€ ๊ทธ๊ฒƒ๊ณผ ํฌ๊ฒŒ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ƒˆ๋กœ์šด ์ž๋™ ์ƒ์„ฑ SSR ๋์ ์ด ๋Œ€์ฒดํ•  ๋ชจ๋“  ์ƒ์šฉ๊ตฌ ๋์ ์„ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์„ ์ •๋ง ์ฆ๊ฒผ์ง€๋งŒ ์ƒˆ๋กœ์šด Loading ์ƒํƒœ๋ฅผ ํฌํ•จํ•˜๋„๋ก ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ๋””์ž์ธํ•  ๊ณ„ํš์€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

๋” ๋น ๋ฅธ TTFB์— ๋Œ€ํ•œ ์—ด๋ง๊ณผ ๋ฏธ๋ž˜์—๋Š” ๋‚ด ์•ฑ์— ์ข‹์€ ๊ธฐ๋Šฅ์ด ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ•  ์ˆ˜์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค Loading ์ƒํƒœ ์œ ์‚ฌํ•œ ์˜ตํŠธ ์ธ ๋˜๋Š” ์˜ตํŠธ ์•„์›ƒ ๊ธฐ๋Šฅ, fallback: false ์— ๋Œ€ํ•ด getStaticPaths ? ํŽ˜์ด์ง€์˜ export const enableLoadingState = false ๋˜๋Š” next.config.js ์‚ฌ์ดํŠธ ์ „์ฒด

https://github.com/zeit/next.js/issues/9524#issuecomment -583962425

์‹คํ—˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ ์ค‘์ด๋ฉฐ ํ˜„์žฌ ์ด ๋™์ž‘์„ ์‹คํ—˜ํ•˜๊ณ  ์žˆ์Œ์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์•Œ๋ ค๋“œ๋ฆฝ๋‹ˆ๋‹ค.

๋‚ด (์‹คํ—˜์ ) SSG ์›น ์‚ฌ์ดํŠธ๋ฅผ Now(๊ธฐ๋ณธ ์„ค์ • ์‚ฌ์šฉ)์— ๋ฐฐํฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ž˜ ์ž‘๋™ํ•˜์ง€๋งŒ ์‚ฌ์ดํŠธ๋ฅผ ํƒ์ƒ‰ํ•  ๋•Œ ๋„คํŠธ์›Œํฌ ํƒญ์— 404 ์˜ค๋ฅ˜๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  404 ์˜ค๋ฅ˜๋Š” _next/static/pages/[slug].js ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

์‹คํ—˜ ์ค‘์— ์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์ž…๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์ผ๋ถ€ ์„ค์ •์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

@joostmeijles ์˜ฌ๋ฐ”๋ฅธ href ๋ฐ as ์„ next/link . ๋™์  ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ href ๋Š” ํŽ˜์ด์ง€ href='/[slug]' ์—ฌ์•ผ ํ•˜๊ณ  as ๋Š” URL as='/slug-1' ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋นŒ๋“œํ•˜๋Š” ๋™์•ˆ ์ฝ˜์†”์— 3๊ฐœ์˜ ๋กœ๊ทธ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๋ฒ„๊ทธ์ธ๊ฐ€์š”?

// Page is showing three logs despite static path only having 2 entries and output generating only two files as intended
export default function Page(props){
    console.log("Page - should only show twice", props); 
    return <><h1>Page</h1></>
}

export async function unstable_getStaticProps(props) {
    console.log("unstable_getStaticProps - should only show twice", props);
    return {
      props
    };

}

export async function unstable_getStaticPaths() {
    console.log("show once")
    return {
        paths: [
        { params: { year: "1901" } },
        { params: { year: "1902" } },
        ]
    }
}

์•„๋‹ˆ์š”, RFC์˜ fallback ์— ๋”ฐ๋ผ ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค.

์•„๋‹ˆ์š”, RFC์˜ fallback ์— ๋”ฐ๋ผ ์˜ˆ์ƒ๋ฉ๋‹ˆ๋‹ค.

export async function unstable_getStaticPaths() {
    console.log("show once")
    return {
        fallback: false,
        paths: [
        // This renders /blog/hello-world to HTML at build time
        { params: { year: "1901" } },
        { params: { year: "1902" } },
        ]
    }
}

์„ ํƒ ํ•ด์ œ๋ฅผ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋ฅ˜: /[์—ฐ๋„]์˜ ๋ถˆ์•ˆ์ •ํ•œ_getStaticPaths์—์„œ ๋ฐ˜ํ™˜๋œ ์ถ”๊ฐ€ ํ‚ค(๋Œ€์ฒด) ํ˜„์žฌ ํ—ˆ์šฉ๋˜๋Š” ์œ ์ผํ•œ ํ•„๋“œ๋Š” paths

์‹คํ—˜ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉ ์ค‘์ด๋ฉฐ ํ˜„์žฌ ๋™์ž‘์„ ์‹คํ—˜ ์ค‘์ด๋ฉฐ ๋ชจ๋“  ๊ฒƒ์ด ๊ตฌํ˜„๋˜๋Š” ๊ฒƒ์€ ์•„๋‹˜์„ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์•Œ๋ ค๋“œ๋ฆฝ๋‹ˆ๋‹ค.

getStaticProps ์ด ๊ธฐ๋Šฅ์€ ํŽ˜์ด์ง€์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?
์˜ˆ๋ฅผ ๋“ค์–ด ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•œ ์ผ๋ถ€ ์ „์—ญ ๊ตฌ์„ฑ์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ด ์•ฑ/๋ฌธ์„œ์—๋„ ํฅ๋ฏธ๋กœ์šธ๊นŒ์š”?

๋‚˜๋Š” ์ด๊ฒƒ์„ '์„ฑ๊ณต์ ์œผ๋กœ' ๊ตฌํ˜„ํ–ˆ๊ณ  ์ง€๊ธˆ๊นŒ์ง€์˜ ๊ฒฐ๊ณผ์— ๋งŒ์กฑํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํ›„์† ๋นŒ๋“œ๋ฅผ '๋” ๋น ๋ฅด๊ฒŒ' ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด SSG ์ƒ์„ฑ ํŽ˜์ด์ง€๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๋‹ค์‹œ ์ƒ์„ฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? (์•„๋งˆ๋„ ๋‚˜์—๊ฒŒ์„œ ํฌ๋ง์ ์ธ ์ƒ๊ฐ)

@timneutkens SSG ํŽ˜์ด์ง€์šฉ sitemap.xml ์ƒ์„ฑ๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•  ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ง€๊ธˆ์€ ์ •์  ํŽ˜์ด์ง€์— ๋Œ€ํ•ด์„œ๋งŒ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์  ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

@timneutkens SSG ํŽ˜์ด์ง€์šฉ sitemap.xml ์ƒ์„ฑ๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•  ๊ณ„ํš์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์ง€๊ธˆ์€ ์ •์  ํŽ˜์ด์ง€์— ๋Œ€ํ•ด์„œ๋งŒ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์  ๊ฒฝ๋กœ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜์ง€๋„ ์•Š์Šต๋‹ˆ๋‹ค.

์˜ˆ, ์ด๊ฒƒ์€ ํ›Œ๋ฅญํ•œ ์„ ํƒ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ SSR๋กœ ์ง์ ‘ ์ƒ์„ฑ ์ค‘์ž…๋‹ˆ๋‹ค. (๊ทธ๋Ÿฌ๋‚˜ sitemap.xml ํŒŒ์ผ์€ ๋กœ๋“œํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค)

https://github.com/zeit/next.js/issues/9524#issuecomment -585293270

getStaticProps๊ฐ€ ๋„์ฐฉํ•œ ํ›„ ์˜ํ–ฅ์„ ์ฃผ๋Š” ๋‹ค๋ฅธ ์ž‘์—…์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜์Œ์—๋Š” ํŽ˜์ด์ง€์—๋งŒ ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค.

https://github.com/zeit/next.js/issues/9524#issuecomment -586957539

์˜ˆ, ํ•˜์ง€๋งŒ ์ด RFC์˜ ์ผ๋ถ€๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ์ด ๋•… ์ดํ›„์— ํ›„์† ์กฐ์น˜๊ฐ€ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@timneutkens ๋‹ค์Œ์ด ์ •์  ํŽ˜์ด์ง€๋ฅผ ๋นŒ๋“œํ•  ๋•Œ๋งˆ๋‹ค URI๋ฅผ ๋ฐฐ์—ด์— ํ‘ธ์‹œํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— SSG ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ๊ตฌํ˜„์ด ์‰ฝ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ ์ข…๋ฃŒ๋˜๋ฉด ๋ฐฐ์—ด์„ ๊ฐ XML ํƒœ๊ทธ์— ๋งคํ•‘ํ•˜๊ณ  ์ค‘๊ฐ„์— ์กฐ์ธํ•˜๊ณ  ์‚ฝ์ž…ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. <sitemapindex> ํƒœ๊ทธ. getStaticProps ๋Š” excludeFromSitemap ๋ผ๋Š” ๋ฐ˜ํ™˜ ๊ฐœ์ฒด์— ๋‹ค๋ฅธ ํ‚ค๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ธฐ๋ณธ๊ฐ’์€ ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ sitemap.xml ๋˜์ง€๋งŒ ์˜ตํŠธ์•„์›ƒ ์˜ต์…˜์ด ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ ๊ฐœ๋ฐœ์ž๋Š” ์‚ฌ์ดํŠธ๋งต์— ๋“ค์–ด๊ฐˆ ์ •์  ํŽ˜์ด์ง€๋ฅผ ๋ฏธ์„ธํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: page [foo] ์˜ getStaticPaths ํ•จ์ˆ˜๊ฐ€ foo ๋กœ ๊ฒฝ๋กœ๋ฅผ ๋ฐ˜ํ™˜ํ•œ ๊ฒฝ์šฐ) 'abc' ๋ฐ 'xyz' ๊ทธ๋Ÿฌ๋‚˜ 'abc' ํŒŒ์ผ excludeFromSitemap ๋ฅผ true ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค getStaticProps ๋งค๊ฐœ๋ณ€์ˆ˜ ==='xyz' getStaticProps .

๋˜ํ•œ SSR ๋ฐ ์ •์  ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ getServerProps , getStaticPaths ๋ฐ getStaticProps ๊ณผ ๊ฐ™์ด ํŽ˜์ด์ง€ ํŒŒ์ผ์—์„œ ์ƒ์ˆ˜(์˜ˆ: export const excludeFromSitemap = true; )๋ฅผ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. getStaticProps ๋ฅผ) ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค.

SSG ํŽ˜์ด์ง€์—์„œ ๋‚ด๋ณด๋‚ธ excludeFromSitemap ์ƒ์ˆ˜(ํŽ˜์ด์ง€ ๊ธฐ๋ณธ๊ฐ’)๊ฐ€ ์žˆ๊ณ  ํ•ด๋‹น ํ‚ค๊ฐ€ getStaticProps ํ•จ์ˆ˜(๊ฒฝ๋กœ๋ณ„)์—์„œ ๋ฐ˜ํ™˜๋œ ๊ฐœ์ฒด์—๋„ ์žˆ๋Š” ๊ฒฝ์šฐ ๋‚ด๋ณด๋‚ธ ๊ฐ’์ด ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ํŽ˜์ด์ง€์˜ ๋ชจ๋“  ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ๊ฐ’๊ณผ ๊ฒฝ๋กœ๋ณ„ excludeFromSitemap ๊ฐ€ getStaticProps ๊ฐœ์ฒด์— ์žˆ๋Š” ๊ฒฝ์šฐ ํŽ˜์ด์ง€์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์žฌ์ •์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(ํŽ˜์ด์ง€๊ฐ€ export cosnt excludeFromSitemap = true ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ทธ๋Ÿฐ ๋‹ค์Œ getStaticProps ๊ฐ’์ด false ๊ฐœ์ฒด์— excludeFromSitemap ํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํŠน์ • ๊ฒฝ๋กœ๋ฅผ ์ œ์™ธํ•œ ์‚ฌ์ดํŠธ๋งต์˜ ๋ชจ๋“  ๊ฒฝ๋กœ๋ฅผ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค.

๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•˜๋Š” ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค(์ €๋Š” ์ง„๋ฆฌํ‘œ๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  Karnaugh ๋งต์œผ๋กœ ์ตœ์†Œ ๋ถ€์šธ ํ‘œํ˜„์‹์„ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค).

//...somewhere else
const validExcludeFromSitemapTypes = ['boolean','undefined'];

//...for each path
const isSSG = !!getStaticPropsReturnedObj && typeof getStaticPropsReturnedObj === "object";
if(
    validExcludeFromSitemapTypes.indexOf(typeof pageExports.excludeFromSitemap)<0 ||
    (isSSG && validExcludeFromSitemapTypes.indexOf(typeof getStaticPropsReturnedObj.excludeFromSitemap)<0)
) {
    throw new Error("'excludeFromSitemap' can either be ommited (undefined) or be a boolean");
}
const defaultExcludedValue = !!pageExports.excludeFromSitemap;
const hasSpecificExcluded = isSSG && typeof getStaticPropsReturnedObj.excludeFromSitemap !== "undefined";
const specificExcludedValue =  isSSG ? !!getStaticPropsReturnedObj.excludeFromSitemap : false;

if(!specificExcludedValue && (!defaultExcludedValue || hasSpecificExcluded))
    sitemapURIs.push(correctlyEncodedURI);

๋ฐฐ์—ด์„ ์‚ฌ์ดํŠธ๋งต์œผ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์€ ์ด๋ ‡๊ฒŒ ํ•˜๋Š” ๊ฒƒ๋งŒํผ ์‰ฝ์Šต๋‹ˆ๋‹ค(๋ฐฐ์—ด์˜ URI๊ฐ€ ์ด๋ฏธ !excludeFromSitemap ์ธ์ฝ”๋”ฉ ๋ฐ ํ•„ํ„ฐ๋ง๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •).

function createSitemap(sitemapURIs: string[]): string {
    return `<sitemapindex>${sitemapURIs.map(u=>`<sitemap><loc>u/loc></sitemap>`).join('')}</sitemapindex>`;
}

์ด ๊ธฐ๋Šฅ์€ ์‚ฌ์šฉ์ž์—๊ฒŒ 100 SEO ์ ์ˆ˜๋ฅผ ์ œ๊ณตํ•˜๊ณ  sitemap.xml ๊ฐ–๋Š” ๊ฒƒ์ด ํฐ ๋„์›€์ด ๋  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด ๊ธฐ๋Šฅ์ด Next.JS์— ์ž˜ ๋“ค์–ด๋งž์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค! ( robots.txt ๋Š” ์‚ฌ์ดํŠธ๋งต ๋ฐฐ์—ด์— ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํ—ˆ์šฉ๋˜์ง€ ์•Š๋Š” ํŽ˜์ด์ง€์˜ ๋‹ค๋ฅธ ๋ฐฐ์—ด์— ํ•ด๋‹น ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ์กฐ๊ฑด์— else ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ž ์žฌ์ ์œผ๋กœ ์ƒ์„ฑ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋ฆด๋ฆฌ์Šค ๋ฒ„์ „์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ unstable_getStaticPaths ํ•จ๊ป˜ unstable_getStaticProps ์ƒํ™œ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ, ๋‹น์‹ ์€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค API๋ฅผ ํ˜ธ์ถœ /api/ .
์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ ํ•ด๋‹น ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์ •์  props๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
๊ฒฝ๋กœ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๊ฑฐ๋‚˜(๊ธฐ๋ณธ์ ์œผ๋กœ ์บ์‹œ๊ฐ€ ์žˆ๋Š” ์ด SSR์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ์—ฌ์ „ํžˆ โ€‹โ€‹์ข‹์Šต๋‹ˆ๋‹ค!) SSG ๋Œ€์‹  SSR์— ์˜์กดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์— ์ข‹์€ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์ด ์•„๋‹๊นŒ์š”? ์—ฌ๊ธฐ์„œ ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์ด ๋ฌด์—‡์ธ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. SSR ๋ฐ /api ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ http ์š”์ฒญ์„ ๋ฐ”๋กœ ๊ฐ€๊ธฐ๋กœ ์ œ์•ˆํ•˜๋Š” ๋‹ค๋ฅธ ๊ณณ์—์„œ ์ œ์•ˆ์„ ์ฝ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์—ฌ๊ธฐ์—์„œ๋„ ์œ ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ชจ๋“  ๊ฒƒ์€ ๋ฌผ๋ก  ๋นŒ๋“œ ํ™˜๊ฒฝ์—์„œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๋ฉฐ, ์ด๋Š” ๋‹ค๋ฅธ ์„œ๋น„์Šค/db ํ˜ธ์ถœ ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์„ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๊ตฌํ˜„๋  ๋•Œ ๋ช…ํ™•ํ•ด์•ผ ํ•˜์ง€๋งŒ ์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๋ฉ‹์ง„ ์ถ”๊ฐ€ ์‚ฌํ•ญ์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@reckter ์˜ˆ, ๋ฐฉ๊ธˆ ๋น„์Šทํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ๋™์•ˆ ๊ฐœ๋ณ„ ํŽ˜์ด์ง€ ์š”์ฒญ๋งˆ๋‹ค db์— ์—ฐ๊ฒฐํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ถ„์ด ๋งŽ์ด ์ด์ƒํ–ˆ๋‹ค...

๊ทธ๊ฒƒ์ด ์ตœ์ข… ์‚ฌ์šฉ ์‚ฌ๋ก€๊ฐ€ ์•„๋‹ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

next.config์—์„œ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ข…์˜ ์ดˆ๊ธฐํ™” ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@reckter HTTP ์š”์ฒญ์„ SSG/SSR์—์„œ API ๊ฒฝ๋กœ๋กœ ๋ฐ”๋กœ ๊ฐ€๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์€ ์ •๋ง ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค! ์ด๋Ÿฌํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค ์ค‘ ํ•˜๋‚˜์—์„œ ๋‚˜ ์ž์‹ ์—๊ฒŒ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ํ•˜๋Š” ๊ฒƒ์ด ์ด์ƒํ•˜๊ฒŒ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค.

์–ด์จŒ๋“ , SSG ๋™์•ˆ API ๊ฒฝ๋กœ์— ์•ก์„ธ์Šคํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์€ ์ •์  ํŽ˜์ด์ง€๋ฅผ ์ปดํŒŒ์ผํ•˜๊ธฐ ์ „์— ๋กœ์ปฌ ์„œ๋ฒ„์—์„œ /api ๊ฒฝ๋กœ๋งŒ ์‹คํ–‰ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค! ๋”ฐ๋ผ์„œ ๋นŒ๋“œ ๋‹จ๊ณ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  1. /api ๊ฒฝ๋กœ๋งŒ ์ œ๊ณตํ•˜๋Š” ์„œ๋ฒ„("api ์ปดํŒŒ์ผ ์„œ๋ฒ„" ๋˜๋Š” ์ด์™€ ์œ ์‚ฌํ•œ ๊ฒƒ)๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  2. unstable_getStaticPaths
  3. unstable_getStaticProps
  4. ์ •์  ํŽ˜์ด์ง€ ์ปดํŒŒ์ผ

@reckter ๊ธฐ๋ณธ์ ์œผ๋กœ API ๋ผ์šฐํŠธ๋ฅผ ํ˜ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ตฌํ˜„ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด http ์›์ธ์„ ๋„˜์–ด์„œ๋Š” ๋งŽ์€ ์˜ค๋ฒ„ํ—ค๋“œ๋„ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ํ˜„์žฌ ๋‹ค์Œ๊ณผ ๊ฐ™์€ API ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ:

import myDb from 'mydatabaseprovider'
const db = myDb()

export default async (req, res) => {
  cont myData = await db.query('posts')
  res.json(myData)
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import myDb from 'mydatabaseprovider'
const db = myDb()

export async function getData() {
  const myData = await db.query('posts')
  return myData
}

export default (req, res) => {
  const myData = await getData()
  res.json(myData)
}

๊ทธ๋Ÿฐ ๋‹ค์Œ ํŽ˜์ด์ง€์—์„œ:

import {getData} from './api/myfunction'

export async function getStaticProps() {
  const myData = await getData()
  return {
    props: {
     myData
   }
  }
}

GraphQL API์— ๋Œ€ํ•ด ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๊นŒ๋‹ค๋กœ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋Œ€๋ถ€๋ถ„์˜ REST์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค.

API ํ˜ธ์ถœ != DB์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ(์ผ๋ฐ˜์ ์œผ๋กœ)
ํ•„๋“œ ์ด๋ฆ„ ๋ฐ”๊พธ๊ธฐ, ๋ฐ์ดํ„ฐ ํ˜•์‹ ๋ณ€๊ฒฝ ๋“ฑ๊ณผ ๊ฐ™์€ API ๊ณ„์ธต์—๋Š” ๊ฑฐ์˜ ํ•ญ์ƒ ๋ช‡ ๊ฐ€์ง€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์žˆ์Šต๋‹ˆ๋‹ค.

pages/api ํ˜ธ์ถœ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์„ ์ด์œ ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•˜์ง€๋งŒ ์‹ค์ œ API์˜ ์šฐํšŒ๋Š” ์‰ฝ๊ฑฐ๋‚˜ ์ €๋ ดํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์—ฌ๋ถ„์˜ ๋ช‡ ๋ฐ€๋ฆฌ์ดˆ๋Š” ์ถ”๊ฐ€ ์ฝ”๋“œ/๋ณต์žก์„ฑ IMO์— ๋Œ€ํ•œ ๋น„์šฉ์„ ๋Šฅ๊ฐ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๋ชจ๋“  API์— ๋Œ€ํ•œ ์š”์ฒญ์ด ํ—ˆ์šฉ๋œ๋‹ค๋Š” ๊ฒƒ์ด ์ด์ƒํ•˜๊ฒŒ ๋Š๊ปด์ง‘๋‹ˆ๋‹ค. ๋‚˜๋งŒ์˜ ๐Ÿคทโ€โ™‚

unstable_getStaticPaths ํ•˜๋ฉด ํŽ˜์ด์ง€๊ฐ€ ๋‹ค์‹œ ๋กœ๋“œ๋˜์–ด ์˜ˆ๋ฅผ ๋“ค์–ด redux์—์„œ ํ˜„์žฌ ์ƒํƒœ๊ฐ€ ์†์‹ค๋ฉ๋‹ˆ๋‹ค. ์•ž์œผ๋กœ ์ด ํ–‰๋™์ด ๋ฐ”๋€”๊นŒ์š”?

ํŽธ์ง‘: ๋งํฌ ๋˜๋Š” ๋ผ์šฐํ„ฐ์—์„œ as ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋™์ž‘์„ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<Link
  href='/item/[key]'
  as={`/item/${itemName}`}
>
router.push(
  '/item/[key]',
  `/item/${itemName}`
);

@meesvandongen ํ•ญ์ƒ <Link> ์ด ์œ ํšจํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ <a> ๋กœ ์ž‘๋™ํ•˜๋Š” ๋ฐฑ์—”๋“œ ๋ถ€๋ถ„์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค. [key] ์™€ ๊ฐ™์€ ๋™์  ์กฐ๊ฐ์€ ํ•ด๋‹น ๊ฐ’๊ณผ ์Œ์„ ์ด๋ฃจ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@reaktivo pages/[lang]/blog/[id].js -> getStaticPaths ์—์„œ ์ •์ ์œผ๋กœ ๋ Œ๋”๋งํ•  ๋ชจ๋“  URL์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

https://github.com/zeit/next.js/issues/9524#issuecomment -562625858
์ด ๊ฒฝ์šฐ index.js๋ฅผ ์ œ์™ธํ•œ ๋ชจ๋“  ํŽ˜์ด์ง€์— getStaticPaths ๋ฐ getStaticProps ํ•จ์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
์ผ๋ถ€ mdx ํŽ˜์ด์ง€๊ฐ€ ์žˆ์œผ๋ฉด ํ”„๋กœ์ ํŠธ๋ฅผ ์œ ์ง€ ๊ด€๋ฆฌํ•˜๊ธฐ๊ฐ€ ๋” ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ •์  getStaticPaths getStaticProps ๋ฉ”์†Œ๋“œ๋กœ์˜ ๋ณ€๊ฒฝ ๋˜๋Š” ํ˜ธํ™˜์„ ๊ณ ๋ คํ•˜์‹ญ์‹œ์˜ค. https://github.com/zeit/next.js/issues/9524#issuecomment -558617056
๊ทธ๋ ‡๋‹ค๋ฉด ํŽ˜์ด์ง€๋Š” ๊ณ ์ฐจ ํ•จ์ˆ˜ ๋˜๋Š” ๊ณ ์ฐจ ๊ตฌ์„ฑ ์š”์†Œ(HOC)์— ์˜ํ•ด ๋ž˜ํ•‘๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋Ÿฐ ์‹์œผ๋กœ ์ฝ”๋“œ๋Š” ๋” ์œ ์ง€ ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฝ๊ณ  typesscript์— ๋” ํŽธ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.


๋‚˜๋ฌด ํ”๋“ค๊ธฐ ๋Œ€ ๋™์ . ์ด ์–ผ๋งˆ๋‚˜ ๊ณจ์น˜ ์•„ํ”ˆ ํŠธ๋ ˆ์ด๋“œ์˜คํ”„์ธ๊ฐ€.๐Ÿ˜‚

9.2.3-canary.13 ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด getStaticPath์—์„œ fallback: false ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

  return {
    fallback: false,
    paths: slugs.map(slug => ({params: {slug: slug}}))
  }

๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์Œ ์˜ค๋ฅ˜์™€ ํ•จ๊ป˜ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

Error: Extra keys returned from unstable_getStaticPaths in /blog/[slug] (fallback) Expected: { paths: [] }

9.2.3-canary.13 ์‚ฌ์šฉํ•˜์—ฌ ๋‹ค์Œ๊ณผ ๊ฐ™์ด getStaticPath์—์„œ fallback: false ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

  return {
    fallback: false,
    paths: slugs.map(slug => ({params: {slug: slug}}))
  }

๊ทธ๋Ÿฌ๋‚˜ ๋‹ค์Œ ์˜ค๋ฅ˜์™€ ํ•จ๊ป˜ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

Error: Extra keys returned from unstable_getStaticPaths in /blog/[slug] (fallback) Expected: { paths: [] }

๋งต์ด ๋” ๋†’์€ ๋ ˆ๋ฒจ์ด ํ•„์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฏ€๋กœ ๋งต์€ ํ˜„์žฌ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐœ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ ๊ณ ์œ ํ•œ ์Šฌ๋Ÿฌ๊ทธ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๊ฒฝ๋กœ์— ๋งคํ•‘ํ•˜๋Š” ๋Œ€์‹ .

์•„์ง nextjs์—์„œ ๋‚ด ๋ฒ„์ „์„ ์—…๋ฐ์ดํŠธํ•˜์ง€ ์•Š์•˜์ง€๋งŒ ๋น„์Šทํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

return data.map(item => {
    return {
      params: {
        slug: item.slug,
      },
    }
  })

@jorngeorg ๊ณต๊ฐœ PR์ž…๋‹ˆ๋‹ค: https://github.com/zeit/next.js/pull/10701

ํ™˜์ƒ์ ์ธ ๊ธฐ์—ฌ! ์ •์  ๋ Œ๋”๋ง ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹ค์ œ๋กœ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค.

๋™์  ๊ฒฝ๋กœ์—์„œ getStaticProps ๋Œ€ํ•œ ํ˜ธ์ถœ ์—†์ด "๋Œ€์ฒด"๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค๋Š” ๋ฌธ์„œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ฆ‰, props๊ฐ€ ๋น„์–ด ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ฝ”๋”ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋˜๋Š” ๋Œ€์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ปจํ…์ŠคํŠธ ์—†์ด getStaticProps ๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ๋™์ž‘์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ next export ํ˜„์žฌ ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹๊ณผ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: getInitialProps ๋ฅผ ์ปจํ…์ŠคํŠธ ์—†์ด ์‹คํ–‰ํ•˜์—ฌ /p/[id].js ๋ฅผ /p/[id].html ๋กœ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค).

  • getStaticProps - next build ์‹œ๊ฐ„์— SSG(์ •์  ์ƒ์„ฑ)๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
  • getServerProps - ์˜จ๋””๋งจ๋“œ๋กœ ๋ Œ๋”๋งํ•˜๋Š” SSR(์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง)์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

10722

getServerProps์˜ ์ด๋ฆ„์„ getServerSideProps๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

๋™์  ๊ฒฝ๋กœ์—์„œ getStaticProps ๋Œ€ํ•œ ํ˜ธ์ถœ ์—†์ด "๋Œ€์ฒด"๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค๋Š” ๋ฌธ์„œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ์ฆ‰, props๊ฐ€ ๋น„์–ด ์žˆ๋Š” ๊ฒฝ์šฐ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์ฝ”๋”ฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์€์ ! ๋‚˜๋Š” ๋˜ํ•œ ๊ทธ๊ฒƒ์„ ๋†“์ณค๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ถ€ ๋นŒ๋“œ/๋ฐฐํฌ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•˜๋„๋ก RFC๋ฅผ ์—…๋ฐ์ดํŠธํ–ˆ์Šต๋‹ˆ๋‹ค.

@timneutkens

  • ๋™์ผํ•œ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ ํ›„์† ์š”์ฒญ์€ ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด Next.js๊ฐ€ ์ƒ์„ฑ๋œ ํŽ˜์ด์ง€๋ฅผ ์บ์‹œํ•  ๊ฒƒ์ž„์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๊นŒ? ์ธ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ์ธ๊ฐ€์š”? ์ด ์บ์‹œ๊ฐ€ ์ œํ•œ์— ์˜ํ•ด ์ œํ•œ๋˜๊ฑฐ๋‚˜ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

next start ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ˜„์žฌ ์บ์‹ฑ ์˜ˆ์ œ์™€ ์œ ์‚ฌํ•œ lru-cache๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ๊ธฐ๋ณธ ์ œํ•œ์€ 50MB์ด๋ฉฐ ๋‚˜์ค‘์— ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://github.com/zeit/next.js/ ๋ธ”๋กญ/์นด๋‚˜๋ฆฌ์•„/ํŒจํ‚ค์ง€/next/next-server/server/spr-cache.ts#L90

ZEIT์—์„œ ํ˜ธ์ŠคํŠธํ•  ๋•Œ ์ด์ œ ์ƒ์„ฑ ๋ฐ ์บ์‹ฑ์ด CDN/ํ”„๋ก์‹œ์—์„œ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ์•ฝ๊ฐ„ ๋‹ค๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋‚˜ lru ์ œํ•œ์„ ์ดˆ๊ณผํ•˜๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ๊ฑฑ์ •ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๐Ÿ‘ ์ข‹์•„, ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋ณด์ธ๋‹ค. ๊ทธ๊ฒƒ์€ ๋‚ด๊ฐ€ ํ•ฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ ๋™์ž‘์œผ๋กœ ์—ผ๋‘์— ๋‘์—ˆ๋˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • getStaticProps - next build ์‹œ๊ฐ„์— SSG(์ •์  ์ƒ์„ฑ)๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
  • getServerProps - ์˜จ๋””๋งจ๋“œ๋กœ ๋ Œ๋”๋งํ•˜๋Š” SSR(์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง)์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

10722

getServerProps์˜ ์ด๋ฆ„์„ getServerSideProps๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์™œ ์ด๋ฆ„์„ ๋ฐ”๊พธ๋‚˜์š”? IMHO getServerProps๋Š” ์ž…๋ ฅํ•˜๊ธฐ์— ์ถฉ๋ถ„ํžˆ ์ •ํ™•ํ•˜๊ณ  ์งง์•„์„œ Side๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์—๊ฒŒ ์ค‘๋ณต๋˜๋Š” ๋Š๋‚Œ์ž…๋‹ˆ๋‹ค.

getStaticPaths ๋ฉ”์„œ๋“œ์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ๋™์  ํŽ˜์ด์ง€๋Š” ๋” ์ด์ƒ ์ •์  ํŽ˜์ด์ง€๋กœ ์ƒ์„ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋žŒ๋‹ค ํ•จ์ˆ˜๋กœ ๋‚ด๋ณด๋‚ด์ง‘๋‹ˆ๋‹ค.

์ด์ œ ๊ธฐ๋ณธ ๋™์ž‘์ด ํŽ˜์ด์ง€๊ฐ€ ๋จผ์ € ๋žŒ๋‹ค๋กœ ๋ Œ๋”๋ง๋˜๊ณ  ํŠน์ • ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•œ ํ›„์—๋งŒ ํŽ˜์ด์ง€๊ฐ€ ์ •์  ํŽ˜์ด์ง€๋กœ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์ด ๋งž์Šต๋‹ˆ๊นŒ? (๋Œ€์ฒด์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ)

@erhankaradeniz ํŽ˜์ด์ง€๊ฐ€ Lambdas ๊ฐ€ ๋˜๋Š” getStaticPaths ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์‚ฌ์šฉ์ƒ์˜ ์˜ค๋ฅ˜์ผ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ๋ฅผ ๋ณด์—ฌ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

@Timer ์ง€๊ธˆ์€ ๊ฒฝ๋กœ์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋ฅผ ์•Œ์•„๋‚ผ ๋•Œ๊นŒ์ง€ ์—ฌ์ „ํžˆ params๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” [email protected]์œผ๋กœ ๋˜๋Œ์•„๊ฐ”์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ํ˜„์žฌ ๋‚ด ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

return cityData.map(city => {
    return {
      params: {
        country: city.countrySlug,
        city: city.slug,
      },
    }
  })

๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

return cityData.map(city => {
    return {
      params: {
        country: city.countrySlug,
        city: city.slug,
      },
    }
  })

๊ฒฝ๋กœ๊ฐ€ ์žˆ๋Š” ์ƒˆ ์นด๋‚˜๋ฆฌ์•„ ๋ฆด๋ฆฌ์Šค๋กœ ๋ณ€ํ™˜ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. console.logs๊ฐ€ getStaticPath ๋‚ด์—์„œ ์‹คํ–‰๋˜์ง€๋„ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋ญ”๊ฐ€ ์ž˜๋ชปํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ค‘์ฒฉ ๊ฒฝ๋กœ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋ฐ SSG์— ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

// pages/[lang]/[...slugs].js

export async function getStaticPaths() {
  let knex = await import("knex/client").then(m => m.default)
  let pages = await knex("page").select(["lang", "url"])
  return {
    fallback: true,
    paths: pages.map(page => {
      return {
        params: {
          lang: page.lang,
          slugs: page.url == "/" ? [] : page.url.slice(1).split("/"),
        }
      }
    }),
  }
}

~์œผ๋กœ ์ด๋Œ๋‹ค

Error occurred prerendering page "/en/". Read more: https://err.sh/next.js/prerender-error:
Error: The provided export path '/en/' doesn't match the '/[lang]/[...slugs]' page.

ํ™ˆ ํŽ˜์ด์ง€์˜ ๊ฒฝ์šฐ. ์–ด๋–ค ์ด์œ ๋กœ NextJS๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

{lang: "en", slugs: []}

์—๊ฒŒ

/[lang]/[...slugs]

{lang: "en", slugs: ["/"]} ํ•˜๋ฉด ๋นŒ๋“œ๋˜์ง€๋งŒ URL์ด ์ž˜๋ชป๋ฉ๋‹ˆ๋‹ค.

โ”œ โ— /[lang]/[...slugs]      875 B        204 kB
โ”œ   โ”œ /en/credits
โ”œ   โ”œ /en/%2F

๊ธฐ๋ก์„ ์œ„ํ•ด getServerSideProps ๋Š” ์œ ์‚ฌํ•œ ์„ค์ •์œผ๋กœ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์‹คํ—˜์ ์ด๋ผ๋Š” ๊ฑด ์•Œ์ง€๋งŒ ์ด ์Šค๋ ˆ๋“œ๋Š” ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋งž๋‚˜์š”?

pages/[lang]/[...slugs].js ์ผ์น˜ /en/abcdef ํ•˜์ง€ /en , ํ˜„์žฌ ๋งŒ๋“ค ํ•„์š”๊ฐ€ ๊ทธ๊ฒƒ์„ ์œ„ํ•ด pages/[lang]/index.js .

์ด์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ ์š”์ฒญ์ด ์žˆ์Šต๋‹ˆ๋‹ค: https://github.com/zeit/next.js/issues/10488

์šฐ์„ , ์ด๊ฒƒ์€ ๊ต‰์žฅํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” Next.js์— ์ด์™€ ๊ฐ™์€ ๊ฒƒ์„ ๊ฐ–๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์นจ๋‚ด Gatsby.js์—์„œ ๋ฒ—์–ด๋‚˜ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์•ฑ(์ •์  + ๋™์ )์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿš€ ๋‚˜๋Š” ์นด๋‚˜๋ฆฌ์•„๋ฅผ ์‹œ๋„ํ–ˆ๊ณ  ๋ฐ˜ ๊ตฌ์šด ๋ณต์žกํ•œ ์•ฑ ๋ฒ„์ „์€ ์ž˜ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ์—ฌ๊ธฐ์— ์žˆ๋Š” ๋ชจ๋“  ์ฃผ์„์„ ์ฝ์ง€ ์•Š์•˜์ง€๋งŒ ๋‚˜๋ฌด ํ”๋“ค๊ธฐ๊ฐ€ ์•„์ง ๊ตฌํ˜„๋˜์—ˆ๋Š”์ง€ ํ™•์‹ ํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ๊ณ ๋ฐฑํ•ฉ๋‹ˆ๋‹ค.

๐Ÿค” getStaticPaths ๋Š” SSG ๋™์ž‘์— ๋Œ€ํ•œ ์ •์  ๊ฒฝ๋กœ๋ฅผ ์ •์˜ํ•˜๋Š” setStaticPaths ์™€ ํ›จ์”ฌ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ์ ์ด ๋‚˜๋ฅผ ์กฐ๊ธˆ ํ˜ผ๋ž€์Šค๋Ÿฝ๊ฒŒ ํ–ˆ๋‹ค.

๐Ÿง ๋นŒ๋“œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋งŒ๋“ค์–ด ๋นŒ๋“œ ์‹œ๊ฐ„์„ ๋‹จ์ถ•ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์„ค์ •์„ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค ๊ฒƒ์ด๋ผ๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ๊ทธ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค:

blog ๋˜๋Š” pages ๋˜๋Š” ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์›ํ•˜๋Š” 2020-content ์„ค์ •ํ•˜๋Š” setBuildCategory ์™€ ๊ฐ™์€ ๊ฒƒ์ด ์žˆ์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ๊ทธ๋Ÿฐ ๋‹ค์Œ SSG ๋นŒ๋”๋Š” ๋ณ€๊ฒฝ๋œ ํŽ˜์ด์ง€์˜ ๋ฒ”์ฃผ๋ฅผ ์ฐพ๊ณ  ์บ์‹œ + ์ƒˆ ๋ Œ๋” ์กฐํ•ฉ์—์„œ๋งŒ ํ•ด๋‹น ๋ฒ”์ฃผ๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ์ด์™€ ๊ฐ™์€ ๊ฒƒ์€ SSG๋ฅผ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค๊ณ  ๋งŽ์ด ๋ณ€๊ฒฝ๋˜์ง€๋Š” ์•Š์ง€๋งŒ ์—ฌ์ „ํžˆ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ณด๊ด€ํ•  ์ˆ˜ ์—†๋Š” ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ๋ง‰๋Œ€ํ•œ ๋นŒ๋“œ ์‹œ๊ฐ„์„ ํ”ผํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์ด ์˜๋ฏธ๊ฐ€ ์žˆ๋‹ค๋ฉด; ์ „ํ™”๋ฅผ ๊ฑธ๊ณ  ์ด์— ๋Œ€ํ•ด ์ฑ„ํŒ…ํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ •์˜ ์„œ๋ฒ„ ๊ตฌํ˜„์œผ๋กœ getServerSideProps ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

if (pathname === '/a') {
  app.render(req, res, '/b', query)
}

์œ„์˜ ์˜ˆ์—์„œ /a ๋ฐฉ๋ฌธํ•˜๋ฉด pages/b.js ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ /a ๋Œ€ํ•œ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ฆฌ๋””๋ ‰์…˜์€ ์ด ๊ฒฝ์šฐ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” a.json ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ JSON ํŒŒ์ผ์„ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด /_next/data/{BUILD_ID}/{PAGE}.json ์— ๋Œ€ํ•œ ์š”์ฒญ์— ๋Œ€ํ•ด ์œ ์‚ฌํ•œ ์กฐ๊ฑด์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

getStaticPaths์—์„œ fallback: true ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด req ๊ฐ์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ์–ป์Šต๋‹ˆ๊นŒ? ํ˜„์žฌ๋กœ์„œ๋Š” ํ•  ์ˆ˜ ์—†๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ผ๋ถ€ ์ฟ ํ‚ค๋ฅผ ๊ฐ€์ ธ์™€ ๊ฒฝ๋กœ๋ฅผ ์ธ์ฆํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@tylermcrobert ์š”์ฒญ์ด ์ „ํ˜€ ์—†์„ ๋•Œ ์ฟ ํ‚ค๋ฅผ ์žก๋Š” ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์ƒ์ƒํ•ฉ๋‹ˆ๊นŒ?!
์‹ค์ œ ๋ฐฉ๋ฌธ์ž ์š”์ฒญ์— ๋”ฐ๋ผ ๋ฐฑ์—”๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ๋กœ๋Š” "์ •์ " ๋ฐ "๋™์ "์˜ ์ •์˜์— ๋”ฐ๋ผ ์ •์ ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ •์  ๋ฐ ์ธ์ฆ์„ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์€ ๋งํ•  ๊ฒƒ๋„ ์—†๊ณ ... ์ธ์ฆ ๋ถ€๋ถ„์€ ํŽ˜์ด์ง€ ๋Œ€์‹  API ๋ฐ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์— ์†ํ•  ๋ฟ์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ •์˜ ์„œ๋ฒ„ ๊ตฌํ˜„์œผ๋กœ getServerSideProps ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

if (pathname === '/a') {
  app.render(req, res, '/b', query)
}

์œ„์˜ ์˜ˆ์—์„œ /a ๋ฐฉ๋ฌธํ•˜๋ฉด pages/b.js ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ /a ๋Œ€ํ•œ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ฆฌ๋””๋ ‰์…˜์€ ์ด ๊ฒฝ์šฐ์— ์กด์žฌํ•˜์ง€ ์•Š๋Š” a.json ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ JSON ํŒŒ์ผ์„ ๋ Œ๋”๋งํ•˜๊ธฐ ์œ„ํ•ด /_next/data/{BUILD_ID}/{PAGE}.json ์— ๋Œ€ํ•œ ์š”์ฒญ์— ๋Œ€ํ•ด ์œ ์‚ฌํ•œ ์กฐ๊ฑด์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

Next.js๋Š” ๋™์  ๊ฒฝ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ์„œ๋ฒ„์—์„œ ๋‹ค์‹œ ๋งคํ•‘ํ•  ํ•„์š”๊ฐ€ ๋” ์ด์ƒ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. https://nextjs.org/docs/routing/dynamic-routes

์ด๋ฏธ ์„ค๋ช…ํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์€ <Link> ์ž‘๋™ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ(์ „์ฒด ํŽ˜์ด์ง€ ์ „ํ™˜์ด ๋ฐœ์ƒํ•จ) getServerSideProps๊ฐ€ ์ด๋ฏธ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@tylermcrobert ์š”์ฒญ์ด ์ „ํ˜€ ์—†์„ ๋•Œ ์ฟ ํ‚ค๋ฅผ ์žก๋Š” ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์ƒ์ƒํ•ฉ๋‹ˆ๊นŒ?!
์‹ค์ œ ๋ฐฉ๋ฌธ์ž ์š”์ฒญ์— ๋”ฐ๋ผ ๋ฐฑ์—”๋“œ๊ฐ€ ์žˆ๋Š” ๊ฒฝ๋กœ๋Š” "์ •์ " ๋ฐ "๋™์ "์˜ ์ •์˜์— ๋”ฐ๋ผ ์ •์ ์œผ๋กœ ๋งŒ๋“ค ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ •์  ๋ฐ ์ธ์ฆ์„ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์€ ๋งํ•  ๊ฒƒ๋„ ์—†๊ณ ... ์ธ์ฆ ๋ถ€๋ถ„์€ ํŽ˜์ด์ง€ ๋Œ€์‹  API ๋ฐ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์— ์†ํ•  ๋ฟ์ž…๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ ๋Œ€์ฒด ์˜ต์…˜์„ ์˜คํ•ดํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ๋งํ•˜๋Š” ๊ฒƒ์€ ๋นŒ๋“œ ํƒ€์ž„ ์ปจํ…์ŠคํŠธ์—์„œ ์™„์ „ํžˆ ์˜๋ฏธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฏธ๋ฆฌ ์ •์˜๋œ ๊ฒฝ๋กœ๊ฐ€ ์—†์„ ๋•Œ๋ฅผ ์œ„ํ•œ fallback: true ์•„๋‹Œ๊ฐ€์š”? ์ด ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €์—์„œ ํด๋ฐฑ(fallback)์— ๋„๋‹ฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๊นŒ?

@tylermcrobert yes fallback: true ์ผ€์ด์Šค์— ์š”์ฒญ์ด ์žˆ์ง€๋งŒ API๋Š” "์ตœ์†Œ ๊ณตํ†ต ๋ถ„๋ชจ"๋กœ ํ†ตํ•ฉ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ๊ฒƒ์ด ํ•˜๋‚˜์˜ ์ „์ œ ์„ธํŠธ๋กœ ๊ตฌ์ถ•๋œ ๋‹ค์Œ ์™„์ „ํžˆ ๋‹ค๋ฅธ ์ „์ œ ์„ธํŠธ๋กœ ์ ์ง„์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜๋Š” ์ž‘์—… ์‹œ์Šคํ…œ์„ ์ƒ์ƒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ์žฌ์•™์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ฆ๋ถ„ ๋นŒ๋“œ๊ฐ€ ๋นŒ๋“œ ๊ฐ„์— ์—ฌ์ „ํžˆ ์บ์‹œ๋œ๋‹ค๋Š” ์ ์„ ๋†“์น˜๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฌธ์ž์˜ ์—ญํ• ์€ ๋ชจ๋“  ํ›„์† ์‚ฌ์šฉ์ž์˜ ๋นŒ๋“œ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค! ๋‚˜์œ ์ƒ๊ฐ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค.

@ivan-kleshnin ์ดํ•ดํ•˜๊ณ  ํ™•์‹คํžˆ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ฌป๋Š” ์ด์œ ๋Š” ๋‚ด ํŠน์ • ์‚ฌ์šฉ ์‚ฌ๋ก€ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ธฐ๋Šฅ์„ ํ—ˆ์šฉํ•˜๋Š” ํ—ค๋“œ๋ฆฌ์Šค CMS๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ€ ํ•„์š”ํ•œ ํŽ˜์ด์ง€๋Š” ๋นŒ๋“œ ์‹œ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ค‘์ธ ํ•ญ๋ชฉ์ด ์ด ์‹œ์ ์—์„œ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค). ๋‚˜๋Š” ์ด๊ฒƒ์ด ๋Œ€์ฒด ์˜ต์…˜์ด ๋“ค์–ด์˜ค๋Š” ๊ฒฝ์šฐ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•ด๋‹น ๋ฏธ๋ฆฌ๋ณด๊ธฐ์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด ์ฟ ํ‚ค๋ฅผ ํ†ตํ•ด ์ œ๊ณต๋˜๋Š” api ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ฐธ์กฐ์— ์•ก์„ธ์Šคํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

useStaticProps ์™„์ „ํžˆ ํ๊ธฐํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๊นŒ? ๋‚ด ๋ฌธ์„œ๋ฅผ ๋ฏธ๋ฆฌ ๋ณผ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ •์  ๋นŒ๋“œ์˜ ์ด์ ์„ ์žƒ๊ณ  ์‹ถ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Gatsby์™€ ๊ฐ™์€ ๊ฒƒ์— ๋น„ํ•ด ์ด RFC์˜ ๋งค๋ ฅ์€ ํ—ค๋“œ๋ฆฌ์Šค CMS๋กœ ์ž‘์—…ํ•˜๋Š” ๋ฐ ๊ณ ํ†ต์„ ๋œ ์ฃผ๋Š” ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ์œผ๋กœ "ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์ œ์–ด"๋ฅผ ์ œ๊ณตํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ธฐ๋Šฅ์„ ํ—ˆ์šฉํ•˜๋Š” ํ—ค๋“œ๋ฆฌ์Šค CMS๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ€ ํ•„์š”ํ•œ ํŽ˜์ด์ง€๋Š” ๋นŒ๋“œ ์‹œ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ค‘์ธ ํ•ญ๋ชฉ์ด ์ด ์‹œ์ ์—์„œ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค). ๋‚˜๋Š” ์ด๊ฒƒ์ด ๋Œ€์ฒด ์˜ต์…˜์ด ๋“ค์–ด์˜ค๋Š” ๊ฒฝ์šฐ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋” ๋นจ๋ฆฌ ์ง€์ผœ๋ด ์ฃผ์„ธ์š” ๐Ÿ•ต

๋”ฐ๋ผ์„œ ์ด๊ฒƒ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ดํ•ดํ•˜๋ฉด ์˜ˆ๋ฅผ ๋“ค์–ด ์‚ฌ์šฉ์ž๊ฐ€ ๋“ฑ๋กํ•  ๋•Œ(์ƒˆ ํŽ˜์ด์ง€/์‚ฌ์šฉ์ž์ด๋ฏ€๋กœ ์ •์  ํŽ˜์ด์ง€๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์Œ) fallback true๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ํ”„๋กœํ•„์ด ๋ฐฉ๋ฌธ์„ ๋ฐ›์œผ๋ฉด ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋ฉ๋‹ˆ๊นŒ?

์—๋ฅดํ•œ ์นด๋ผ๋ฐ๋‹ˆ์ฆˆ
http://www.erhankaradeniz.com

2020๋…„ 3์›” 4์ผ 20์‹œ 25๋ถ„์— Tim Neutkens [email protected]์ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ผ์Šต๋‹ˆ๋‹ค.


๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ธฐ๋Šฅ์„ ํ—ˆ์šฉํ•˜๋Š” ํ—ค๋“œ๋ฆฌ์Šค CMS๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋ฏธ๋ฆฌ๋ณด๊ธฐ๊ฐ€ ํ•„์š”ํ•œ ํŽ˜์ด์ง€๋Š” ๋นŒ๋“œ ์‹œ ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ค‘์ธ ํ•ญ๋ชฉ์ด ์ด ์‹œ์ ์—์„œ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค). ๋‚˜๋Š” ์ด๊ฒƒ์ด ๋Œ€์ฒด ์˜ต์…˜์ด ๋“ค์–ด์˜ค๋Š” ๊ฒฝ์šฐ๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.

๋” ๋นจ๋ฆฌ ์ง€์ผœ๋ด ์ฃผ์„ธ์š” ๐Ÿ•ต

โ€”
๋‹น์‹ ์ด ์–ธ๊ธ‰๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ฑฐ๋‚˜ GitHub์—์„œ ๋ณด๊ฑฐ๋‚˜ ๊ตฌ๋…์„ ์ทจ์†Œํ•˜์„ธ์š”.

์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋Š” ํ•ด๋‹น ํด๋ผ์ด์–ธํŠธ ์ธก์„ ๊ฐ€์ ธ์˜ค๋ ค๋Š” ๋‚˜์œ ์˜ˆ์ž…๋‹ˆ๋‹ค. ๋Œ€์ฒด๋Š” ๋นŒ๋“œ ์‹œ ์ƒ์„ฑ๋˜์ง€ ์•Š์€ ํŽ˜์ด์ง€๋ฅผ ์ •์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ์ฃผ๋ฌธํ˜• ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋นŒ๋“œ ์‹œ ์ƒ์œ„ 100๊ฐœ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์„ ์ƒ์„ฑํ•˜๊ณ  ํŠธ๋ž˜ํ”ฝ์ด ์ ์€ ๋‹ค๋ฅธ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ์€ ์ƒ์„ฑํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์„œ๋„๊ตฌ๋Š” ๊ณง ์ œ๊ณต๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋„ค, ์ œ๊ฐ€ ์˜๋ฏธํ•œ ๊ฒƒ์€ ์ž๋ฆฌ ํ‘œ์‹œ์ž ํŽ˜์ด์ง€์˜€์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@timneutkens ์ •์ ์œผ๋กœ ์ƒ์„ฑ๋œ ํŠน์ • ํŽ˜์ด์ง€๋ฅผ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์•ˆ๋…•ํ•˜์„ธ์š”!!! ์ตœ์ ์˜ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์ฒ˜๋Ÿผ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. ๋‚˜๋Š” React์™€ Next๋ฅผ ๋ชจ๋‘ ์‚ฌ๋ž‘ํ•ฉ๋‹ˆ๋‹ค!!! ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ชจ๋“  ๊ฒƒ์„ ์šฐ์•„ํ•˜๊ณ  ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค!! ๊ทธ๋Ÿฌ๋‚˜ ์˜ˆ์ œ์—๋Š” ๊ฐœ๋… ๋ธ”๋กœ๊ทธ๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. Headless CMS๋ฅผ ์ฟผ๋ฆฌํ•  ๋•Œ ๊ตฌํ˜„์˜ ์˜ˆ๋ฅผ ๋ณด๊ณ  ํŽ˜์ด์ง€/๊ฒŒ์‹œ๋ฌผ๋‹น ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ •์  ํ•ญ๋ชฉ์œผ๋กœ ๋‚ด๋ณด๋‚ด๊ธฐ๋กœ ์ˆ˜ํ–‰ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

// ๊ธˆ์š”์ผ์ด ๊ฐ€๊นŒ์›Œ์„œ ๊ฑด๋ฐฐ!!!

@timneutkens ์‹ ๋‚˜๋„ค์š” ๐Ÿ‘Œ

์šฐ๋ฆฌ๊ฐ€ ์ž์ฃผ ์ ‘ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค ์ค‘ ํ•˜๋‚˜๋Š” ๋™์  ๊ฒฝ๋กœ ๋˜๋Š” ๋ฃจํ”„์—์„œ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ์„ ์ œ์™ธํ•˜๊ณ  next.js ๋˜๋Š” gatsby์— ๋Œ€ํ•œ ์™„๋ฒฝํ•œ ์†”๋ฃจ์…˜์ด ์•„์ง ์—†์Šต๋‹ˆ๋‹ค.

์—ญ์‚ฌ์  ์ด์œ ๋กœ ์šฐ๋ฆฌ๋Š” ๊ฐ€๊ฒฉ, ํ†ตํ™”, ์ง€์› ์ „ํ™”๋ฒˆํ˜ธ ๋ฐ ์–ธ์–ด ์„ ํƒ๊ธฐ๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋™์ผ/์ •ํ™•ํ•œ ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ๋„๋ฉ”์ธ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์ด๋ฅผ ๋ณ€๊ฒฝํ•  ์ƒ๊ฐ์ด ์—†์Šต๋‹ˆ๋‹ค). ๋ณธ์งˆ์ ์œผ๋กœ ์ด๋Ÿฌํ•œ ๋งˆ์ผ€ํŒ… ํŽ˜์ด์ง€์˜ ๋Œ€๋ถ€๋ถ„์€ ๋งค์šฐ ์ •์ ์ด๋ฉฐ ๋งค์ผ ๋˜๋Š” ๋งค์ฃผ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค(๋ชจ๋“  ์š”์ฒญ์— โ€‹โ€‹๋Œ€ํ•ด ๋ Œ๋”๋งํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ๊ณผ ๋น„๊ต).

๋‚ด ์งˆ๋ฌธ/์ƒ๊ฐ: (๋ฏธ๋ž˜์—?) getStaticPaths ๊ฐ€ ๊ฒฝ๋กœ ๋งค๊ฐœ๋ณ€์ˆ˜๋Š” ์•„๋‹ˆ์ง€๋งŒ ์š”์ฒญ ์ˆ˜์ค€์—์„œ ํŽ˜์ด์ง€๋ฅผ ์ „ํ™˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ(์˜ˆ: ์„œ๋ฒ„๋ฆฌ์Šค ํ•จ์ˆ˜๋Š” locale ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์ „ ๋นŒ๋“œ๋œ ์ •์  ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ์ฒด์ ์œผ๋กœ ์ด๊ฒƒ์€ https://mysite.com/my-product ๋ฐ https://mysite.co.uk/my-product ๊ฐ€ ๋‘ ๊ฐœ์˜ ๋‹ค๋ฅธ ์ •์  ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ ๋‹ค์Œ ์•ฑ์„ 50๋ฐฐ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๋ชจ๋“  ์š”์ฒญ์— โ€‹โ€‹๋Œ€ํ•ด CMS๋ฅผ ๋ˆ„๋ฅด์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

๋ฏธ๋ฆฌ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ํŠนํžˆ ๊ทธ๊ฒƒ์ด ๋ฏธ๋ž˜๋ฅผ ์œ„ํ•ด ํ•ด๊ฒฐ/ํ•ด๊ฒฐ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋ผ๋ฉด ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ฃ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค โค๏ธ

SEO๋ฅผ ์œ„ํ•ด ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์€ ๋ฐฉ๋ฌธ ํŽ˜์ด์ง€์™€ ์„œ๋ฒ„ ๋ถ€ํ•˜๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด SSG๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์ง€๋งŒ ์ˆ˜ํ™” ํ›„ ํ˜„์žฌ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์ด ํŽ˜์ด์ง€๋กœ์˜ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์„ ์›ํ•˜๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ๊ฐ€๋Šฅํ• ๊นŒ์š”?

๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด ํŽ˜์ด์ง€๋กœ์˜ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์šฐํŒ…์—์„œ ๋™์ž‘์€ getInitialProps ์™€ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค(ํ˜„์žฌ ๋ฐ์ดํ„ฐ๋Š” ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋˜๊ธฐ ์ „์— ๊ฐ€์ ธ์˜ด). ๊ทธ๋ฆฌ๊ณ  ์ด ํŽ˜์ด์ง€๋กœ์˜ ์„œ๋ฒ„ ์ธก ๋ผ์šฐํŒ…์—์„œ ์ •์  html์ด ์ œ๊ณต๋˜๊ณ  ์ˆ˜ํ™”๋˜์–ด์•ผ ํ•˜๋ฉฐ (์„ ํƒ ์‚ฌํ•ญ) ํŽ˜์ด์ง€์˜ ์ผ๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด ์ผ๋ถ€ API ์‘๋‹ต์„ ๊ฐ€์ ธ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฉ๊ธˆ unstable_getStaticProps ๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์•˜๋Š”๋ฐ ์žฌ๋ฏธ์žˆ๋Š” ์ถฉ๋Œ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. getStaticProps ์™€ API ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ์˜ ์˜๋ฏธ์— ์ฃผ์˜๋ฅผ ๊ธฐ์šธ์ด์ง€ ๋ง๊ณ  ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ ํ๋ฆ„์—๋งŒ ์ฃผ์˜ํ•˜์‹ญ์‹œ์˜ค.

// pages/api/healthcheck.ts
import { NextApiResponse, NextApiRequest } from 'next';

export type ApiHealthCheckResponse = {
  message: 'ok';
};

const healthCheckHandler = (
  req: NextApiRequest,
  res: NextApiResponse<ApiHealthCheckResponse | ''>,
) => {
  if (req.method === 'GET') {
    return res.status(200).json({ message: 'ok' });
  }

  return res.status(405).send('');
};

export default healthCheckHandler;
// pages/index.js
// ...

export async function unstable_getStaticProps() {
  return {
    props: {
      healthcheck: (await fetch('localhost:3000/api/healthcheck').json())
    },
  };
}

์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํŽ˜์ด์ง€ ๋นŒ๋“œ๊ฐ€ ๋นŒ๋“œ ์‹œ ์ถฉ๋Œํ•ฉ๋‹ˆ๋‹ค. getStaticProps ๊ฐ€ ๋„ˆ๋ฌด ๋™์ ์ธ ๊ฒƒ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜์–ด์„œ๋Š” ์•ˆ ๋˜๋ฏ€๋กœ ์ด๊ฒƒ์ด ์œ ํšจํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ธ์ง€ ํ™•์‹คํ•˜์ง€ ์•Š์ง€๋งŒ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ํฅ๋ฏธ๋กœ์šด ์‚ฌ๋ก€๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ API์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์„œ ๋‹ค์‹œ ํฌ๋งทํ•˜์‹ญ์‹œ์˜ค.

@martpie ์ด ๋Œ“๊ธ€์„ ํ™•์ธํ•˜๊ณ  ์‹ถ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค: https://github.com/zeit/next.js/issues/9524#issuecomment -589772756

Next.js 9.3์—์„œ ์ฐจ์„ธ๋Œ€ SSG(์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ) ์ง€์›์ด ์•ˆ์ •์ ์œผ๋กœ ๋ฆด๋ฆฌ์Šค๋˜์—ˆ์Šต๋‹ˆ๋‹ค!

์ด ๋ฆด๋ฆฌ์Šค๋Š” ๋˜ํ•œ "๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋ชจ๋“œ"์— ๋Œ€ํ•œ ์ง€์›, ๋˜๋Š” ์ •์ ์œผ๋กœ ์‚ฌ์ „ ๋ Œ๋”๋ง ๋œ ํŽ˜์ด์ง€ ์šฐํšŒ ํ•  ์ˆ˜์žˆ๋Š” ๊ธฐ๋Šฅ์„ ํฌํ•จํ•˜๊ณ  ์ฃผ๋ฌธํ˜• ๊ถŒํ•œ์ด ๋ถ€์—ฌ ๋œ ์‚ฌ์šฉ์ž์˜ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด ๋ฌธ์„œ ๋กœ ๋ฐ”๋กœ ์ด๋™ํ•˜์‹ญ์‹œ์˜ค!

Next.js GitHub ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์งˆ๋ฌธ์„ ๊ฒŒ์‹œํ•˜์„ธ์š”!

์ด๊ฑฐ ๋Œ€๋ฐ•! ๋…ธ๊ณ ์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์€ ํ˜„์žฌ saga ๋ฐ redux์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰