Web

NextJS ν”„λ‘œμ νŠΈ λ°°ν¬ν•˜κΈ° ( with. Github Acion, κ°€λΉ„μ•„ )

3jun 2023. 1. 27. 19:22
πŸ’‘ λ³Έ ν¬μŠ€νŒ…μ€ NextJs ν”„λ‘œμ νŠΈλ₯Ό 배포 과정을 μ†Œκ°œν•˜λŠ”κ²Œ μ•„λ‹ˆλΌ, 배포 κ³Όμ •μ—μ„œ κ²ͺ은 μ—λŸ¬λ“€μ„ μ†Œκ°œν•˜κ³  ν•΄κ²° 방법듀을 κΈ°λ‘ν•˜κΈ° μœ„ν•œ κΈ€μž…λ‹ˆλ‹€. 배포 방법을 μ°ΎμœΌμ‹œλŠ” 뢄은 λ’€λ‘œκ°€κΈ° λ²„νŠΌμ„ λˆŒλŸ¬μ£Όμ„Έμš”.

μ—λŸ¬ ν™˜κ²½

기쑴에 Vercel 을 ν™œμš©ν•˜μ—¬ 배포 ν–ˆλ˜ ν”„λ‘œμ νŠΈλ₯Ό Github pages 둜 배포 ν”Œλž«νΌμ„ λ³€κ²½ν•˜λŠ” κ³Όμ •μ—μ„œ λ°œμƒ

 

이전에 μ§„ν–‰ν–ˆλ˜ μ‚¬μ΄λ“œ ν”„λ‘œμ νŠΈλ₯Ό Vercel을 μ‚¬μš©ν•˜μ—¬ λ°°ν¬ν•˜κ³  κ°€λΉ„μ•„μ—μ„œ κ΅¬λ§€ν•œ 도맀인을 μ—°κ²°ν–ˆμ—ˆλ‹€.

ν•œλ‹¬ 반쯀 μ§€λ‚¬μ„κΉŒ μ•„λž˜μ™€ 같은 κ²½κ³  λ©”μ‹œμ§€λ₯Ό λ°›μ•˜λ‹€.

μ•„λ¬΄λž˜λ„ 각 νŽ˜μ΄μ§€μ— μž‘κ²ŒλŠ” 10μ—¬κ°œ λ§Žκ²ŒλŠ” 수백개의 이미지λ₯Ό λžœλ”λ§ ν•˜λ‹€λ³΄λ‹ˆ image source의 갯수 μ œν•œμ„ μ΄ˆκ³Όν–ˆλ˜ λͺ¨μ–‘이닀.

ν•œλ™μ•ˆ μ±„μš©κ³Όμ œλ₯Ό μ§„ν–‰ν•˜λŠλΌ, μ•„λ¬΄λŸ° 쑰치λ₯Ό λͺ»ν–ˆμ—ˆλŠ”데 5μ°¨λ‘€ κ²½κ³  λ©”μ‹œμ§€κ°€ 온 ν›„ 배포가 μ€‘λ‹¨λ˜μ–΄ 버렸닀. κ²Œλ‹€κ°€ μ‚¬μš©λŸ‰μ΄ ν”„λ‘œμ νŠΈλ³„λ‘œ 카운트 λ˜λŠ” 것이 μ•„λ‹ˆλΌ κ³„μ •λ‹¨μœ„λ‘œ 카운트 λ˜λŠ” 건지 이제 κ³„μ •μ—μ„œ 배포λ₯Ό ν•˜λ €κ³  ν•˜λ‹ˆ Pro λ²„μ „μœΌλ‘œ μ—…κ·Έλ ˆμ΄λ“œλ₯Ό μš”κ΅¬ν•˜λŠ” λ°”λžŒμ— μƒˆλ‘œμš΄ 방법을 μ°Ύμ•„μ•Όλ§Œ ν–ˆλ‹€. ( 배포가 μ€‘λ‹¨λ˜κ³  λ‚˜λ‹ˆ μ„œλ₯˜ 합격λ₯ μ΄ ν˜„μ €νžˆ λ–¨μ–΄μ Έμ„œ μ‹œκΈ‰ν•˜κ²Œ ν•΄κ²°ν•΄μ•Όλ§Œ ν–ˆλ‹€. )

 

