BackНазад к блогу

Next.js 9

Next.js 9 включает поддержку TypeScript, динамическую маршрутизацию, API-маршруты, автоматическую статическую оптимизацию и многое другое!

После 70 канареечных релизов мы рады представить Next.js 9 с такими возможностями:

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

Terminal
npm i next@latest react@latest react-dom@latest

Лишь в редких случаях могут потребоваться изменения в коде. Подробнее см. руководство по обновлению.

С момента последнего релиза такие компании, как IGN, Bang & Olufsen, Intercom, Buffer и Ferrari, запустили проекты на Next.js. Больше примеров в шоукейсе!

Встроенная поддержка TypeScript без конфигурации

Год назад в Next.js 6 появилась базовая поддержка TypeScript через плагин @zeit/next-typescript. Пользователям также приходилось настраивать .babelrc и включать его в next.config.js.

После настройки плагин позволял собирать файлы .ts и .tsx в Next.js. Однако проверка типов не была интегрирована, а типы не предоставлялись ядром Next.js. Это означало, что пакет сообщества приходилось поддерживать отдельно в DefinitelyTyped, что могло рассинхронизироваться с релизами.

Общаясь с пользователями, новыми и существующими, мы поняли, что большинство очень заинтересованы в использовании TypeScript. Им нужно было более надежное и стандартное решение для простой интеграции TypeScript в существующую или новую кодовую базу.

По этой причине мы решили интегрировать поддержку TypeScript в ядро Next.js, улучшив опыт разработчиков и ускорив процесс.

Автоматическая настройка

Начать использовать TypeScript в Next.js просто: переименуйте любой файл, страницу или компонент с .js на .tsx. Затем запустите next dev!

Next.js обнаружит использование TypeScript в вашем проекте. CLI Next.js проведет вас через установку необходимых типов для React и Node.js.

Next.js также создаст стандартный tsconfig.json с разумными настройками, если его еще нет. Этот файл позволяет интегрировать проверку типов в редакторах, таких как Visual Studio Code.

Автоматическая настройка TypeScript в Next.js 9

Интегрированная проверка типов

Next.js проверяет типы как в разработке, так и при сборке для продакшена.

В режиме разработки Next.js покажет ошибки типов после сохранения файла. Проверка типов происходит в фоне, позволяя мгновенно взаимодействовать с обновленным приложением в браузере. Ошибки типов будут отображаться в браузере по мере их обнаружения.

Проверка типов в разработке в Next.js 9

Next.js также автоматически завершит сборку для продакшена (т.е. next build) с ошибкой, если обнаружатся проблемы с типами. Это помогает предотвратить попадание некорректного кода в продакшен.

Проверка типов при сборке в Next.js 9

Проверка типов при сборке в Next.js 9

Ядро Next.js написано на TypeScript

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

Например, при импорте next/link редакторы с поддержкой TypeScript покажут допустимые свойства и принимаемые значения.

Типы ядра Next.js

Типы ядра Next.js

Динамические сегменты маршрутов

Динамическая маршрутизация (также известная как URL-слаг или "чистые" URL) была одним из первых запросов на GitHub после релиза Next.js 2,5 года назад!

Проблема была "решена" в Next.js 2.0 введением API кастомного сервера для программного использования Next.js. Это позволило использовать Next.js как движок рендеринга, реализуя абстракции и сопоставление входящих URL для отображения определенных страниц.

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

Однако кастомный сервер имеет свои недостатки: маршрутизация обрабатывается на уровне сервера, а не прокси; он развертывается и масштабируется как монолит; подвержен проблемам производительности.

Поскольку кастомный сервер требует доступности всего приложения в одном экземпляре, его сложно развернуть в Serverless-среде, которая решает эти проблемы. Serverless-запросы маршрутизируются на уровне прокси и выполняются/масштабируются независимо, избегая узких мест производительности.

Кроме того, мы уверены, что можем предложить лучший опыт разработки! Магия Next.js начинается, когда вы создаете файл pages/blog.js и внезапно получаете страницу, доступную по /blog.

