โ† ๋ชจ๋“  ๊ธ€

next.jsoptimization

Next.js Hidden Optimizations

Next.js๋Š” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ์šฐ์—ฐํžˆ ๋ฐœ๊ฒฌํ•œ ์ตœ์ ํ™” ๊ณผ์ •์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

2025.02.152 min read

Next.js๋Š” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ์šฐ์—ฐํžˆ ๋ฐœ๊ฒฌํ•œ ์ตœ์ ํ™” ๊ณผ์ •์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

MSW์™€ ์•ฑ ๋ผ์šฐํ„ฐ ์—ฐ๋™ ๋ฌธ์ œ

Next.js์˜ ์•ฑ ๋ผ์šฐํ„ฐ์—์„œ MSW๋ฅผ ์—ฐ๋™ํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์•ฑ ๋ผ์šฐํ„ฐ๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด์„œ MSW๋ฅผ ์—ฐ๋™ํ•˜๋Š”๋ฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋Š”๋ฐ,
SSR ๋™์ž‘์‹œ ๊ทธ ์ „์— MSW ์„œ๋ฒ„๊ฐ€ ๋™์ž‘ํ•ด์„œ mock api๋ฅผ ํ™œ์„ฑํ™” ํ•ด์•ผํ•˜๋Š” ๋ฌธ์ œ์˜€์Šต๋‹ˆ๋‹ค.

MSW ์ž์ฒด์—์„œ๋Š” ๋…ธ๋“œ ํŒจํ‚ค์ง€๋ฅผ ์ œ๊ณตํ•ด์„œ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ ์‹œํ‚ฌ์ˆ˜ ์žˆ์—ˆ์œผ๋‚˜, Next.js์˜ SSR ๋™์ž‘ ์ด์ „์— ํ•ด๋‹น ์„œ๋ฒ„๋ฅผ ์ •ํ™•ํžˆ ๋™์ž‘ ์‹œํ‚ฌ ๋ฐฉ๋ฒ•์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ด์Šˆ๋ฅผ ์ฐพ์•„๋ณด์•˜์œผ๋‚˜ ์ž„์‹œ๋ฐฉํŽธ์˜ ํ•ด๊ฒฐ๋ฐฉ๋ฒ• ๋ฟ์ด์˜€์Šต๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ๋ฐœ๊ฒฌ

MSW ์˜ˆ์ œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ ์•ฑ ๋ผ์šฐํ„ฐ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ PR์ด ์˜ฌ๋ผ์™€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น PR์€ ์•„์ง ๋จธ์ง€๊ฐ€ ์•ˆ๋˜์—ˆ์ง€๋งŒ
ํ•ด๋‹น ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ ์–ด๋А์ •๋„ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ๋ฐฉ์‹์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด window ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ํŒ๋ณ„ํ•˜๊ณ  ์ด๋ ‡๊ฒŒ ์„ค์ •ํ•˜๋ฉด SSR๋กœ ์‘๋‹ต์ด ์˜ค๊ธฐ์ „์— ํ•ญ์ƒ MSW ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰์ด ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค.

typescript
'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 ํ”„๋กœ์„ธ์Šค์˜ ์ฝ”๋“œ ์ค‘์— ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

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

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

์ฆ‰, ๋‹ค์ด๋‚˜๋ฏน ์ž„ํฌํŠธ์™€ ๊ฐ™์€ ๋™์ž‘์ด ๋งˆ์ดํฌ๋กœํƒœ์Šคํฌ๋กœ ์ˆ˜ํ–‰๋ ๋•Œ ์ด๋Ÿฌํ•œ ๋™์ž‘์ด ๋จผ์ € ์ˆ˜ํ–‰๋˜์–ด์„œ Next.js์—์„œ ์–ด๋–ค ๋ฆฌ์†Œ์Šค๋“ค์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž„ํฌํŠธํ–ˆ๋Š”์ง€ ๋ถ„์„ํ•˜๊ณ  ์ตœ์ ํ™” ํ•˜๊ธฐ ์œ„ํ•จ์ด์˜€์Šต๋‹ˆ๋‹ค.

Next.js๋Š” ์ด๋ ‡๊ฒŒ ์ˆ˜์ง‘ํ•œ ์ •๋ณด๋ฅผ ํ†ตํ•ด ๋ฉ”์ธ ํŽ˜์ด์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์‘๋‹ต ํ—ค๋”๋กœ preload ์†์„ฑ์„ ๋„ฃ์–ด์„œ HTML ํŒŒ์‹ฑํ•˜์ง€ ์•Š๊ณ  ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์–ด๋–ค ๋ฆฌ์†Œ์Šค๋ฅผ ๋‹ค์šด ๋ฐ›์•„์•ผ ํ• ์ง€ ์ œ๊ณตํ•˜๋ฏ€๋กœ์จ ์ตœ์ ํ™”๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๋‚ด์šฉ์€ ๊ณต์‹๋ฌธ์„œ์— ์ œ๊ณต๋˜์ง€ ์•Š์•„์„œ ์ง์ ‘ ์ฐพ์•„๋ณด์ง€ ์•Š์œผ๋ฉด ์•Œ์ง€ ๋ชปํ•˜๋Š” ๋‚ด์šฉ์ด์˜€์Šต๋‹ˆ๋‹ค.

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