이전에 κΉƒν—ˆλΈŒ νŽ˜μ΄μ§€λ‘œ λ°°ν¬ν–ˆμ„ λ•ŒλŠ” 이런 λ¬Έμ œκ°€ μ—†μ—ˆκΈ°μ— ν›„λ‹€λ‹₯ κΉƒν—ˆλΈŒ νŽ˜μ΄μ§€λ‘œ λ°°ν¬ν•˜κ³ μž ν–ˆμœΌλ‚˜... λ„ˆλ¬΄ μ•ˆμΌμ•ˆ μƒκ°μ΄μ—ˆλ‹€.

κΉƒν—ˆλΈŒ νŽ˜μ΄μ§€λ₯Ό ν™œμš©ν•˜μ—¬ NextJS ν”„λ‘œμ νŠΈλ₯Ό λ°°ν¬ν•˜λŠ” 방법은 ꡬ글에 수 λ§Žμ€ μžλ£Œκ°€ μžˆμœΌλ‹ˆ νŒ¨μŠ€ν•˜κ³  λ‚΄κ°€ κ²ͺμ—ˆλ˜ μ—λŸ¬λ“€ μœ„μ£Όλ‘œ κΈ°λ‘ν•˜λ €κ³  ν•œλ‹€. 

첫번째 μ—λŸ¬. Github Action을 μ‚¬μš©ν•˜μ—¬ NextJS ν”„λ‘œμ νŠΈ build κ³Όμ •μ—μ„œ λ°œμƒν•œ μ—λŸ¬ ( Static HTML Export )

ν”„λ‘œμ νŠΈλ₯Ό λΉŒλ“œν•˜λŠ” κ³Όμ •μ—μ„œ Static HTML export with Next.js λ‹¨κ³„μ—μ„œ μ—λŸ¬κ°€ λ°œμƒν•˜μ˜€λ‹€.

μ—λŸ¬ λ°œμƒ 원인. Static HTML Export 

κ³΅μ‹λ¬Έμ„œμ—μ„œ Static HTML export 에 λŒ€ν•΄μ„œ 찾아보면 μ•„λž˜μ™€ 같이 κΈ°λŠ₯듀이 λ‚˜λ‰˜μ–΄μ Έ μžˆλ‹€. 

next export λ₯Ό ν™œμš©ν•˜μ—¬ Next.js application을 static HTML둜 export  ν•˜λŠ”λ°, μ΄λŠ” Node.js μ„œλ²„κ°€ 없어도 λ…λ¦½μ μœΌλ‘œ μ‹€ν–‰κ°€λŠ₯ν•˜λ‹€. μ„œλ²„λ₯Ό μš”κ΅¬ν•˜λŠ” μ œκ³΅λ˜μ§€ μ•ŠλŠ” κΈ°λŠ₯을 ν•„μš”λ‘œ ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ next export λ₯Ό λ‹¨λ…μœΌλ‘œ μ‚¬μš©ν•˜λŠ” 것을 μΆ”μ²œν•œλ‹€.

즉, Node.js μ„œλ²„κ°€ μžˆμ–΄μ•Όλ§Œ getServerSideProps λ₯Ό μ‚¬μš©ν•  수 μžˆλŠ”λ° 이 ν”„λ‘œμ νŠΈλŠ” μ„œλ²„λ‹¨ μ½”λ“œκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŒμ—λ„ getServersideProps λ₯Ό ν™œμš©ν•˜μ—¬ μ½”λ“œκ°€ μž‘μ„±ν–ˆκΈ°μ— λ°œμƒν•œ μ—λŸ¬μ˜€λ‹€.

κ°œμ„ λ°©λ²•

κΈ°μ‘΄ getServerSideProps μ½”λ“œ

export const getServerSideProps: GetServerSideProps = wrapper.getServerSideProps(() => async (context) => {
  const param = context.query.clips;

  const queryClient = new QueryClient();

  await queryClient.prefetchQuery([QUERY_KEYS.GETDATA_BYID], () => getContentById(param as string));
  await queryClient.prefetchQuery([QUERY_KEYS.GET_UPNEXT], () => getUpNext(param as string));

  return {
    props: { dehydratedState: dehydrate(queryClient), param },
  };
});

