Сегодня мы рады представить Next.js 9.5 с новыми возможностями:
- Стабильная инкрементная статическая регенерация: пересборка статических страниц после деплоя за миллисекунды
- Настраиваемый базовый путь: размещение Next.js проектов в подкаталогах домена
- Поддержка перезаписей, редиректов и заголовков: перезапись URL, перенаправление старых URL и добавление заголовков к статическим страницам
- Опциональный слеш в URL: единообразное применение или отсутствие завершающего слеша
- Постоянное кэширование бандлов страниц: неизмененные JavaScript-файлы страниц теперь сохраняются между сборками
- Улучшения Fast Refresh: повышение надежности live-редактирования в Next.js
- Профилирование React в продакшене: новый флаг для измерения "стоимости" рендеринга вашего проекта
- Опциональные catch-all маршруты: динамические маршруты теперь обеспечивают большую гибкость для SEO-кейсов
- Поддержка Webpack 5 (бета): опциональное подключение Webpack 5 для уменьшения размера сборки и ускорения сборки
Стабильная инкрементная статическая регенерация
Next.js представил методы генерации статических сайтов в версии 9.3 с четкой целью: получить преимущества статики (всегда быстро, всегда онлайн, глобально реплицируемо), но с отличной поддержкой динамических данных, за которую Next.js известен.
Чтобы получить лучшее из обоих миров, Next.js представил Инкрементную статическую генерацию, обновляющую статический контент после сборки сайта. Используя опцию fallback: true
в getStaticPaths
, вы можете регистрировать новые статические страницы во время выполнения.
Таким образом Next.js может предварительно рендерить неограниченное количество страниц по требованию, независимо от размера вашего набора данных.
Сегодня мы объявляем о стабильной доступности Инкрементной статической регенерации — механизма обновления существующих страниц путем их фонового перерендеринга при поступлении трафика.
Вдохновленный stale-while-revalidate, фоновый перерендеринг гарантирует бесперебойную работу трафика, всегда обслуживаемого из статического хранилища, а новая версия страницы публикуется только после завершения генерации.
export async function getStaticProps() {
return {
props: await getDataFromCMS(),
// мы попытаемся регенерировать страницу:
// - при поступлении запроса
// - максимум раз в секунду
revalidate: 1,
};
}
Параметр revalidate указывает количество секунд, в течение которых произойдет не более одной генерации, чтобы предотвратить проблему "толпы" кэша.
В отличие от традиционного SSR, инкрементная статическая регенерация сохраняет преимущества статики:
- Нет скачков задержки. Страницы обслуживаются стабильно быстро.
- Страницы никогда не выходят из строя. Если фоновая регенерация не удалась, старая страница остается без изменений.
- Низкая нагрузка на базу данных и бэкенд. Страницы пересчитываются не более одного раза одновременно.
Обе инкрементные функции (добавление страниц и их ленивое обновление), а также режим предпросмотра, теперь стабильны и полностью поддерживаются как next start
, так и платформой Vercel edge из коробки.
Чтобы продемонстрировать эту функцию, мы создали пример, показывающий регенерацию статической страницы с количеством реакций GitHub к определенному issue: https://reactions-demo.vercel.app/
После первого посещения после нашей реакции с эмодзи запускается фоновая генерация новой страницы. Каждый запрос обслуживается из статического кэша.
Далее мы работаем над дополнительным RFC для реализации двух возможностей инкрементной статической генерации:
- Регенерация и инвалидация нескольких страниц одновременно (например, индекс блога и определенный пост)
- Регенерация по событиям (например, вебхукам CMS) до поступления пользовательского трафика
Подробнее см. документацию getStaticProps
.
Настраиваемый базовый путь
Next.js проекты не всегда размещаются в корне домена. Иногда может потребоваться разместить Next.js проект в подкаталоге, например /docs
, чтобы проект покрывал только этот раздел домена.
Хотя это было возможно и раньше, требовалась дополнительная конфигурация. Например, добавление префикса к каждому <Link>
и обеспечение правильного пути для JavaScript-бандлов Next.js.
Для решения этой проблемы мы представляем новую опцию конфигурации basePath
, которая позволяет легко размещать Next.js проект в подкаталоге домена.
Чтобы начать использовать basePath
, добавьте его в next.config.js
:
module.exports = {
basePath: '/docs',
};
После настройки basePath
ваш проект автоматически будет обслуживаться из указанного пути. В данном случае /docs
.
При ссылках на другие страницы проекта с помощью next/link
или next/router
префикс basePath
добавляется автоматически. Это позволяет изменять basePath
без изменения проекта.
Пример использования next/link
для перехода на другую страницу:
import Link from 'next/link';
export default function HomePage() {
return (
<>
<Link href="/documentation-page">
<a>Documentation page</a>
</Link>
</>
);
}
Использование next/link
таким образом приведет к следующему HTML в браузере:
<a href="/docs/documentation-page">Documentation page</a>
Подробнее см. документацию basePath
.
Поддержка перезаписей, редиректов и заголовков
Перезаписи
При создании Next.js проекта может потребоваться проксирование определенных маршрутов на другой URL. Например, при постепенном переходе на Next.js вы можете направить существующие страницы в Next.js проект, а все остальное — в старый проект.
В Next.js 9.5 мы представляем новую опцию конфигурации rewrites
, которая позволяет сопоставить входящий путь запроса с другим целевым путем, включая внешние URL.
Например, можно перенаправить определенный маршрут на example.com
:
module.exports = {
async rewrites() {
return [
{ source: '/backend/:path*', destination: 'https://example.com/:path*' },
];
},
};
В этом случае все пути под /backend
будут перенаправлены на example.com
.
Вы также можете проверить соответствие маршрутов Next.js проекта и затем перенаправить на старый проект при отсутствии совпадения. Это особенно полезно для постепенного перехода на Next.js:
module.exports = {
async rewrites() {
return [
// сначала проверяем соответствие маршрутов Next.js
{
source: '/:path*',
destination: '/:path*',
},
{
source: '/:path*',
destination: `https://example.com/:path*`,
},
];
},
};
В этом случае сначала проверяются все пути. Если совпадений нет, происходит перенаправление на example.com
(старый проект).
Подробнее о функции rewrites
см. документацию.
Редиректы
Большинству сайтов требуются редиректы, особенно при изменении структуры маршрутов. Например, при переходе с /blog
на /news
.
Раньше для настройки редиректов в Next.js требовался кастомный сервер или страница _error
для проверки редиректов. Однако это лишало преимуществ статической оптимизации или было неудобно.
Начиная с Next.js 9.5 вы можете создавать список редиректов в next.config.js
с помощью ключа redirects
:
module.exports = {
async redirects() {
return [
{
source: '/about',
destination: '/',
permanent: true,
},
];
},
};
Подробнее о функции redirects
см. документацию.
Заголовки (Headers)
Next.js позволяет создавать гибридные проекты, использующие как статическую генерацию (Static Generation), так и рендеринг на стороне сервера (SSR). При использовании рендеринга на стороне сервера вы можете устанавливать заголовки для входящих запросов. Для статических страниц установка заголовков ранее была невозможна.
Теперь мы добавили свойство headers
в next.config.js
, которое применяется ко всем маршрутам Next.js:
module.exports = {
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'Feature-Policy',
// Отключаем микрофон и геолокацию
value: "microphone 'none'; geolocation 'none'",
},
],
},
];
},
};
Опция headers
позволяет устанавливать часто используемые заголовки, такие как Feature-Policy
и Content-Security-Policy
.
Чтобы узнать больше о функции headers
, ознакомьтесь с документацией по заголовкам.
Опциональный завершающий слеш в URL-адресах (Optional Trailing Slash in URLs)
Когда Next.js был представлен 3 года назад, его поведение по умолчанию заключалось в том, что все URL-адреса с завершающим слешем всегда возвращали страницу 404.
Хотя это было эффективно, некоторые пользователи просили возможность изменить это поведение. Например, при миграции существующего проекта на Next.js, где ранее всегда требовался завершающий слеш.
В Next.js 9.5 мы добавили новую опцию trailingSlash
в next.config.js
.
Эта новая опция гарантирует, что Next.js автоматически обрабатывает поведение завершающего слеша:
- Автоматически перенаправляет URL-адреса с завершающим слешем на URL-адрес без слеша, например:
/about/
на/about
- Когда
trailingSlash
установлен вtrue
, URL-адрес без завершающего слеша будет перенаправлен на URL-адрес со слешем, например:/about
на/about/
- Гарантирует, что
next/link
автоматически добавляет/удаляет завершающий слеш, чтобы избежать ненужных перенаправлений.
module.exports = {
// Принудительно добавлять завершающий слеш, по умолчанию слеш отсутствует (false)
trailingSlash: true,
};
Чтобы узнать больше о функции trailingSlash
, ознакомьтесь с документацией по trailingSlash.
Постоянное кэширование для сборок страниц (Persistent Caching for Page Bundles)
При создании страниц в Next.js генерация всех скриптовых сборок, CSS-стилей и HTML полностью автоматизирована и скрыта от вас. Если вы посмотрите на сгенерированные теги <script>
до Next.js 9.5, вы заметите, что их URL-адреса следуют такому шаблону:
/_next/static/ovgxWYrvKyjnlM15qtz7h/pages/about.js
Сегмент пути ovgxWYrvKyjnlM15qtz7h
выше — это то, что мы называли идентификатором сборки (build ID). Хотя эти файлы легко кэшировались на стороне клиента и на сервере, после пересборки приложения идентификатор сборки менялся, и все кэши сбрасывались.
Для большинства проектов такой компромисс был приемлем, однако мы хотели оптимизировать это поведение, чтобы больше не инвалидировать кэш браузера для страниц, которые не изменились.
Введение улучшенной стратегии разделения кода в Next.js 9.2, разработанной совместно с командой Google Chrome, заложило основу для этих улучшений в генерации сборок страниц Next.js.
Начиная с Next.js 9.5 все JavaScript-сборки страниц будут использовать хэши содержимого вместо идентификатора сборки. Это позволяет страницам, которые не изменились между деплоями, оставаться в кэше браузера и на сервере без необходимости повторной загрузки.
После этих изменений шаблон URL-адреса выглядит примерно так:
/_next/static/chunks/pages/about.qzfS4o5gIEXRME6sTEahL.js
Вместо глобального идентификатора сборки часть qzfS4o5gIEXRME6sTEahL
представляет собой детерминированный хэш сборки about.js
, который будет стабильным, пока код этого раздела вашего сайта не изменится. Кроме того, теперь он кэшируется на долгий срок между деплоями благодаря Cache-Control: public,max-age=31536000,immutable
, который Next.js устанавливает автоматически.
Улучшения Fast Refresh
Мы представили Fast Refresh в Next.js 9.4 — новый опыт горячей перезагрузки, который дает мгновенную обратную связь при редактировании React-компонентов.
Next.js 9.5 дополнительно улучшает нашу реализацию Fast Refresh и предоставляет инструменты для успешной работы:
- Понятные ошибки: Все ошибки компиляции и выполнения были обновлены, чтобы показывать только релевантную информацию, включая фрагмент кода, который вызвал ошибку.
- Советы по сохранению состояния компонентов: Next.js теперь предоставляет полезные советы, чтобы гарантировать, что Fast Refresh сохранит состояние ваших компонентов в максимально возможном количестве сценариев. Каждый совет Next.js полностью применим и сопровождается примерами "до" и "после"!
- Предупреждения при сбросе состояния компонента: Теперь мы будем выводить подробное предупреждение, когда Next.js не может сохранить состояние компонента после редактирования файла. Это предупреждение поможет вам диагностировать, почему проект сбросил состояние компонента, и исправить это, чтобы полностью использовать потенциал Fast Refresh.
- Новая документация: Мы добавили подробную документацию, которая объясняет, что такое Fast Refresh, как он работает и чего ожидать! Документация также научит вас лучше использовать Fast Refresh, объясняя, как работает восстановление после ошибок.
- Руководство по устранению неполадок: Новая документация также включает общие шаги по устранению неполадок и советы о том, как максимально эффективно использовать Fast Refresh в разработке.
Профилирование React в продакшене (Production React Profiling)
React представил Profiler API некоторое время назад, который позволяет отслеживать проблемы производительности в ваших React-компонентах. Хотя эта функция работает автоматически в режиме разработки, для профилирования в продакшене требуется отдельная версия ReactDOM.
В Next.js 9.5 вы теперь можете включить профилирование React в продакшене с помощью флага --profile
в next build
:
next build --profile
После этого вы можете использовать профилировщик так же, как и в режиме разработки.
Чтобы узнать больше о профилировании React, вы можете прочитать пост о React Profiler от команды React. Особая благодарность TODOrTotev и @darshkpatel за вклад в эту функцию.
Опциональные catch-all маршруты (Optional Catch All Routes)
Next.js 9.2 добавил поддержку catch-all динамических маршрутов, которые широко используются сообществом для различных сценариев. Catch-all маршруты дают гибкость для создания высокодинамичных структур маршрутизации, работающих с Headless CMS, GraphQL API, файловой системой и т. д.
Учитывая обратную связь, мы услышали, что пользователи хотят еще больше гибкости для совпадения с корневым уровнем маршрута. Сегодня мы рады представить опциональные catch-all динамические маршруты для таких продвинутых сценариев.
Чтобы создать опциональный catch-all маршрут, вы можете создать страницу, используя синтаксис [[...slug]]
.
Например, pages/blog/[[...slug]].js
будет соответствовать /blog
, а также любому маршруту под ним, например: /blog/a
, /blog/a/b/c
и т. д.
Как и в случае с catch-all маршрутами, slug
будет предоставлен в объекте запроса роутера в виде массива частей пути. Так, для пути /blog/foo/bar
объект запроса будет { slug: ['foo', 'bar'] }
. Для пути /blog
объект запроса не будет содержать ключ slug: { }
.
Вы можете узнать больше об опциональных catch-all маршрутах в нашей документации.
Поддержка Webpack 5 (бета)
Webpack 5 в настоящее время находится в бета-версии. Он включает несколько значительных улучшений:
- Улучшенное Tree-Shaking: Вложенные экспорты, внутренние модули и CommonJS теперь подвергаются tree-shaking
- Постоянное кэширование (Persistent Caching): Позволяет повторно использовать результаты предыдущих сборок
- Детерминированные идентификаторы чанков и модулей: Решает проблему изменения идентификаторов модулей webpack между сборками
Мы рады объявить о бета-доступности webpack 5 для Next.js.
Чтобы попробовать webpack 5, вы можете использовать Yarn resolutions в вашем package.json
:
{
"resolutions": {
"webpack": "^5.0.0-beta.30"
}
}
Бета-версия Webpack 5 уже развернута в продакшене на nextjs.org и vercel.com. Мы рекомендуем попробовать ее постепенно и поделиться своими наблюдениями на GitHub.
Улучшения инфраструктуры компиляции
Для поддержки webpack 5 мы переписали большую часть конвейера компиляции, чтобы он лучше соответствовал Next.js:
- Next.js больше не зависит от
webpack-hot-middleware
иwebpack-dev-middleware
, вместо этого мы теперь используем webpack напрямую и оптимизируем его специально для проектов Next.js. Это приводит к более простой архитектуре и более быстрой компиляции в режиме разработки. - On-demand-entries — система Next.js, которая позволяет компилировать только те страницы, которые вы посещаете в данный момент во время разработки, также была переписана и теперь стала еще надежнее благодаря новому поведению webpack, специально адаптированному под наш сценарий использования.
- React Fast Refresh и Next.js Error Overlay теперь полностью совместимы с webpack 5
- Дисковое кэширование будет включено в будущей бета-версии.
Обратная совместимость
Мы всегда стремимся гарантировать, что Next.js остается обратно совместимым с предыдущими версиями.
Webpack 4 продолжит полностью поддерживаться. Мы тесно сотрудничаем с командой webpack, чтобы обеспечить максимально плавный переход с webpack 4 на 5.
Если ваш проект Next.js не имеет пользовательской конфигурации webpack, никаких изменений в проекте не потребуется для полного использования webpack 5.
Важно: если ваш проект имеет пользовательскую конфигурацию webpack, могут потребоваться некоторые изменения для перехода на webpack 5. Рекомендуем следить за нашими инструкциями по миграции или минимизировать использование расширений webpack для беспроблемных обновлений в будущем.
Улучшенное отслеживание файлов на macOS
Недавно мы обнаружили проблему в webpack, когда отслеживание файлов на macOS прекращалось после нескольких изменений в коде. Приходилось вручную перезапускать проект, чтобы увидеть обновления. После нескольких изменений цикл повторялся.
Более того, мы обнаружили, что эта проблема возникает не только в проектах Next.js, но и во всех проектах и фреймворках, построенных на основе webpack.
После нескольких дней отладки мы нашли коренную причину в реализации отслеживания файлов, которую использует webpack, — chokidar, широко используемую в экосистеме Node.js.
Мы отправили исправление в chokidar для устранения проблемы. После выпуска исправления мы работали с Tobias Koppers, чтобы внедрить его в новую версию webpack.
Эта исправленная версия webpack автоматически используется при обновлении до Next.js 9.5.
Заключение
Мы рады видеть продолжающийся рост популярности Next.js:
- У нас было более 1,200 независимых участников, из них более 135 новых участников с момента релиза 9.4.
- На GitHub проект получил более 51,100 звезд.
Присоединяйтесь к сообществу Next.js на GitHub Discussions. Discussions — это пространство сообщества, где вы можете общаться с другими пользователями Next.js, свободно задавать вопросы или делиться своей работой.
Например, вы можете начать с публикации URL вашего проекта.
Если вы хотите внести вклад, но не знаете как, мы рекомендуем попробовать экспериментальные функции, такие как поддержка Webpack, и поделиться своими наблюдениями!
Благодарности
Мы благодарим наше сообщество, включая все внешние отзывы и вклады, которые помогли сформировать этот релиз.
Особая благодарность Jan Potoms, давнему участнику сообщества Next.js, который внес вклад в несколько функций этого релиза.
Особая благодарность Tobias Koppers, автору webpack, который помог реализовать поддержку webpack 5 в Next.js.
Этот релиз стал возможен благодаря вкладу: @chandan-reddy-k, @Timer, @aralroca, @artemisart, @sospedra, @prateekbh, @Prioe, @Janpot, @merceyz, @ijjk, @PavelK27, @marbiano, @MichelleLucero, @thorsten-stripe, @TODOrTotev, @Skn0tt, @lfades, @timneutkens, @akhila-ariyachandra, @chibicode, @rafaelalmeidatk, @kirill-konshin, @jamesvidler, @JeffersonBledsoe, @tylev, @jamesmosier, @filipemarins, @Remeic, @vvo, @timothyis, @jazibsawar, @coetry, @adam-zacharski, @danwilliams, @tywmick, @matamatanot, @goldins, @mvllow, @its-tayo, @sshyam-gupta, @wilbert-abreu, @sebastianbenz, @jaydenseric, @developit, @dylanjha, @darshkpatel, @spinks, @stefanprobst, @moh12594, @jasonmerino, @cristiand391, @HyunSangHan, @mcsdevv, @M1ck0, @hydRAnger, @alexej-d, @valmassoi, @motleydev, @eKhattak, @jpedroschmitz, @JerryGoyal, @bowen31337, @phillip055, @balazsorban44, @chuabingquan, @youhosi, @andresz1, @bell-steven, @areai51, @Wssn, @ndom91, @anthonyshort, @zxzl, @jbowes, @IamLizu, @PascalPixel, @ralphilius, @ysun62, @muslax, @elsigh, @AsherFoster, @botv, @tomdohnal, @christianalfoni, @tomasztunik, @gsimone, @illuminist, @jplew, @OskarKaminski, @RickyAbell, @steph-query, @ericgoe, @MalvinJay, @cristianbote, @Ashikpaul, @jensmeindertsma, @amorriscode, @abhik-b, @awareness481, @LukasPolak, @arvigeus, @romMidnight, @jackyef, @drumm2k, @kuldeepkeshwar, @bogy0, @Belco90, @wawjr3d, @tanmaylaud, @SarKurd, @kevinsproles, @dstotijn, @styfle, @blackwright, @BrunoBernardino, @heyAyushh, @Necmttn, @TrySound, @obedparla, @NyashaNziramasanga, @tonyspiro, @kukicado, @ceorourke, @MehediH, @robintom, @karlhorky и @tcK1!