W Metropolii Quantum, zaawansowane systemy diagnostyczne są kluczowe dla prawidłowego funkcjonowania całej infrastruktury. Niewidzialne dla przeciętnego obywatela sieci czujników i analizatorów nieustannie monitorują każdy aspekt miejskich systemów, pozwalając inżynierom na szybkie wykrywanie i naprawianie problemów. Podobnie w świecie Next.js, instrumentation i narzędzia debugowania zapewniają deweloperom wgląd w działanie aplikacji i możliwość szybkiego rozwiązywania problemów.
Instrumentacja w kontekście Next.js odnosi się do procesu dodawania kodu monitorującego do aplikacji w celu zbierania danych o jej wydajności, błędach i zachowaniu. Jest to jak sieć czujników kwantowych rozmieszczonych w kluczowych punktach Metropolii Quantum - pozwalają one na monitorowanie stanu systemów i zbieranie danych niezbędnych do analizy ich działania.
Next.js 15 oferuje zaawansowane narzędzia instrumentacji, które pozwalają deweloperom lepiej zrozumieć i zoptymalizować działanie swoich aplikacji.
Next.js 15 wprowadza dedykowany plik instrumentacji, który jest wykonywany podczas startu serwera. Możesz go użyć do konfiguracji narzędzi monitorujących, takich jak Sentry, New Relic, czy OpenTelemetry.
Aby włączyć instrumentację w aplikacji Next.js, wykonaj następujące kroki:
Utwórz plik o nazwie
instrumentation.ts (lub instrumentation.js) w katalogu głównym aplikacji (obok app lub src/app).Upewnij się, że twój plik
next.config.js zawiera flagę experimental.instrumentationHook = true:1// next.config.js
2/** @type {import('next').NextConfig} */
3const nextConfig = {
4 experimental: {
5 instrumentationHook: true,
6 }
7};
8
9module.exports = nextConfig;Zaimplementuj hook
register w pliku instrumentacji:1// instrumentation.ts
2export async function register() {
3 if (process.env.NEXT_RUNTIME === 'nodejs') {
4 // Kod instrumentacji wykonywany tylko na serwerze
5 console.log('Inicjalizacja systemu monitorowania Metropolii Quantum...');
6
7 // Tutaj możesz zaimplementować właściwą instrumentację
8 // np. inicjalizację Sentry, LogRocket, czy OpenTelemetry
9 }
10}Funkcja
register jest wywoływana przy starcie aplikacji i może być używana do ustawienia monitorowania na poziomie całej aplikacji.W Metropolii Quantum, różne systemy monitorowania spełniają różne role - od monitorowania poziomu energii po śledzenie ruchu obywateli. Podobnie w świecie web developmentu, różne narzędzia służą do różnych celów monitorowania.
OpenTelemetry to zestaw API, bibliotek i narzędzi do zbierania danych telemetrycznych (metryk, logów i trace'ów) z aplikacji.
1// instrumentation.ts
2export async function register() {
3 if (process.env.NEXT_RUNTIME === 'nodejs') {
4 // Dynamiczny import, aby uniknąć problemów podczas budowania aplikacji
5 const { registerOTel } = await import('./monitoring/otel');
6 registerOTel();
7 }
8}
9
10// monitoring/otel.ts
11import * as opentelemetry from '@opentelemetry/sdk-node';
12import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
13import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
14
15export function registerOTel() {
16 const sdk = new opentelemetry.NodeSDK({
17 traceExporter: new OTLPTraceExporter({
18 url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
19 }),
20 instrumentations: [getNodeAutoInstrumentations()],
21 });
22
23 sdk.start();
24 console.log('OpenTelemetry został zainicjalizowany');
25}Sentry to popularna platforma do monitorowania błędów, która pozwala na śledzenie, priorytetyzację i naprawę błędów w czasie rzeczywistym.
1// instrumentation.ts
2export async function register() {
3 if (process.env.NEXT_RUNTIME === 'nodejs') {
4 const { initSentry } = await import('./monitoring/sentry');
5 initSentry();
6 }
7}
8
9// monitoring/sentry.ts
10import * as Sentry from '@sentry/nextjs';
11
12export function initSentry() {
13 Sentry.init({
14 dsn: process.env.SENTRY_DSN,
15 environment: process.env.NODE_ENV,
16 tracesSampleRate: 1.0,
17 });
18
19 console.log('Sentry został zainicjalizowany');
20}Możesz także zaimplementować własne rozwiązanie do zbierania danych analitycznych:
1// instrumentation.ts
2export async function register() {
3 if (process.env.NEXT_RUNTIME === 'nodejs') {
4 const { initAnalytics } = await import('./monitoring/analytics');
5 initAnalytics();
6 }
7}
8
9// monitoring/analytics.ts
10import { NextRequest } from 'next/server';
11
12// Middleware do zbierania danych analitycznych
13export function analyticsMiddleware(req: NextRequest) {
14 const start = Date.now();
15
16 // Po zakończeniu przetwarzania żądania
17 const responseTime = Date.now() - start;
18
19 // Zapisz dane o wydajności
20 console.log(`Ścieżka: ${req.nextUrl.pathname}, Czas: ${responseTime}ms`);
21
22 // W rzeczywistej aplikacji, wysłałbyś te dane do systemu analitycznego
23}
24
25export function initAnalytics() {
26 console.log('System analityczny Metropolii Quantum został zainicjalizowany');
27}Instrumentacja nie ogranicza się tylko do serwera. W klienckich komponentach możesz korzystać z różnych narzędzi do monitorowania doświadczenia użytkownika i wydajności aplikacji.
React Profiler to wbudowane narzędzie React do mierzenia czasu renderowania komponentów. Możesz go użyć do identyfikacji wąskich gardeł wydajnościowych w swojej aplikacji.
1// components/PerformanceWrapper.tsx
2"use client";
3
4import { Profiler, ProfilerOnRenderCallback, ReactNode } from 'react';
5
6interface PerformanceWrapperProps {
7 id: string;
8 children: ReactNode;
9}
10
11export function PerformanceWrapper({ id, children }: PerformanceWrapperProps) {
12 const handleRender: ProfilerOnRenderCallback = (
13 id, // id komponentu, który został zrenderowany
14 phase, // "mount" lub "update"
15 actualDuration, // czas spędzony na renderowaniu
16 baseDuration, // szacowany czas renderowania bez optymalizacji
17 startTime, // kiedy React zaczął renderowanie
18 commitTime // kiedy React zakończył renderowanie
19 ) => {
20 // Zapisz dane o wydajności
21 console.log(`[Profiler] ${id} - ${phase}: ${actualDuration.toFixed(2)}ms`);
22
23 // W produkcji, wysłałbyś te dane do systemu analitycznego
24 if (process.env.NODE_ENV === 'production') {
25 // sendToAnalytics({ id, phase, actualDuration, baseDuration });
26 }
27 };
28
29 return (
30 <Profiler id={id} onRender={handleRender}>
31 {children}
32 </Profiler>
33 );
34}Teraz możesz owinąć dowolny komponent w
PerformanceWrapper, aby mierzyć jego wydajność:1// app/dashboard/page.tsx
2"use client";
3
4import { PerformanceWrapper } from '@/components/PerformanceWrapper';
5import { DashboardContent } from '@/components/DashboardContent';
6
7export default function DashboardPage() {
8 return (
9 <PerformanceWrapper id="dashboard-page">
10 <DashboardContent />
11 </PerformanceWrapper>
12 );
13}Web Vitals to inicjatywa Google mająca na celu zapewnienie jednolitych wskazówek dotyczących wskaźników jakości, które są niezbędne dla zapewnienia doskonałego wrażenia użytkownika w sieci.
Next.js 15 umożliwia łatwe raportowanie Web Vitals:
1// app/layout.tsx
2"use client";
3
4import { useReportWebVitals } from 'next/web-vitals';
5
6export function WebVitalsReporter() {
7 useReportWebVitals((metric) => {
8 const { id, name, label, value } = metric;
9
10 // Zapisz dane Web Vitals
11 console.log(`[Web Vitals] ${name} (${label}): ${value}`);
12
13 // W produkcji, wysłałbyś te dane do systemu analitycznego
14 if (process.env.NODE_ENV === 'production') {
15 // sendToAnalytics({ id, name, label, value });
16 }
17 });
18
19 return null;
20}
21
22export default function RootLayout({ children }) {
23 return (
24 <html lang="pl">
25 <body>
26 <WebVitalsReporter />
27 {children}
28 </body>
29 </html>
30 );
31}W Metropolii Quantum, inżynierowie używają zaawansowanych narzędzi diagnostycznych, aby identyfikować i naprawiać problemy w systemach miejskich. Podobnie, deweloperzy Next.js mają dostęp do szeregu narzędzi, które ułatwiają debugowanie aplikacji.
Najprostszym sposobem debugowania na serwerze jest dodanie logów:
1// app/api/users/route.ts
2export async function GET() {
3 console.log('Rozpoczynam pobieranie użytkowników...');
4 try {
5 const users = await fetchUsers();
6 console.log(`Pobrano ${users.length} użytkowników`);
7 return Response.json(users);
8 } catch (error) {
9 console.error('Błąd podczas pobierania użytkowników:', error);
10 return Response.json({ error: 'Internal Server Error' }, { status: 500 });
11 }
12}Logi te będą widoczne w konsoli serwera, gdzie uruchomiona jest aplikacja Next.js.
Next.js obsługuje wbudowany debugger Node.js. Aby go uruchomić, wykonaj:
1NODE_OPTIONS='--inspect' next devNastępnie otwórz Chrome i przejdź do
chrome://inspect, gdzie będziesz mógł się podłączyć do procesu Node.js i użyć narzędzi deweloperskich Chrome do debugowania.Możesz także dodać breakpointy w kodzie za pomocą instrukcji
debugger:1// app/api/data/route.ts
2export async function GET() {
3 debugger; // Zatrzyma wykonanie gdy podłączony jest debugger
4 const data = await processData();
5 return Response.json(data);
6}React Developer Tools to rozszerzenie przeglądarki, które pozwala na inspekcję drzewa komponentów React, monitorowanie props, state i hooks.
Aby efektywnie debugować za pomocą React Developer Tools:
Szczególnie użyteczne przy debugowaniu Server i Client Components jest zwrócenie uwagi na ikony przy komponentach:
1// components/UserProfile.tsx
2"use client";
3
4import { useState, useEffect } from 'react';
5
6export default function UserProfile({ userId }) {
7 const [user, setUser] = useState(null);
8 const [loading, setLoading] = useState(true);
9 const [error, setError] = useState(null);
10
11 useEffect(() => {
12 async function fetchUser() {
13 try {
14 const response = await fetch(`/api/users/${userId}`);
15 if (!response.ok) throw new Error('Failed to fetch user');
16 const data = await response.json();
17 setUser(data);
18 } catch (err) {
19 setError(err.message);
20 } finally {
21 setLoading(false);
22 }
23 }
24
25 fetchUser();
26 }, [userId]);
27
28 if (loading) return <div>Loading user data...</div>;
29 if (error) return <div>Error: {error}</div>;
30 if (!user) return <div>No user found</div>;
31
32 return (
33 <div>
34 <h1>{user.name}</h1>
35 <p>{user.email}</p>
36 </div>
37 );
38}W React DevTools możesz monitorować zmiany stanów
user, loading i error w czasie rzeczywistym.Server Actions to nowa funkcja w Next.js 15, która pozwala na wykonywanie kodu na serwerze z komponentów klienckich. Debugowanie ich wymaga specjalnego podejścia:
1// app/actions.ts
2"use server";
3
4import { revalidatePath } from 'next/cache';
5
6export async function updateUserProfile(formData: FormData) {
7 const userId = formData.get('userId');
8 const name = formData.get('name');
9 const email = formData.get('email');
10
11 console.log(`Aktualizacja profilu dla użytkownika ${userId}:`, { name, email });
12
13 try {
14 // Logika aktualizacji profilu
15 const result = await updateUserInDatabase(userId, { name, email });
16 console.log('Rezultat aktualizacji:', result);
17
18 // Odświeżenie ścieżki, aby pokazać zaktualizowane dane
19 revalidatePath(`/users/${userId}`);
20
21 return { success: true };
22 } catch (error) {
23 console.error('Błąd podczas aktualizacji profilu:', error);
24 return { success: false, error: error.message };
25 }
26}Debugowanie Server Actions polega głównie na:
Next.js 15 zawiera kilka wbudowanych narzędzi, które ułatwiają debugowanie:
Next.js 15 wyświetla szczegółowe komunikaty błędów w interfejsie deweloperskim, wskazując dokładnie, gdzie wystąpił problem i sugerując rozwiązania.
React Refresh pozwala na zachowanie stanu komponentów podczas wprowadzania zmian w kodzie, co znacznie ułatwia debugowanie i iteracyjny rozwój.
Next.js 15 wprowadza wbudowane narzędzia deweloperskie, które dostarczają informacji o wydajności, załadowanych modułach, komponentach i trasach.
Aby włączyć Next.js DevTools, dodaj flagę do swojego
next.config.js:1// next.config.js
2/** @type {import('next').NextConfig} */
3const nextConfig = {
4 experimental: {
5 instrumentationHook: true,
6 webVitalsAttribution: ['CLS', 'LCP'],
7 },
8};
9
10module.exports = nextConfig;W Metropolii Quantum, inżynierowie nieustannie monitorują wydajność wszystkich systemów, aby zapewnić optymalne doświadczenie mieszkańcom. W świecie Next.js, monitorowanie wydajności jest równie ważne dla zapewnienia dobrego doświadczenia użytkownikom.
Next.js oferuje wbudowane narzędzie do monitorowania Web Vitals, które można zintegrować z narzędziem analitycznym:
1// pages/_app.js (dla Pages Router) lub app/layout.js (dla App Router)
2export function reportWebVitals(metric) {
3 const { id, name, label, value } = metric;
4
5 // Przykład: wysyłanie metryk do Google Analytics
6 ga('send', 'event', {
7 eventCategory: 'Web Vitals',
8 eventAction: name,
9 eventValue: Math.round(name === 'CLS' ? value * 1000 : value), // Wartości CLS są zazwyczaj małe
10 eventLabel: id,
11 nonInteraction: true,
12 });
13}Możesz także zaimplementować własne monitorowanie wydajności, wykorzystując Performance API:
1// lib/performance.ts
2export function measurePageLoad() {
3 if (typeof window !== 'undefined' && window.performance) {
4 const performanceEntries = performance.getEntriesByType('navigation');
5
6 if (performanceEntries.length > 0) {
7 const navigationEntry = performanceEntries[0] as PerformanceNavigationTiming;
8
9 const metrics = {
10 // Czas od rozpoczęcia nawigacji do zakończenia ładowania DOM
11 domComplete: navigationEntry.domComplete,
12
13 // Czas od rozpoczęcia nawigacji do pełnego załadowania strony
14 loadComplete: navigationEntry.loadEventEnd,
15
16 // Czas od rozpoczęcia nawigacji do pierwszego renderowania
17 firstPaint: performance.getEntriesByName('first-paint')[0]?.startTime || 0,
18
19 // Czas od rozpoczęcia nawigacji do pierwszego renderowania treści
20 firstContentfulPaint: performance.getEntriesByName('first-contentful-paint')[0]?.startTime || 0,
21 };
22
23 console.log('Performance Metrics:', metrics);
24
25 // W produkcji, wysłałbyś te dane do systemu analitycznego
26 if (process.env.NODE_ENV === 'production') {
27 // sendToAnalytics(metrics);
28 }
29 }
30 }
31}Funkcję tę możesz wywołać w komponencie klienckim, na przykład:
1// components/PerformanceMonitor.tsx
2"use client";
3
4import { useEffect } from 'react';
5import { measurePageLoad } from '@/lib/performance';
6
7export function PerformanceMonitor() {
8 useEffect(() => {
9 // Mierz wydajność po załadowaniu strony
10 if (document.readyState === 'complete') {
11 measurePageLoad();
12 } else {
13 window.addEventListener('load', measurePageLoad);
14 return () => window.removeEventListener('load', measurePageLoad);
15 }
16 }, []);
17
18 return null; // Komponent nie renderuje nic widocznego
19}Jednym z najbardziej zaawansowanych aspektów Next.js 15 jest system Server i Client Components. Powoduje to jednak nowe wyzwania dotyczące debugowania.
1// app/dashboard/page.tsx
2export default function Dashboard() {
3 // BŁĄD: Nie można używać hooków w Server Components
4 const [count, setCount] = useState(0);
5
6 return <div>Dashboard</div>;
7}Rozwiązanie: Przenieś logikę stanu do Client Component.
1// app/dashboard/page.tsx
2import { DashboardClient } from './dashboard-client';
3
4export default function Dashboard() {
5 // Server Component
6 return <DashboardClient />;
7}
8
9// dashboard-client.tsx
10"use client";
11
12import { useState } from 'react';
13
14export function DashboardClient() {
15 // Teraz możemy użyć hooka React
16 const [count, setCount] = useState(0);
17
18 return <div>Dashboard Count: {count}</div>;
19}1// app/dashboard/page.tsx
2export default function Dashboard() {
3 // BŁĄD: Nie można uzyskać dostępu do window w Server Component
4 const windowWidth = typeof window !== 'undefined' ? window.innerWidth : 0;
5
6 return <div>Width: {windowWidth}</div>;
7}Rozwiązanie: Przenieś kod używający API przeglądarki do Client Component.
1// app/dashboard/page.tsx
2import { WindowSizeClient } from './window-size-client';
3
4export default function Dashboard() {
5 return <WindowSizeClient />;
6}
7
8// window-size-client.tsx
9"use client";
10
11import { useState, useEffect } from 'react';
12
13export function WindowSizeClient() {
14 const [windowWidth, setWindowWidth] = useState(0);
15
16 useEffect(() => {
17 setWindowWidth(window.innerWidth);
18
19 const handleResize = () => setWindowWidth(window.innerWidth);
20 window.addEventListener('resize', handleResize);
21 return () => window.removeEventListener('resize', handleResize);
22 }, []);
23
24 return <div>Width: {windowWidth}</div>;
25}1// BŁĄD: Nie można bezpośrednio importować Server Component do Client Component
2// components/dashboard-wrapper.tsx
3"use client";
4
5import { ServerDataFetcher } from './server-data-fetcher';
6
7export function DashboardWrapper() {
8 return (
9 <div className="dashboard">
10 <ServerDataFetcher /> {/* To nie zadziała */}
11 </div>
12 );
13}Rozwiązanie: Przekazuj Server Components jako props do Client Components.
1// app/dashboard/page.tsx
2import { DashboardWrapper } from '@/components/dashboard-wrapper';
3import { ServerDataFetcher } from '@/components/server-data-fetcher';
4
5export default function Dashboard() {
6 return (
7 <DashboardWrapper>
8 <ServerDataFetcher /> {/* Przekazanie jako children */}
9 </DashboardWrapper>
10 );
11}
12
13// components/dashboard-wrapper.tsx
14"use client";
15
16export function DashboardWrapper({ children }) {
17 return (
18 <div className="dashboard">
19 {children}
20 </div>
21 );
22}
23
24// components/server-data-fetcher.tsx
25// Server Component
26export async function ServerDataFetcher() {
27 const data = await fetchData();
28 return <div>{data}</div>;
29}W Metropolii Quantum, centralne systemy monitorowania zbierają dane z tysięcy czujników rozmieszczonych po całym mieście, tworząc pełny obraz stanu miejskiej infrastruktury. W świecie aplikacji webowych, podobne narzędzia zewnętrzne pomagają monitorować produkcyjne wdrożenia.
Jeśli hostujesz swoją aplikację na Vercel (twórcy Next.js), możesz skorzystać z Vercel Analytics:
1npm install @vercel/analytics
2# lub
3yarn add @vercel/analytics1// app/layout.tsx
2import { Analytics } from '@vercel/analytics/react';
3
4export default function RootLayout({ children }) {
5 return (
6 <html>
7 <body>
8 {children}
9 <Analytics />
10 </body>
11 </html>
12 );
13}New Relic to kompleksowe narzędzie do monitorowania aplikacji, które pozwala na śledzenie wydajności, błędów i zachowania użytkowników.
1npm install newrelic
2# lub
3yarn add newrelicNastępnie utwórz plik
newrelic.js w głównym katalogu projektu:1// newrelic.js
2'use strict';
3
4exports.config = {
5 app_name: ['Quantum Voyages - Next.js'],
6 license_key: process.env.NEW_RELIC_LICENSE_KEY,
7 logging: {
8 level: 'info'
9 },
10 allow_all_headers: true,
11 attributes: {
12 exclude: [
13 'request.headers.cookie',
14 'request.headers.authorization',
15 'request.headers.proxyAuthorization',
16 'request.headers.setCookie*',
17 'request.headers.x*',
18 'response.headers.cookie',
19 'response.headers.authorization',
20 'response.headers.proxyAuthorization',
21 'response.headers.setCookie*',
22 'response.headers.x*'
23 ]
24 }
25};Datadog to platforma monitorująca chmurę, która zapewnia monitorowanie serwerów, baz danych, narzędzi i usług poprzez platformę analityczną danych.
1npm install @datadog/browser-rum
2# lub
3yarn add @datadog/browser-rum1// app/datadog-rum.tsx
2"use client";
3
4import { useEffect } from 'react';
5import { datadogRum } from '@datadog/browser-rum';
6
7export function DatadogRUM() {
8 useEffect(() => {
9 if (process.env.NODE_ENV === 'production') {
10 datadogRum.init({
11 applicationId: process.env.NEXT_PUBLIC_DATADOG_APPLICATION_ID,
12 clientToken: process.env.NEXT_PUBLIC_DATADOG_CLIENT_TOKEN,
13 site: 'datadoghq.eu', // lub 'datadoghq.com' zależnie od regionu
14 service: 'quantum-voyages',
15 env: process.env.NODE_ENV,
16 version: '1.0.0',
17 sessionSampleRate: 100,
18 sessionReplaySampleRate: 100,
19 trackUserInteractions: true,
20 trackResources: true,
21 trackLongTasks: true,
22 defaultPrivacyLevel: 'mask-user-input'
23 });
24 }
25 }, []);
26
27 return null;
28}Następnie dodaj komponent do layoutu:
1// app/layout.tsx
2import { DatadogRUM } from './datadog-rum';
3
4export default function RootLayout({ children }) {
5 return (
6 <html>
7 <body>
8 {children}
9 <DatadogRUM />
10 </body>
11 </html>
12 );
13}Instrumentacja i debugowanie to kluczowe aspekty rozwoju aplikacji Next.js 15, podobnie jak systemy monitorowania są niezbędne dla prawidłowego funkcjonowania Metropolii Quantum. Dzięki odpowiednim narzędziom i praktykom możesz:
Pamiętaj, że najlepszym podejściem jest wczesne włączenie instrumentacji i monitoringu w cykl rozwoju aplikacji, a nie dodawanie ich jako myśl po fakcie. Podobnie jak inżynierowie Metropolii Quantum projektują systemy monitorowania równocześnie z budową infrastruktury miejskiej, ty powinieneś implementować narzędzia do debugowania i monitorowania już na wczesnych etapach rozwoju aplikacji Next.js.
W kolejnym module omówimy zarządzanie zmiennymi środowiskowymi i konfigurację aplikacji Next.js 15, co pozwoli na bezpieczne przechowywanie wrażliwych danych i dostosowywanie zachowania aplikacji do różnych środowisk.