βœ… getSaticProps 와 getStaticPaths μ½”λ“œ

...
export const getStaticProps: GetStaticProps = async (context) => {
  const param = context.params?.clips;

  const queryClient = new QueryClient();

  await queryClient.prefetchQuery([QUERY_KEYS.GETDATA_BYID], () => getContentById(param as string));
  await queryClient.prefetchQuery([QUERY_KEYS.GET_UPNEXT], () => getUpNext(param as string));

  return {
    props: { dehydratedState: dehydrate(queryClient) },
  };
};

export const getStaticPaths: GetStaticPaths = async () => {
  return {
    paths: [],
    fallback: 'blocking',
  };
};
...

 

λ‘λ²ˆμ§Έ μ—λŸ¬. Custom domain μ—°κ²°ν•˜λŠ” κ³Όμ •μ—μ„œ DNS check unsuccessful (κ°€λΉ„μ•„)

μœ„ λ°©λ²•λŒ€λ‘œ getServerSideProps λ₯Ό getStaticProps둜 μˆ˜μ •ν•˜κ³  λ‚˜λ‹ˆ build 와 deployκ°€ μ •μƒμ μœΌλ‘œ μ΄λ£¨μ–΄μ‘Œλ‹€. 이전에 Vercel둜 λ°°ν¬ν•˜λ©΄μ„œ 섀정을 λ°”κΏ”λ†“μ•„μ„œμΈμ§€ url 도 λ°”λ‘œ λ‚΄κ°€ 기쑴에 μ‚¬μš©ν•˜λ˜ cutom domain으둜 μ—°κ²°λ˜μ—ˆμœΌλ‚˜, 404 μ—λŸ¬κ°€ 좜λ ₯λ˜μ—ˆλ‹€. 

 

κ°€λΉ„μ•„μ—μ„œ κ΅¬λ§€ν•œ 도메인을 μ—°κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” μƒˆ λ°°ν¬ν™˜κ²½μ— 맞게 κ°€λΉ„μ•„μ—μ„œλ„ 섀정을 손봐야 ν–ˆλ‹€.

DNS μ„€μ •ν•˜κΈ°

1. κ°€λΉ„μ•„ 둜그인 ν›„ DNS κ΄€λ¦¬νˆ΄ λ©”λ‰΄λ‘œ 이동

2. DNS 관리 λ©”λ‰΄μ—μ„œ 섀정은 λ³€κ²½ν•˜κ³ μž ν•˜λŠ” 도메인을 μ„ νƒν•˜κ³  DNS μ„€μ •μœΌλ‘œ 이동

3. λ°°ν¬ν™˜κ²½μ— 맞게 CNAME, A λ ˆμ½”λ“œλ₯Ό μΆ”κ°€ ( μ—¬κΈ°μ—μ„œλŠ” Github λ ˆμ½”λ“œ 값듀을 μΆ”κ°€ν•˜μ˜€μŒ)

μ—¬κΈ°κΉŒμ§€λ§Œ 잘 λ”°λΌμ˜€λ©΄ λŒ€λΆ€λΆ„ λ¬Έμ œκ°€ 없을 것이닀.

ν•˜μ§€λ§Œ 이처럼 DNS check κ°€ 성곡적이지 μ•Šλ‹€λŠ” μ—λŸ¬ λ©”μ‹œμ§€μ°½μ„ 확인할 수 μžˆλŠ”λ°, 이것은 DNS μ„œλ²„κ°€ μ‹€μ‹œκ°„μœΌλ‘œ μ μš©λ˜μ§€ μ•Šμ•„μ„œ μž„μ‹œλ‘œ λ°œμƒν•˜λŠ” μ—λŸ¬μ΄κ³  μΆ”ν›„ λ ˆμ½”λ“œ 변경사항이 DNS μ„œλ²„μ— 적용되고 λ‚˜λ©΄ μ •μƒλ™μž‘ ν•œλ‹€κ³  ν•œλ‹€. 

이λ₯Ό μœ„ν•΄ μ†Œμš”λ˜λŠ” μ‹œκ°„μ€ 볡뢈볡이며 μ΅œλŒ€ 48μ‹œκ°„ κΉŒμ§€λ„ 걸릴 수 μžˆλ‹€κ³  ν•œλ‹€. (by Github Community discussions )

