Доки по разработке
This project is maintained by teniryte
Ваш проект включает примеры:
src/instrumentation.ts и src/instrumentation-client.ts,next/web-vitals в WebVitals‑компоненте,15-instrumentation.Здесь собраны принципы и паттерны, как «засунуть весь проект под микроскоп»: логирование, метрики, обработка ошибок.
instrumentation.ts: глобовые хуки приложенияВ App Router Next.js позволяет описывать глобовую инструментaцию в файле:
src/instrumentation.tsКлючевые элементы:
export async function register() — вызывается при запуске:
export const onRequestError — глобовый хук ошибок запросов.Паттерн register:
export async function register() {
console.log('Instrumentation initialized');
// Пример: выполняем код только на Node.js‑рантайме
if (process.env.NEXT_RUNTIME === 'nodejs') {
const os = await import('os');
console.log('hostname', os.hostname());
}
// Здесь можно условно подключить разные модули в зависимости от рантайма
if (process.env.NEXT_RUNTIME === 'nodejs') {
// await import('./instrumentation-node');
}
if (process.env.NEXT_RUNTIME === 'edge') {
// await import('./instrumentation-edge');
}
}
Идеи:
process.env.NEXT_RUNTIME === 'nodejs' — можно использовать Node API (fs, os, process и т.п.);process.env.NEXT_RUNTIME === 'edge' — только Web‑/Edge‑совместимые API.onRequestErrorВ instrumentation.ts также определяется:
export const onRequestError = async (err: any, request: any, context: any) => {
console.log('ERROR', err, request, context);
};
Принцип: этот хук позволяет:
Типичный практический вариант:
export async function onRequestError(
error: unknown,
request: Request,
context: { route?: string },
) {
// Отправляем ошибку в систему мониторинга
// e.g. Sentry.captureException(error, { extra: { url: request.url } });
console.error('Request error:', error, 'URL:', request.url, 'Context:', context);
}
instrumentation-client.tsФайл src/instrumentation-client.ts — место для:
Простейший пример (как в проекте):
console.log('Instrumentation client initialized');
Что обычно делают здесь на практике:
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
});
Компонент WebVitals в вашем src/app/_components/WebVitals.tsx использует:
useReportWebVitals из next/web-vitals,Паттерн:
'use client';
import { useReportWebVitals } from 'next/web-vitals';
function logWebVitals(metric: any) {
console.log('METRIC', metric);
// здесь можно отправить метрику на свой backend или в аналитический сервис
}
export function WebVitals() {
useReportWebVitals(logWebVitals);
return null;
}
Использование в RootLayout:
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<WebVitals />
{children}
</body>
</html>
);
}
Какие метрики приходят:
FCP — First Contentful Paint,LCP — Largest Contentful Paint,CLS — Cumulative Layout Shift,FID / INP — время реакции,TTFB — Time to First Byte,Паттерн отправки метрик на сервер:
function logWebVitals(metric: any) {
// Пример отправки на backend
navigator.sendBeacon(
'/analytics',
JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
label: metric.label,
}),
);
}
15-instrumentationОтдельная страница‑маршрут (в вашем коде она возвращает, например, 25-instrumentation/15-instrumentation) служит:
register,WebVitals и другие метрики работают.Типичный вид:
export default function InstrumentationDemoPage() {
return <div>Instrumentation demo page</div>;
}
Можно добавить на неё:
onRequestError/Sentry),На основе ваших примеров можно сформулировать базовый чек‑лист:
instrumentation.ts для инициализации логгера;instrumentation-client.ts;window.onerror, unhandledrejection (если нужно).WebVitals в root layout;onRequestError для серверных ошибок запросов;error.tsx в маршрутах, React error boundaries).Ниже — пример того, как можно объединить всё вместе:
// src/instrumentation.ts
import * as Sentry from '@sentry/nextjs';
export async function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 1.0,
});
}
}
export async function onRequestError(
error: unknown,
request: Request,
context: { route?: string },
) {
Sentry.captureException(error, {
extra: { url: request.url, route: context.route },
});
}
// src/instrumentation-client.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 1.0,
});
// src/app/_components/WebVitals.tsx
'use client';
import { useReportWebVitals } from 'next/web-vitals';
export function WebVitals() {
useReportWebVitals((metric) => {
// Отправить на backend или в Sentry
console.log('METRIC', metric);
});
return null;
}
Этот модуль в вашем «конспекте» отвечает за всё, что связано с наблюдаемостью: как увидеть, что происходит с приложением в продакшене, и как находить проблемы ещё до того, как их заметят пользователи.