Зачем пользователю создавать собственный сервер и изучать программный API Next.js для поддержки маршрута типа /blog/my-first-post (/blog/:id)?

Основываясь на этом отзыве и видении, мы начали исследовать решения для сопоставления маршрутов, ориентируясь на то, что пользователи уже знали: директорию pages/.

Создание страницы с динамическим маршрутом

Next.js поддерживает создание маршрутов с базовыми именованными параметрами — паттерн, популяризированный path-to-regexp (библиотека, используемая в Express).

Создать страницу, соответствующую маршруту /post/:pid, теперь можно, создав файл в директории pages с именем: pages/post/[pid].js!

Next.js автоматически сопоставит запросы типа /post/1, /post/hello-nextjs и т.д. и отрендерит страницу, определенную в pages/post/[pid].js. Соответствующий сегмент URL будет передан как параметр запроса на вашу страницу с именем, указанным в [квадратных-скобках].

Например: для следующей страницы и запроса /post/hello-nextjs объект query будет { pid: 'hello-nextjs' }:

static async getInitialProps({ query }) {
  // pid = 'hello-nextjs'
  const { pid } = query
 
  const postContent = await fetch(
    `https://api.example.com/post/${encodeURIComponent(pid)}`
  ).then(r => r.text())
 
  return { postContent }
}

Также поддерживаются множественные динамические сегменты URL!

Синтаксис [param] работает для имен директорий и файлов, то есть следующие примеры корректны:

./pages/blog/[blogId]/comments/[commentId].js
./pages/posts/[pid]/index.js

Вы можете узнать больше об этой возможности в документации Next.js или разделе Next.js Learn.

Автоматическая статическая оптимизация

Next.js добавил поддержку генерации статических сайтов в v3, выпущенном примерно два года назад. В то время это была самая запрашиваемая функция.

И не зря: нельзя отрицать, что статические сайты быстры! Они не требуют вычислений на стороне сервера и могут быть мгновенно доставлены пользователю из CDN.

Однако выбор между серверным рендерингом и статической генерацией был бинарным: либо SSR, либо статическая генерация. Не было золотой середины.

В реальности у приложений могут быть разные требования. Эти требования требуют разных стратегий рендеринга и компромиссов.

Например, главная страница и маркетинговые страницы обычно содержат статический контент и отлично подходят для статической оптимизации.

С другой стороны, панель управления продуктом может выиграть от серверного рендеринга, где данные часто обновляются.

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

Начиная с Next.js 9, пользователям больше не нужно выбирать между полным серверным рендерингом или статическим экспортом приложения. Вы получаете лучшее из обоих миров для каждой страницы.

Автоматический частичный статический экспорт

Был введен эвристический метод для автоматического определения, может ли страница быть пререндерена в статический HTML.

Это определение основано на наличии или отсутствии блокирующих требований к данным через использование getInitialProps.

Эта эвристика позволяет Next.js создавать гибридные приложения, содержащие как серверно-рендеренные, так и статически сгенерированные страницы.

Встроенный сервер Next.js (next start) и программный API (app.getRequestHandler()) поддерживают этот вывод сборки прозрачно. Не требуется никакой дополнительной конфигурации или обработки.

Статически сгенерированные страницы остаются реактивными: Next.js гидратирует ваше приложение на стороне клиента для полной интерактивности.

Кроме того, Next.js обновит ваше приложение после гидратации, если страница зависит от параметров запроса в URL.

Next.js визуально информирует вас во время разработки, будет ли страница статически сгенерирована. Этот индикатор можно скрыть, кликнув по нему.

Индикатор статической оптимизации в Next.js

Индикатор статической оптимизации в Next.js

Статически сгенерированные страницы также отображаются в выводе сборки Next.js:

Индикатор типа сборки в Next.js

Индикатор типа сборки в Next.js

API-маршруты

Во многих случаях при создании React-приложений вам в конечном итоге нужен какой-то бэкенд. Либо для получения данных из базы данных, либо для обработки данных, предоставленных пользователями (например, контактная форма).