이걸 λ―Ώκ³  48μ‹œκ°„μ„ κΈ°λ‹€λ ΈμŒμ—λ„ λ‚˜λŠ” 배포가 μ •μƒμ μœΌλ‘œ λ˜μ§€ μ•Šμ•˜λ‹€. μ—¬μ „νžˆ 404 νŽ˜μ΄μ§€λ§Œ λ³΄μ˜€λ‹€.

μ—λŸ¬ λ°œμƒ 원인. λ„€μž„μ„œλ²„

원인을 찾지 λͺ»ν•΄ 거의 ν•˜λ£¨ν•˜κ³ λ„ λ°˜λ‚˜μ ˆμ„ ν—€λ§ΈλŠ”λ°, 원인은 DNS μ„œλ²„μ— μžˆμ—ˆλ‹€. ν„°λ―Έλ„μ—μ„œ dig μ»€λ§¨λ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ νŠΉμ • 도메인에 λŒ€ν•œ DNS μ„œλ²„ 정보λ₯Ό  확인할 수 μžˆλŠ”λ° λ‚΄ μ»€μŠ€ν…€ 도메인을 ν™•μΈν•΄λ³΄λ‹ˆ ANSWER SECTION에 A λ ˆμ½”λ“œ 값이 μ•„λž˜ μŠ€ν¬λ¦°μƒ·μ—μ„œ 보듯이 κΉƒν—ˆλΈŒ νŽ˜μ΄μ§€μ˜ A λ ˆμ½”λ“œκ°€ μ•„λ‹ˆλΌ 이전에 λ°°ν¬ν–ˆλ˜ Vercel의 A λ ˆμ½”λ“œ 값이 λ“€μ–΄μžˆμ—ˆλ‹€. 

λΆ„λͺ… κΉƒν—ˆλΈŒμ˜ CNAME, A λ ˆμ½”λ“œλ₯Ό μΆ”κ°€ν•˜λ©΄μ„œ 기쑴에 있던 A λ ˆμ½”λ“œ 값을 μ‚­μ œν–ˆμŒμ—λ„ 도메인에 적용이 λ˜μ–΄μžˆμ§€ μ•Šμ•„ 배포가 이루어지지 μ•Šμ•˜λ˜ κ²ƒμ΄μ—ˆλ‹€. 

κ°œμ„  방법. λ„€μž„μ„œλ²„ μ„€μ • λ³€κ²½

1. κ°€λΉ„μ•„ 둜그인 ν›„ 도메인 톡합 κ΄€λ¦¬νˆ΄ λ©”λ‰΄λ‘œ 이동

2. 도메인 κ΄€λ¦¬μ—μ„œ 도메인 정보 λ³€κ²½ 클릭 ν›„, λ³€κ²½ν•˜κ³ μž ν•˜λŠ” 도메인 μ²΄ν¬ν•œ ν›„ λ„€μž„μ„œλ²„ 클릭

4. βœ… λ„€μž„μ„œλ²„λ₯Ό λ°°ν¬ν•˜κ³ μž ν•˜λŠ” ν™˜κ²½μ— 따라 μˆ˜μ •

κΈ°μ‘΄μ—λŠ” μ•„λž˜μ™€ 같이 vercel의 λ„€μž„μ„œλ²„λ‘œ μ„€μ •λ˜μ–΄ μžˆμ—ˆλŠ”λ°,

κΉƒν—ˆλΈŒμ—μ„œλŠ” λ³„λ„μ˜ λ„€μž„μ„œλ²„λ₯Ό 섀정을 μš”κ΅¬ν•˜μ§€ μ•Šμ•„ κ°€λΉ„μ•„μ˜ λ„€μž„μ„œλ²„λ‘œ μˆ˜μ •ν•˜μ˜€λ‹€. 

μ—¬κΈ°κΉŒμ§€ ν•˜κ³  λ‚˜λ‹ˆ μ•½ 10λΆ„ 후에 배포가 μ •μƒμ μœΌλ‘œ μ΄λ£¨μ–΄μ‘Œλ‹€. 

μ™œ? λΌλŠ” 질문이 μ™œ μ€‘μš”ν•œμ§€ κΉ¨λ‹¬μ•˜λ˜ κ²½ν—˜..