framework/NextJS

๐Ÿ“Š Next.js App Router ์›น ์• ๋„๋ฆฌํ‹ฑ์Šค ์„ค์ • ์™„๋ฒฝ ๊ฐ€์ด๋“œ

octo54 2025. 4. 29. 11:16
๋ฐ˜์‘ํ˜•

๐Ÿ“Š Next.js App Router ์›น ์• ๋„๋ฆฌํ‹ฑ์Šค ์„ค์ • ์™„๋ฒฝ ๊ฐ€์ด๋“œ

Next.js App Router๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง, ์‚ฌ์šฉ์ž ๋ถ„์„, ์˜คํ”ˆํ…”๋ ˆ๋ฉ”ํŠธ๋ฆฌ ๊ด€์ธก๊นŒ์ง€ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์„ ๊ณ ๋ คํ•ด ์‹ค์šฉ์ ์ธ ๊ตฌ์„ฑ๋งŒ ๋‹ค๋ฃน๋‹ˆ๋‹ค.


โœ… 1. Web Vitals ์„ฑ๋Šฅ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘

Next.js๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์›น ํผํฌ๋จผ์Šค ์ง€ํ‘œ(Core Web Vitals)๋ฅผ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ๋Š” useReportWebVitals ํ›…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•

// app/_components/WebVitals.tsx
'use client';

import { useReportWebVitals } from 'next/web-vitals';

export function WebVitals() {
  useReportWebVitals((metric) => {
    console.log(metric);
    // ์˜ˆ: ์™ธ๋ถ€ ๋ถ„์„ ์„œ๋น„์Šค๋กœ ์ „์†ก ๊ฐ€๋Šฅ
  });
}

๋ฃจํŠธ ๋ ˆ์ด์•„์›ƒ์— ์ถ”๊ฐ€ํ•˜๋ฉด ์ „์—ญ ์ธก์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

// app/layout.tsx
import { WebVitals } from './_components/WebVitals';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body>
        <WebVitals />
        {children}
      </body>
    </html>
  );
}

์ฃผ์˜: ๋ฐ˜๋“œ์‹œ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—ฌ์•ผ ํ•˜๋ฉฐ, 'use client' ์„ ์–ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


โœ… 2. ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ ์‹คํ–‰ํ•˜๊ธฐ

์•ฑ์ด ์‹œ์ž‘ํ•  ๋•Œ ์• ๋„๋ฆฌํ‹ฑ์Šค ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๋‚˜ ์—๋Ÿฌ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด instrumentation-client.ts ํŒŒ์ผ์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ

// instrumentation-client.ts
console.log('์• ๋„๋ฆฌํ‹ฑ์Šค ์‹œ์ž‘');

window.addEventListener('error', (event) => {
  console.error('์˜ค๋ฅ˜ ๋ฐœ์ƒ', event.error);
  // ์˜ค๋ฅ˜๋ฅผ ์™ธ๋ถ€ ์„œ๋ฒ„๋กœ ์ „์†ก ๊ฐ€๋Šฅ
});

์ด ํŒŒ์ผ์€ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ์— ์ƒ์„ฑํ•˜๊ณ , ์ž๋™์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” ๊ณผ์ •์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.


โœ… 3. Google Analytics ์‰ฝ๊ฒŒ ์—ฐ๊ฒฐํ•˜๊ธฐ

๋ฐ˜์‘ํ˜•

Next.js๋Š” GA4๋ฅผ ์‰ฝ๊ฒŒ ์—ฐ๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก @next/third-parties ํŒจํ‚ค์ง€๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์„ค์น˜

npm install @next/third-parties

์‚ฌ์šฉ๋ฒ•

// app/layout.tsx
import { GoogleAnalytics } from '@next/third-parties/google';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body>
        {children}
        <GoogleAnalytics gaId="G-XXXXXXX" />
      </body>
    </html>
  );
}
  • G-XXXXXXX๋Š” ๋ณธ์ธ์˜ Google Analytics ์ธก์ • ID๋กœ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค.
  • ํŽ˜์ด์ง€ ์ด๋™ ์‹œ ์ž๋™ ์ถ”์ ๋ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ : Google Tag Manager๋ฅผ ์“ฐ๋Š” ๊ฒฝ์šฐ, GA ์ง์ ‘ ์‚ฝ์ž… ๋Œ€์‹  GTM์„ ํ†ตํ•ด ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.


โœ… 4. OpenTelemetry๋ฅผ ์ด์šฉํ•œ ๊ณ ๊ธ‰ ๊ด€์ธก ์„ค์ •

์•ฑ ์ „์ฒด ํŠธ๋ž˜ํ”ฝ, API ์‘๋‹ต ์‹œ๊ฐ„, ์„œ๋ฒ„ ์„ฑ๋Šฅ ๋“ฑ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด OpenTelemetry๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ค์ • ์ ˆ์ฐจ

  1. ํŒจํ‚ค์ง€ ์„ค์น˜
npm install @vercel/otel @opentelemetry/sdk-logs @opentelemetry/api-logs @opentelemetry/instrumentation
  1. instrumentation.ts ํŒŒ์ผ ์ƒ์„ฑ
// instrumentation.ts
import { registerOTel } from '@vercel/otel';

registerOTel();
  • ์ž๋™์œผ๋กœ ํŠธ๋ ˆ์ด์Šค(trace), ๋กœ๊ทธ, ๋ฉ”ํŠธ๋ฆญ(metrics)์„ ์ˆ˜์ง‘ ๊ฐ€๋Šฅ
  • Datadog, NewRelic, Jaeger ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฐฑ์—”๋“œ์— ์—ฐ๋™ ๊ฐ€๋Šฅ

โœ… ์š”์•ฝ ์ •๋ฆฌ

๊ธฐ๋Šฅ ๊ตฌํ˜„ ๋ฐฉ๋ฒ• ์œ„์น˜/ํŒŒ์ผ

Web Vitals ์ธก์ • useReportWebVitals ํ›… ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ
ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™” ์ฝ”๋“œ instrumentation-client.ts ์ž‘์„ฑ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ
Google Analytics ์—ฐ๋™ @next/third-parties ์„ค์น˜ ๋ฐ ์‚ฌ์šฉ ๋ฃจํŠธ ๋ ˆ์ด์•„์›ƒ
OpenTelemetry ์„ค์ • instrumentation.ts ์ž‘์„ฑ ๋ฐ ๋“ฑ๋ก ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ

 

https://nextjs.org/docs/app/guides/analytics


 

Next.js, App Router, ์›น ๋ถ„์„, Web Vitals, Google Analytics, OpenTelemetry, ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง, ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”, ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘, SEO ์ตœ์ ํ™”, ์„œ๋ฒ„ ๊ด€์ธก