๐Ÿ”ง Next.js ์„ฑ๋Šฅ ์ตœ์ ํ™”๊ธฐ โ‘ก - ์ง€์—ฐ ๋กœ๋”ฉ์œผ๋กœ ๋ฉ”์ธ์Šค๋ ˆ๋“œ ๋‹ค์ด์–ดํŠธ ํ•˜๊ธฐ

ํ˜œ์—ฐยท2025๋…„ 6์›” 3์ผ
0

Next.js

๋ชฉ๋ก ๋ณด๊ธฐ
16/20
post-thumbnail

Minimize main-thread work, 6.7์ดˆ ๐Ÿ˜“

Minimize main-thread work๊ฐ€ 6.7์ดˆ๋กœ, ์ฒซ ํŽ˜์ด์ง€ ์—ด์ž๋งˆ์ž ๋ฉ”์ธ์Šค๋ ˆ๋“œ๊ฐ€ ํ•  ์ผ์ด ๋„ˆ๋ฌด ๋งŽ์ด ์ƒํƒœ์˜€๋‹ค.
JS ํŒŒ์ผ์ด ๋งŽ๊ณ , ๋ฐ์ดํ„ฐ๋„ ์—„์ฒญ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ๋ Œ๋”๋ง๋„ ๋งŽ์•„์ง€๋‹ˆ๊นŒ ๊ทธ๋Ÿฐ๊ฑฐ ๊ฐ™์•˜๋‹ค.
๊ทผ๋ฐ ๋‚˜๋Š” ์ปดํฌ๋„ŒํŠธ๋„ ์ž˜ ์ชผ๊ฐœ๊ณ , use client๋„ ์ตœ๋Œ€ํ•œ ์ค„์ด๋ฉด์„œ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ž˜ ์จ๋†จ์–ด์„œ ๋”์ด์ƒ ๊ตฌ์กฐ์ ์œผ๋กœ ์ชผ๊ฐค ๊ฑด ์—†์—ˆ๋‹ค.
๊ทธ๋ž˜์„œ ๊ฒฐ๊ตญ ๋‚จ์€ ๋ฌธ์ œ๋Š”:

์ฒซ ํŽ˜์ด์ง€์—์„œ ๋„ˆ๋ฌด ๋งŽ์€ ๊ฑธ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์—ˆ๋˜ ๊ฒŒ ๋ฌธ์ œ์˜€๋‹ค.


๊ทธ๋ž˜์„œ ๋‚˜๋Š” "์ง€์—ฐ ๋กœ๋”ฉ"์„ ์ ์šฉํ–ˆ๋‹ค.

์ง€์—ฐ ๋กœ๋”ฉ์€ ๋ง ๊ทธ๋Œ€๋กœ ์ง€์—ฐํ•ด์„œ ๋กœ๋”ฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
ํ•„์š”ํ•œ ์‹œ์ ์ด ๋  ๋•Œ ๊ทธ๋•Œ ๊ฐ€์„œ ๊ฐ์ฒด(์ปดํฌ๋„ŒํŠธ)๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์ด๋ผ๊ณ  ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค.

์ฒซ ํŽ˜์ด์ง€์—์„œ ๋ฐ”๋กœ ๋ณด์—ฌ์ฃผ์ง€ ์•Š์•„๋„ ๋˜๋Š” ๊ฒƒ์€ ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ๋ฉ”์ธ์Šค๋ ˆ๋“œ์˜ ๋ถ€๋‹ด์„ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•

์˜ˆ๋ฅผ ๋“ค์–ด ๋‚ด ์‚ฌ์ดํŠธ์—์„œ๋Š”

  • ๋กœ๊ทธ์ธ / ๋งˆ์ดํŽ˜์ด์ง€ ๋ฒ„ํŠผ
    ํ—ค๋”์— ๋ฐ”๋กœ ๋ณด์—ฌ์•ผ ํ•˜๋‹ˆ๊นŒ ์ง€์—ฐ ๋กœ๋”ฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•จ
  • ๋กœ๊ทธ์ธ / ํšŒ์›๊ฐ€์ž… ๋ชจ๋‹ฌ
    ๋ฒ„ํŠผ ๋ˆ„๋ฅด๊ธฐ ์ „๊นŒ์ง„ ์•ˆ ๋ณด์—ฌ๋„ ๋˜๋‹ˆ๊นŒ ์ง€์—ฐ ๋กœ๋”ฉํ•˜๊ธฐ ๋”ฑ ์ข‹์Œ
  • ์ธ๊ธฐ ์Šคํ„ฐ๋”” ์Šฌ๋ผ์ด๋”
    ์Šค์ผˆ๋ ˆํ†ค UI๊ฐ€ ์žˆ์–ด์„œ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ผญ ๋ณด์—ฌ์ค„ ํ•„์š”๋Š” ์—†์Œ โ†’ ์ง€์—ฐ ๋กœ๋”ฉ ์ ํ•ฉ

๋กœ๊ทธ์ธ ๋ชจ๋‹ฌ ์ง€์—ฐ ๋กœ๋”ฉ

Next.js์—์„œ ๋™์  import ํ•  ๋• dynamic()์„ ์“ฐ๋Š”๋ฐ, ์ด๊ฑด ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
๊ทธ๋ž˜์„œ ๋‚˜๋Š” DynamicmodalWrapper.tsx๋ผ๋Š” ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ–ˆ๋‹ค.

