Привет, на связи Майя из Spectr. Сегодня я поделюсь обзором последней, пятнадцатой версии Next.js. В статье мы разберем интересные улучшения: React Compiler, улучшенные сообщения об ошибках гидрации в ‘use-client’, исправление поведения кэширования, Partial Prerendering (PPR), API next/after, обновленный дизайн create-next-app и оптимизацию бандлинга внешних пакетов.
Общее
Next.js — популярный фреймворк для создания клиентских приложений с возможностью серверного рендеринга (SSR). Он стал фаворитом среди разработчиков благодаря ряду преимуществ:
SEO-оптимизация.
Высокая скорость загрузки приложений.
Безопасность — возможность скрывать данные на сервере.
Развитое сообщество и качественная документация.
Постоянные улучшения и инновации.
В сегодняшнем обзоре мы сосредоточимся на последнем пункте — что нового появилось в последней версии Next.js 15.
Что нового в Next.js 15
Релизы 14 и 15 были направлены скорее на стабилизацию существующих функций, чем на введение кардинально новых. Это важная новость для разработчиков, так как стабильность фреймворка имеет критическое значение при использовании на коммерческих проектах.
На момент написания обзора версия Next.js 15 находится в статусе Release Candidate (RC), как и версия React 19, на которой она основана. Ожидается, что Next.js 15 станет стабильной одновременно с выходом React 19.
Итак, что нам предлагает Next.js 15?
React Compiler
React Compiler — это долгожданное улучшение. Он автоматически оптимизирует код и мемоизирует компоненты, самостоятельно определяя, где это необходимо, чтобы избежать лишних перерисовок. Это устранит одну из главных проблем разработчиков. Подключить компилятор можно через ‘next.config.js’:
const nextConfig = {
experimental: {
reactCompiler: true,
},
};
module.exports = nextConfig;
Имейте в виду, что эта опция будет работать только с 15-й версии. При переходе на Next.js 15 и подключении React Compiler, вероятно, придется строго следовать правилам ESLint, чтобы компилятор мог корректно воспринимать и оптимизировать код. Однако создатели React Compiler утверждают, что он работает с обычным JavaScript и понимает правила React, поэтому переписывать код для его использования не потребуется.
Пока React Compiler видится мощным улучшением, которое позволит ускорить и упростить разработку, а также улучшить пользовательский опыт.
Улучшенные сообщения об ошибках гидрации в ‘use-client’
Ошибки гидрации в Next.js раньше были неочевидны и сложны для диагностики. В версии 15 сообщения об ошибках стали более информативными: они будут подробно описывать проблему и прямо указывать место в коде, где произошла ошибка гидрации. Это поможет быстрее находить и устранять проблемы. Пример ошибки:
Исправление поведения кэширования
Многие разработчики сталкивались с непредсказуемым поведением кэширования запросов при использовании App Router. Начиная с Next.js 13, по умолчанию для fetch-запросов применялся флаг ‘force-cache’, что приводило к возвращению устаревших данных из кэша. Это означало, что результаты запросов сохранялись, и при следующем вызове возвращались старые данные, а не обновленные.
Разработчики обычно ожидают получать свежие данные при выполнении запросов. В версии Next.js 15 эта проблема была решена: теперь по умолчанию используется флаг ‘no-store’, который отключает кэширование и гарантирует получение актуальной информации.
Если кэширование всё же необходимо, его можно включить вручную, установив нужный флаг:
// было:
fetch("https:// …" , { cache: 'force-cache' });
// стало:
fetch("https:// …" , { cache: 'no-store' });
Возможные значения:
‘no-store’ — получать ресурс с удаленного сервера при каждом запросе и не обновлять кеш.
‘force-cache’ — получить ресурс из кеша (если он существует) или удаленного сервера и обновить кэш.
Partial Prerendering (PPR)
Эта экспериментальная функция впервые появилась в версии 14 и продолжает дорабатываться. Partial Prerendering делит страницу на сегменты, часть из которых будет сгенерирована статично, а другая — динамично. Это позволяет рендерить страницу частично статически и частично динамически, что улучшает производительность и пользовательский опыт.
import { Suspense } from "react";
import { StaticComponent, DynamicComponent } from "@/app/ui";
export const experimental_ppr = true;
export default function Page() {
return (
<>
<StaticComponent />
<Suspense fallback={...}>
<DynamicComponent />
</Suspense>
</>
);
}
Если включен частичный предварительный рендеринг (PPR), страница Page генерирует статическую оболочку на основе установленной границы <Suspense />. fallback из React Suspense предварительно визуализируется.
Резервные варианты отображения в оболочке (т. е. fallback, на месте которого обычно рисуют Skeleton или Loader) затем заменяются динамическими компонентами (<DynamicComponent />), например, такими как чтение файлов cookie для определения корзины или показ баннера на основе данных о пользователе.
Чтобы пользоваться этой функцией, нужно предварительно подключить её:
const nextConfig = {
experimental: {
ppr: 'incremental',
},
};
module.exports = nextConfig;
Более подробно идеи и применение PPR описаны здесь:
API next/after
API after() разделяет задачи на сервере на "основные" и "вторичные". Это позволяет клиенту получать ответ быстрее, так как вторичные задачи (например, логирование или аналитика) выполняются позже. Сейчас клиенту приходится ждать, пока "вторичные" задачи завершатся, прежде чем он получит ответ на запрос. Однако after()изменит этот порядок. Например, если мы хотим посмотреть видео на сайте, то по логике after() сначала загрузится интересующий нас контент, и только потом начнется выполнение аналитики и других второстепенных задач на сайте. Такой подход к приоритезации задач положительно скажется на TTFB.
TTFB (Time To First Byte) — это метрика, определяющая время, прошедшее с момента отправки HTTP-запроса до получения первого байта ответа от сервера. Этот показатель играет важную роль в достижении высоких результатов как в SEO, так и в коммерческом успехе интернет-магазинов. Сокращение времени доставки контента пользователям предоставляет значительное конкурентное преимущество, что делает Next.js 15 весьма привлекательным инструментом для коммерческой разработки.
Пример использования after():
import { unstable_after as after } from 'next/server';
import { log } from '@/app/utils';
export default function Layout({ children }) {
// Secondary task
after(() => {
log();
});
// Primary task
return <>{children}</>;
}
Чтобы функция заработала, её нужно подключить в next.config:
const nextConfig = {
experimental: {
reactCompiler: true,
},
};
module.exports = nextConfig;
Подробнее о функции можно почитать здесь:
Обновленный дизайн create-next-app
create-next-app получил обновленный минималистичный дизайн. Теперь шаблон содержит меньше ненужного кода, который раньше приходилось удалять.
Новый дизайн:
Также появилась команда npx create-next-app@rc --empty для создания практически пустого шаблона:
npx create-next-app@rc --empty
При инициализации приложения появится промпт, который будет спрашивать, включить Turbopack или нет.
Turbopack также можно включить при инициализации проекта с помощью команды:
npx create-next-app@rc --turbo
Turbopack пока находится на стадии тестирования, но уже пройдено 95,5% тестов для продакшена. Актуальное состояние бандлера можно посмотреть на сайте: https://areweturboyet.com.
Оптимизация бандлинга внешних пакетов (стабильная версия)
Теперь у разработчиков есть больше возможностей контролировать, какие пакеты попадают в бандл, что позволяет значительно уменьшить его размер.
Опция bundlePagesRouterDependencies включает автоматическое объединение зависимостей на стороне сервера для приложений, использующих Pages Router:
/** @type {import('next').NextConfig} */
const nextConfig = {
bundlePagesRouterDependencies: true,
};
module.exports = nextConfig;
Вы можете использовать опцию serverExternalPackages, чтобы отказаться от определенных пакетов, если это необходимо. Чтобы исключить пакеты из бандла используйте:
const nextConfig = {
// Automatically bundle external packages in the Pages Router:
bundlePagesRouterDependencies: true,
// Opt specific packages out of bundling for both App и Pages Router:
serverExternalPackages: ['package-name'],
};
module.exports = nextConfig;
С помощью опции transpilePackages Next.js может автоматически транспилировать и бандлить зависимости из локальных пакетов (например, монорепозиториев) или внешних зависимостей (node_modules). Это заменяет пакет next-transpile-modules.
С помощью опции transpilePackages Next.js может автоматически транспилировать и бандлить зависимости из локальных пакетов (например, из монорепозиториев) или внешних зависимостей (node_modules). Эта опция заменяет пакет next-transpile-modules:
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ['package-name'],
};
module.exports = nextConfig;
Опция optimizePackageImports позволит загружать только те модули, которые вы действительно используете:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
optimizePackageImports: ['icon-library'],
},
};
module.exports = nextConfig;
Опция serverExternalPackages позволяет исключить из объединения определенные пакеты:
/** @type {import('next').NextConfig} */
const nextConfig = {
serverExternalPackages: ['package-name'],
};
module.exports = nextConfig;
Подробнее о технологии можно почитать здесь.
Заключение
Мы рассмотрели основные обновления Next.js 15 и с нетерпением ждем выхода стабильной версии. Многие разработчики уже отмечают, что этот релиз выглядит более зрелым и проработанным по сравнению с версиями 13 и 14. Надеемся, что Next.js 15 оправдает возложенные на него ожидания и станет стимулом для многих команд перейти на новую версию, обеспечив еще более стабильную и эффективную разработку.
Полезные ссылки
Описание релиза в документации Next.js :
https://nextjs.org/blog/next-15-rc#executing-code-after-a-response-with-nextafter-experimentalСтатьи про Partial Prerendering (PPR):
https://nextjs.org/docs/app/building-your-application/rendering/partial-prerendering
https://nextjs.org/blog/next-14#partial-prerendering-preview
Статья про next/after API:
https://nextjs.org/docs/app/api-reference/functions/unstable_afterСтатья про оптимизацию бандлинга:
https://nextjs.org/docs/app/building-your-application/optimizing/package-bundling