Мы обнаружили, что многие пользователи, которым нужен был бэкенд, создавали API с помощью кастомного сервера. При этом они сталкивались с рядом проблем. Например, Next.js не компилирует код кастомного сервера, что означает, что нельзя использовать import/export или TypeScript.

По этой причине многие пользователи реализовывали собственный процесс компиляции поверх кастомного сервера. Хотя это решало их задачу, такой подход чреват множеством подводных камней: например, при неправильной настройке tree shaking отключалось для всего приложения.

Это подняло вопрос: что, если мы перенесем опыт разработки, который предоставляет Next.js, на создание бэкенд-API?

Сегодня мы рады представить API-маршруты — лучший в своем классе опыт разработки от Next.js для создания вашего бэкенда.

Чтобы начать использовать API-маршруты, создайте директорию api/ внутри pages/.

Любой файл в этой директории будет автоматически сопоставлен с /api/<ваш-маршрут>, аналогично тому, как другие файлы страниц сопоставляются с маршрутами.

Например, pages/api/contact.js будет сопоставлен с /api/contact.

Примечание: API-маршруты также поддерживают динамическую маршрутизацию!

Все файлы в директории pages/api/ экспортируют функцию-обработчик запроса вместо React-компонента:

export default function handle(req, res) {
  res.end('Hello World');
}

Обычно API-эндпоинты принимают входящие данные, например, строку запроса, тело запроса или куки, и отвечают другими данными.

Исследуя добавление поддержки API-маршрутов в Next.js, мы заметили, что во многих случаях пользователи не использовали объекты запроса и ответа Node.js напрямую. Вместо этого они использовали абстракции, предоставляемые серверными библиотеками, такими как Express.

Причина в том, что во многих случаях входящие данные — это какой-то текст, который сначала нужно разобрать, чтобы он стал полезным. Эти серверные библиотеки помогают снять бремя ручного разбора данных, чаще всего через middleware. Наиболее часто используемые предоставляют разбор строки запроса, тела и куки, но все равно требуют некоторой настройки для начала работы.

API-маршруты в Next.js будут предоставлять эти middleware по умолчанию, чтобы вы могли сразу продуктивно создавать API-эндпоинты:

export default function handle(req, res) {
  console.log(req.body); // Тело запроса
  console.log(req.query); // Строка запроса URL
  console.log(req.cookies); // Переданные куки
  res.end('Hello World');
}

Помимо использования входящих данных, ваш API-эндпоинт обычно также возвращает данные. Чаще всего это JSON. Next.js предоставляет res.json() по умолчанию для удобной отправки данных:

export default function handle(req, res) {
  res.json({ title: 'Hello World' });
}

При внесении изменений в API-эндпоинты в режиме разработки код автоматически перезагружается, поэтому нет необходимости перезапускать сервер.

Оптимизации для продакшена

Next.js 9 будет автоматически префетчить компоненты <Link>, когда они появляются в области видимости.

Эта функция улучшает отзывчивость вашего приложения, ускоряя переходы на новые страницы.

Next.js использует Intersection Observer для префетчинга необходимых ресурсов в фоне.

Эти запросы имеют низкий приоритет и уступают fetch() или XHR-запросам. Next.js не будет автоматически префетчить, если у пользователя включен режим экономии данных.

Вы можете отключить эту функцию для редко посещаемых страниц, установив свойство prefetch в false:

<Link href="/terms" prefetch={false}>
  <a>Terms of Service</a>
</Link>

Оптимизированный AMP по умолчанию

Начиная с Next.js 9, AMP-страницы (как AMP-first, так и гибридные) теперь рендерятся в оптимизированном виде по умолчанию.

Хотя AMP-страницы остаются опциональными, Next.js автоматически оптимизирует их вывод. Эти оптимизации могут ускорить рендеринг до 50%!

Это стало возможным благодаря работе Себастьяна Бенца (Sebastian Benz) над AMP Optimizer.

Устранение мёртвого кода для веток typeof window

