← λͺ©λ‘μœΌλ‘œ
Next.js Hidden Optimizations

Next.jsλŠ” λ§Žμ€ κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€. κ·Έ 쀑 μš°μ—°νžˆ λ°œκ²¬ν•œ μ΅œμ ν™” 과정에 λŒ€ν•΄ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

MSW와 μ•± λΌμš°ν„° 연동 문제

Next.js의 μ•± λΌμš°ν„°μ—μ„œ MSWλ₯Ό μ—°λ™ν•˜κ³ μž ν–ˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ μ•± λΌμš°ν„°λ‘œ λ³€κ²½λ˜λ©΄μ„œ MSWλ₯Ό μ—°λ™ν•˜λŠ”λ° λ¬Έμ œκ°€ μžˆμ—ˆλŠ”λ°,
SSR λ™μž‘μ‹œ κ·Έ 전에 MSW μ„œλ²„κ°€ λ™μž‘ν•΄μ„œ mock apiλ₯Ό ν™œμ„±ν™” ν•΄μ•Όν•˜λŠ” λ¬Έμ œμ˜€μŠ΅λ‹ˆλ‹€.

MSW μžμ²΄μ—μ„œλŠ” λ…Έλ“œ νŒ¨ν‚€μ§€λ₯Ό μ œκ³΅ν•΄μ„œ μ„œλ²„λ₯Ό μ‹€ν–‰ μ‹œν‚¬μˆ˜ μžˆμ—ˆμœΌλ‚˜, Next.js의 SSR λ™μž‘ 이전에 ν•΄λ‹Ή μ„œλ²„λ₯Ό μ •ν™•νžˆ λ™μž‘ μ‹œν‚¬ 방법이 μ—†μ—ˆμŠ΅λ‹ˆλ‹€.
κ·Έλž˜μ„œ μ—¬λŸ¬κ°€μ§€ 이슈λ₯Ό μ°Ύμ•„λ³΄μ•˜μœΌλ‚˜ μž„μ‹œλ°©νŽΈμ˜ 해결방법 λΏμ΄μ˜€μŠ΅λ‹ˆλ‹€.

ν•΄κ²° 방법 발견

MSW 예제 λ ˆν¬μ§€ν† λ¦¬μ—μ„œ μ•± λΌμš°ν„° ν™˜κ²½μ— λŒ€ν•œ PR이 μ˜¬λΌμ™€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€. ν•΄λ‹Ή PR은 아직 λ¨Έμ§€κ°€ μ•ˆλ˜μ—ˆμ§€λ§Œ
ν•΄λ‹Ή μ ‘κ·Ό λ°©μ‹μœΌλ‘œ μ–΄λŠμ •λ„ λ¬Έμ œκ°€ ν•΄κ²°λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

해결방식은 μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€. μ½”λ“œλ₯Ό 보면 window 객체λ₯Ό μ΄μš©ν•΄ μ„œλ²„μ™€ ν΄λΌμ΄μ–ΈνŠΈλ₯Ό νŒλ³„ν•˜κ³  μ΄λ ‡κ²Œ μ„€μ •ν•˜λ©΄ SSR둜 응닡이 μ˜€κΈ°μ „μ— 항상 MSW μ„œλ²„κ°€ 싀행이 보μž₯λ©λ‹ˆλ‹€.

'use client';

import { PropsWithChildren, use } from 'react';

const shouldMockRequest = (url: string) => {
  return !url.includes('_rsc') && !url.includes('/_next/') && url.includes('api');
};

const mockingEnabledPromise =
  typeof window !== 'undefined'
    ? import('./browser').then(async ({ worker }) => {
        await worker.start({
          onUnhandledRequest: (request, print) => {
            if (shouldMockRequest(request.url)) {
              print.warning();
            }
          },
        });
      })
    : import('./mocks/server').then(async ({ server }) => {
        await server.listen({
          onUnhandledRequest: (request, print) => {
            if (shouldMockRequest(request.url)) {
              print.warning();
            }
          },
        });
      });

Next.js의 μˆ¨κ²¨μ§„ μ΅œμ ν™” 발견

