Next.js 15.3: Turbopack в продакшне, instrumentation-client.ts и навигационные хуки, которые решают реальные боли

nextjsturbopackreactjavascriptfrontendwebdevperformancehooksrouting

Turbopack Builds (alpha)

Исправление главного недостатка (в моем представлении) turbopack - теперь он доступен и и в production

Раньше не было смысла держать два разных бандлера: один для dev, другой для боевого окружения. С версии 15.3 всё меняется: появилась альфа-команда

next build --turbopack

Команда nextjs пока что не рекомендует использовать это для критически важных приложений, но для новых проектов я уже перехожу на него сам и советую задуматься о миграции. Это действительно ускоряет сборку, уменьшает размер бандла и повышает производительность.

Добавлен новый файл instrumentation-client.js|ts

Он позволяет выполнять скрипты ДО того, как начнёт выполняться код веб-приложения. Его необходимо располагать в root папке проекта или app/pages директориях.

Основные кейсы: интеграци инструментов мониторинга или логирования для приложения. Например, Vercel OpenTelemetry:

import { registerOTel } from '@vercel/otel'

export function register() {
	registerOTel('next-app')
}

Так как данный файл вызывается во всех средах исполнения, можно указать, какие файлы в какой среде будут исполнены:

export async function register() {
	if (process.env.NEXT_RUNTIME === 'nodejs') {
		await import('./instrumentation-node')
	}

	if (process.env.NEXT_RUNTIME === 'edge') {
		await import('./instrumentation-edge')
	}
}

Новые навигационные хуки onNavigate и useLinkStatus

Их цель - увеличить возможности контроля за роутингом и побочными эффектами на стороне клиента.

onNavigate - новый пропс для компонента <Link> из next/link, очень похож на onClick, но не срабатывает на:

  • на Ctrl/Cmd + Click
  • внешние URLs
  • ссылки с атрибутом download

Можно отменять навигацию при помощи e.preventDefault()

Рекомендуется использовать для событий, которые должны происходить на стороне реальной сессии клиента: анимации, защита навигации, аналитика.

Как пример: блокирование перехода на другую страницу, если пользователь не сохранил данные, введенные в форме:

'use client' import Link from 'next/link'
import { useNavigationBlocker } from '../contexts/navigation-blocker'

interface CustomLinkProps extends React.ComponentProps<typeof Link> { children: React.ReactNode }

export function CustomLink({ children, ...props }: CustomLinkProps) {
	const { isBlocked } = useNavigationBlocker()

	return (
		<Link onNavigate={(e) => {
			if (
				isBlocked &&
				!window.confirm('You have unsaved changes. Leave anyway?')
			) {
				e.preventDefault()
				}
			}}
			{...props}>
			{children}
		</Link> ) }

useLinkStatus Хук, возвращающий { pending } для локальных индикаторов загрузки при переходах между страницами. Сделан по образцу useFormStatus из React. Есть несколько условий для правильной работы хука:

  • компонент с useLinkStatus должен располагаться внутри компонента <Link>
  • prefetching отключен или уже выполняется, что означает блокировку навигации
  • роут назначения динамический и не содержит loading.js, из-за которого навигация была бы моментальной
  • не поддерживается в pages router

Пример с кастомной ссылкой:

import Link, { LinkProps } from "next/link";
import LoadingIndicator from "./loading-indicator";

const CustomLinkWithLoader = (props: LinkProps & { children: React.ReactNode }) => {
  return <Link {...props}>
    {props.children}
    <LoadingIndicator />
  </Link>
}

export default CustomLinkWithLoader;

'use client' import { useLinkStatus } from 'next/link'
export default function LoadingIndicator() {
	const { pending } = useLinkStatus()

	return pending ? (
		<div role="status" aria-label="Loading" className='loader' /> )
		: null
}

Я уже добавил нововведение с useLinkStatus в свой проект, вместо лоадера рядом с сылкой я добавляю тонкий прогресс-бар сверху страницы - UX заметно лучше.

Есть и другие мелкие изменения, с ними можно ознакомиться на официальной странице обновления Nextjs 15.3, перейдя по ссылкам в ПРы с изменениями.

Итог

Обновление получилось полезным и некоторые фичи уже начал использовать на своих проектах, особенно порадовали Turbopack для продакшн и хук useLinkStatus.