В Next.js 9 выражение typeof window заменяется на соответствующее значение (undefined или object) во время сборки на сервере и клиенте. Это позволяет Next.js автоматически удалять мёртвый код из продакшен-сборки вашего приложения.

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

Улучшения для разработчиков

Индикатор компиляции

В версиях до 9-й единственным способом узнать, что произойдёт горячая замена кода (и что инструментарий Next.js выполняет работу), было наблюдение за консолью разработчика.

Однако часто разработчики смотрят на результат рендеринга, из-за чего сложно понять, продолжает ли Next.js компиляцию. Например, при внесении малозаметных изменений в стили страницы не сразу ясно, были ли они обновлены.

По этой причине мы создали RFC / "good first issue" для обсуждения возможных решений проблемы индикации выполняемой работы.

Мы получили отзывы от многих дизайнеров и инженеров в рамках RFC, включая их предпочтения и возможные направления дизайна индикатора.

Рафаэль Алмейда (Rafael Almeida) воспользовался этой возможностью для сотрудничества с нашей командой и реализовал новый индикатор, который теперь доступен по умолчанию в Next.js 9.

Теперь при выполнении компиляции в Next.js в правом нижнем углу страницы появляется небольшой треугольник!

Индикатор компиляции Next.js

Вывод в консоли

Раньше при внесении изменений в режиме разработки Next.js показывал индикатор компиляции с заполняющимися полосами загрузки и постоянно очищал экран.

Это вызывало некоторые проблемы. В частности, очищались выводы консоли как из кода приложения (например, console.log в компонентах), так и при использовании внешних инструментов, таких как Vercel CLI или docker-compose.

Начиная с Next.js 9, вывод в консоли стал менее "прыгающим" и больше не очищает экран. Это улучшает общий опыт, так как в терминале остаётся больше релевантной информации, меньше мерцания, а Next.js лучше интегрируется с используемыми инструментами.

Вывод в консоли Next.js

Особая благодарность Джастину Чейзу (Justin Chase) за сотрудничество по очистке вывода.

Статистика сборки

Теперь при сборке приложения для продакшена с помощью next build вы получаете детальный обзор всех собранных страниц.

Каждая страница автоматически получает несколько статистических данных.

Наиболее заметный — размер бандла. По мере роста приложения растут и JavaScript-бандлы, и эта статистика поможет отслеживать их увеличение. В будущем вы также сможете устанавливать бюджеты производительности (performance budgets) для страниц, при превышении которых сборка будет завершаться ошибкой.

Размер страниц Next.js после сборки

Размер страниц Next.js после сборки

Помимо размеров бандлов, мы также показываем, сколько компонентов проекта и node_modules используется на каждой странице. Это даёт представление о сложности страницы.

Количество пакетов на странице Next.js

Количество пакетов на странице Next.js

Каждая страница также указывает, является ли она статически оптимизированной или рендерится на стороне сервера, так как поведение страниц может различаться.

Тип страницы Next.js после сборки

Тип страницы Next.js после сборки

Объект конфигурации для каждой страницы

Теперь каждая страница может экспортировать объект конфигурации. Изначально эта конфигурация позволяет включить AMP, но в будущем вы сможете настраивать и другие параметры для конкретных страниц.

pages/about.js
export const config = { amp: true };
 
export default function AboutPage(props) {
  return <h3>Моя AMP-страница "О нас"!</h3>;
}

Для гибридного AMP-рендеринга можно использовать значение 'hybrid':

pages/about.js
import { useAmp } from 'next/amp';
 
export const config = { amp: 'hybrid' };
 
export default function AboutPage(props) {
  const isAmp = useAmp();
  return <h3>Моя страница "О нас"!{isAmp ? <> На базе AMP!</> : ''}</h3>;
}

Компонент высшего порядка withAmp был удалён в пользу этой новой конфигурации.

Мы предоставили codemod, который автоматически преобразует использование withAmp в новый объект конфигурации. Подробнее об этом можно прочитать в руководстве по обновлению.