이 μ½”λ“œλ₯Ό 보고 Next.jsμ—μ„œλŠ” λ‚΄λΆ€μ—μ„œ λ Œλ”λ§μ„ ν•˜κΈ° 전에 이런 μ½”λ“œλ₯Ό μ–΄λ–»κ²Œ 평가할 것인지에 λŒ€ν•΄μ„œ ꢁ금증이 μƒκ²ΌμŠ΅λ‹ˆλ‹€.
κ·ΈλŸ¬λ‹€κ°€ Next.js의 SSR ν”„λ‘œμ„ΈμŠ€μ˜ μ½”λ“œ 쀑에 μ•„λž˜μ™€ 같은 μ½”λ“œλ₯Ό λ°œκ²¬ν–ˆμŠ΅λ‹ˆλ‹€.

await Promise((res) => setTimeout(() => res()));

이 μ½”λ“œλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈ μ—”μ§„μ˜ 이벀트 루프λ₯Ό ν•œλ²ˆ κ±΄λ„ˆλ›°κ³  λ‹€μŒ 이벀트 루프에 λ™μž‘ν•˜λ„λ‘ 보μž₯ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.
그리고 μ£Όμ„μœΌλ‘œ Next.jsλŠ” 동기적인 λ Œλ”λ§ ν”„λ‘œμ„ΈμŠ€λ₯Ό μ›ν•˜λŠ”κ±΄ μ•„λ‹ˆμ§€λ§Œ preload와 κ΄€λ ¨λœ μ΅œμ ν™”λ₯Ό μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ λ Œλ”λ§μ„ μΌλΆ€λŸ¬ μ§€μ—°ν•œλ‹€λŠ” λ‚΄μš©μ΄μ˜€μŠ΅λ‹ˆλ‹€.

즉, λ‹€μ΄λ‚˜λ―Ή μž„ν¬νŠΈμ™€ 같은 λ™μž‘μ΄ λ§ˆμ΄ν¬λ‘œνƒœμŠ€ν¬λ‘œ μˆ˜ν–‰λ λ•Œ μ΄λŸ¬ν•œ λ™μž‘μ΄ λ¨Όμ € μˆ˜ν–‰λ˜μ–΄μ„œ Next.jsμ—μ„œ μ–΄λ–€ λ¦¬μ†ŒμŠ€λ“€μ„ κ°œλ°œμžκ°€ μž„ν¬νŠΈν–ˆλŠ”μ§€ λΆ„μ„ν•˜κ³  μ΅œμ ν™” ν•˜κΈ° μœ„ν•¨μ΄μ˜€μŠ΅λ‹ˆλ‹€.

Next.jsλŠ” μ΄λ ‡κ²Œ μˆ˜μ§‘ν•œ 정보λ₯Ό 톡해 메인 νŽ˜μ΄μ§€λ₯Ό λ°˜ν™˜ν•˜λŠ” 응닡 ν—€λ”λ‘œ preload 속성을 λ„£μ–΄μ„œ HTML νŒŒμ‹±ν•˜μ§€ μ•Šκ³  λΈŒλΌμš°μ €κ°€ μ–΄λ–€ λ¦¬μ†ŒμŠ€λ₯Ό λ‹€μš΄ λ°›μ•„μ•Ό ν• μ§€ μ œκ³΅ν•˜λ―€λ‘œμ¨ μ΅œμ ν™”λ₯Ό μˆ˜ν–‰ν•©λ‹ˆλ‹€.

이런 λ‚΄μš©μ€ κ³΅μ‹λ¬Έμ„œμ— μ œκ³΅λ˜μ§€ μ•Šμ•„μ„œ 직접 찾아보지 μ•ŠμœΌλ©΄ μ•Œμ§€ λͺ»ν•˜λŠ” λ‚΄μš©μ΄μ˜€μŠ΅λ‹ˆλ‹€.

이처럼 Next.jsλŠ” μš°λ¦¬κ°€ μ•Œμ§€λͺ»ν•˜λŠ” μ΅œμ ν™”λ₯Ό λ‚΄λΆ€μ μœΌλ‘œ 많이 μˆ˜ν–‰ν•©λ‹ˆλ‹€.
κ·Έλž˜μ„œ 이런 ν”„λ ˆμž„μ›Œν¬λŠ” μ‹€μ œλ‘œ 많이 μ‚¬μš©ν•΄λ³΄μ§€ μ•ŠμœΌλ©΄ μ˜ˆμƒμΉ˜ λ™μž‘μ„ 맞이 ν•  수 있기 λ•Œλ¬Έμ— μœ μ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.