"use client";
import dynamic from "next/dynamic";

// ๋ชจ๋‹ฌ ์ปดํฌ๋„ŒํŠธ ๋™์  import, SSR ๋น„ํ™œ์„ฑํ™”
const LoginSignupModal = dynamic(
  () => import("@/components/auth/LoginSignupModal"),
  { ssr: false }
);

export default function DynamicModalWrapper() {
  return <LoginSignupModal />;
}

์—ฌ๊ธฐ์„œ ssr: false๋Š” ์„œ๋ฒ„์— ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ  ๋ธŒ๋ผ์šฐ์ €์—๋งŒ ๋ Œ๋”๋งํ•˜๊ฒ ๋‹ค๋Š” ๋œป์ด๋‹ค. ์ด ๋ชจ๋‹ฌ ์ปดํฌ๋„ŒํŠธ๋Š” ์œ ์ €๊ฐ€ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์„œ ํ•„์š”ํ•œ ์ˆœ๊ฐ„์—๋งŒ ๋ถˆ๋Ÿฌ์˜ค๊ฒŒ ๋˜๋Š” ๊ฒƒ!


โœ… ์ธ๊ธฐ ์Šคํ„ฐ๋”” ์Šฌ๋ผ์ด๋”๋„ ์ง€์—ฐ ๋กœ๋”ฉ

๋กœ๊ทธ์ธ ๋ชจ๋‹ฌ์ฒ˜๋Ÿผ ์ธ๊ธฐ๊ธ€ ์Šฌ๋ผ์ด๋”๋„ dynamic์œผ๋กœ ๊ฐ์ŒŒ๋‹ค.

const PopularStudySlider = dynamic(() => import("./PopularStudySlider"), {
  ssr: false,
  loading: () => (
    <div className="grid grid-cols-1 md:grid-cols-3  ">
      {Array.from({ length: 1 }).map((_, i) => (
        <PopularCardSkeleton key={i} />
      ))}
    </div>
  ),
});

์ฒ˜์Œ์—๋Š” ์ธ๊ธฐ๊ธ€๋„ ์ง€์—ฐ๋กœ๋”ฉ์„ ํ•˜๋Š”๊ฒŒ ๋งž๋Š”์ง€ ๊ณ ๋ฏผํ–ˆ๋‹ค. ์ธ๊ธฐ๊ธ€์€ ๋น ๋ฅด๊ฒŒ ๋ณด์—ฌ์ฃผ๋Š”๊ฒŒ ์ข‹์„๊ฑฐ ๊ฐ™์•„์„œ
๊ทผ๋ฐ ์˜คํžˆ๋ ค ์ง€์—ฐ๋กœ๋”ฉ์„ ์ ์šฉํ•˜๋‹ˆ๊นŒ ํŽ˜์ด์ง€๊ฐ€ ๋” ๋นจ๋ผ์ ธ์„œ ์ธ๊ธฐ๊ธ€์ด ๋” ๋นจ๋ฆฌ ๋ณด์ด๋Š” ๋А๋‚Œ์ด ๋“ค์—ˆ๋‹ค.
์•„๋งˆ ์ „์ฒด ํŽ˜์ด์ง€๊ฐ€ ๋ฌด๊ฑฐ์›Œ์„œ ๋А๋ ค์ง€๋˜๊ฒŒ ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ์กฐ๊ธˆ ๋ถ„์‚ฐ๋˜๋‹ˆ๊นŒ ๋‚˜๋จธ์ง€๊ฐ€ ๋” ๋นจ๋ฆฌ ๋กœ๋”ฉ๋˜๋Š”๊ฒŒ ์•„๋‹๊นŒ?

์ถ”๊ฐ€์ ์œผ๋กœ loading ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์„œ ์Šค์ผˆ๋ ˆํ†ค UI์„ ๋ณด์—ฌ์ฃผ๋ฉด์„œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œ์ผฐ๋‹ค.


์ตœ์ข…๊ฒฐ๊ณผ

์ด๋ ‡๊ฒŒ ์ธ๊ธฐ๊ธ€ ์Šฌ๋ผ์ด๋” + ๋กœ๊ทธ์ธ ๋ชจ๋‹ฌ์„ ์ง€์—ฐ ๋กœ๋”ฉ์œผ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ๋‚˜์„œ ๋‹ค์‹œ ์„ฑ๋Šฅ ์ธก์ •ํ•ด๋ดค๋”๋‹ˆโ€ฆ

Minimize main-thread work
6.7์ดˆ โ†’ 5.6์ดˆ๋กœ ์ค„์–ด๋“ฆ!! ๐ŸŽ‰

๊ฐ„๋‹จํ•œ ์ง€์—ฐ ๋กœ๋”ฉ์œผ๋กœ 1.1์ดˆ๋‚˜ ์ค„์–ด๋“ค์–ด์„œ ๋งŒ์กฑ์Šค๋Ÿฌ์› ๋‹ค.


๋‹ค์ŒํŽธ์—์„œ๋Š” DB ์ตœ์ ํ™”์™€ ์ธ๋ฑ์Šค ์ถ”๊ฐ€ ๋“ฑ์œผ๋กœ ๋ฐฑ์—”๋“œ ์‘๋‹ต ์†๋„๋ฅผ ์ค„์ธ ๊ณผ์ •์„ ์ •๋ฆฌํ•  ์˜ˆ์ •์ž„๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€