Улучшения кодовой базы

Мы внесли изменения в наш инструментарий, чтобы улучшить опыт разработки и обеспечить стабильность по мере роста кодовой базы.

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

Next.js уже имел обширный набор интеграционных тестов, включающий 50+ приложений Next.js с тестами для них. Эти тесты гарантируют, что при выпуске новой версии обновление проходит гладко, так как все ранее доступные функции проверяются тем же набором тестов.

Большинство наших тестов — интеграционные, так как во многих случаях они имитируют "реальных" разработчиков, использующих Next.js в разработке. Например, у нас есть тесты, имитирующие внесение изменений в приложение Next.js для проверки работы горячей замены модулей.

Наши интеграционные тесты в основном основаны на Selenium WebDriver в сочетании с chromedriver для тестирования в headless Chrome. Однако со временем возникали проблемы в других браузерах, особенно в старых, таких как Internet Explorer 11.

Благодаря использованию Selenium мы смогли автоматически запускать тесты в нескольких браузерах.

Сейчас наш набор тестов выполняется в Chrome, Firefox, Safari и Internet Explorer 11.

Сотрудничество с Google Chrome

Команда Google Chrome работает над улучшением Next.js, внося предложения через RFC и pull-request'ы.

Цель этого сотрудничества — масштабные улучшения производительности, сосредоточенные на размерах бандлов, времени загрузки и гидратации.

Например, эти изменения улучшат опыт как небольших сайтов, так и крупных приложений, таких как Hulu, Twitch и Deliveroo.

Module / Nomodule

Первая область внимания — отправка современного JavaScript в браузеры, которые его поддерживают.

Например, сейчас Next.js должен предоставлять полифиллы для синтаксиса async/await, так как код может выполняться в браузерах, которые не поддерживают async/await, что приведёт к ошибке.

RFC по сотрудничеству Module/Nomodule в Next.js

RFC по сотрудничеству Module/Nomodule в Next.js

Чтобы избежать ошибок в старых браузерах и при этом отправлять современный JavaScript поддерживающим его браузерам, Next.js будет использовать шаблон module/nomodule. Этот шаблон предоставляет надёжный механизм для отправки современного JavaScript современным браузерам, позволяя старым браузерам использовать полифиллы ES5.

RFC для module/nomodule в Next.js можно найти здесь.

Улучшенное разделение бандлов

Текущая стратегия разделения бандлов в Next.js основана на эвристике по соотношению для включения модулей в единый "общий" чанк. Из-за низкой гранулярности (так как есть только один бандл) код либо загружается избыточно (так как общий чанк может включать код, не требуемый для конкретного маршрута), либо дублируется в нескольких бандлах страниц.

RFC по сотрудничеству по разделению бандлов в Next.js

RFC по сотрудничеству по разделению бандлов в Next.js

RFC по улучшенному разделению бандлов можно найти здесь.

Другие улучшения

Команда Chrome также работает над множеством других оптимизаций и изменений, которые улучшат Next.js. RFC для них будут опубликованы в ближайшее время.

Эти RFC и pull-request'ы помечены меткой "Collaboration", чтобы их можно было легко найти в трекере проблем Next.js.

Сообщество

Мы рады видеть продолжающийся рост сообщества Next.js.

В этом релизе более 65 авторов pull-request'ов внесли улучшения в ядро или примеры.

Говоря о примерах, мы теперь предоставляем более 200 примеров интеграции Next.js с различными библиотеками и технологиями! Включая большинство css-in-js и библиотек для получения данных.

  • У нас более 720 участников, внесших хотя бы один коммит.
  • На GitHub проект получил более 38,600 звёзд.
  • Было отправлено более 3,400 pull-request'ов с момента первого релиза, из них более 800 с момента последнего мажорного релиза!

Сообщество Next.js удвоилось с момента последнего мажорного релиза и насчитывает более 8,600 участников. Присоединяйтесь!

Мы благодарны нашему сообществу и всем внешним отзывам и вкладам, которые помогли сформировать этот релиз.