Next.js 9.0 был выпущен примерно два месяца назад. С тех пор мы выпустили 7 более мелких, но важных обновлений: 9.0.1, 9.0.2, 9.0.3, 9.0.4, 9.0.5, 9.0.6 и 9.0.7.
Давайте рассмотрим, что эти обновления привнесли в ваши сайты и приложения без каких-либо критических изменений.
- Улучшенная параллельная обработка в Windows: Процесс
next build
теперь более надежен в Windows и лучше распределяет нагрузку. - Gzip-сжатие по умолчанию: Gzip-сжатие теперь включено по умолчанию для уменьшения шагов оптимизации.
- Отчеты TypeScript только для активных страниц: Встроенная поддержка TypeScript была расширена для отслеживания изменений только на активных страницах, что сделало её быстрее и надежнее.
- Телеметрия: Поможет нам сосредоточиться на оптимизации ключевых частей Next.js и проверять эффективность изменений.
- Улучшенное отслеживание элементов
next/head
: Классnext-head
был удален, что упрощает интеграцию с инструментами проверки. - Запрет нестраничных файлов в директории pages: Улучшение безопасности приложений и времени сборки за счет предотвращения случайной публикации нестраничных файлов.
- Улучшения времени выполнения: Неиспользуемые части Next.js (например,
next/dynamic
) больше не загружаются в runtime, уменьшая размер бандлов.
Улучшенная параллельная обработка в Windows
Next.js выполняет параллельную обработку во многих местах во время процесса next build
. Основное применение — минификация выходных данных сборки с помощью Terser.
Ранее эта работа распределялась между несколькими CPU с использованием пакета worker-farm
. Однако мы заметили, что многие пользователи Windows отключали минификацию через пользовательскую конфигурацию webpack. Дальнейшее исследование показало, что worker-farm
нестабильно работает в Windows.
Для решения этой проблемы мы перешли с worker-farm
на jest-worker
. Это обеспечивает надежность сборки в macOS, Linux и Windows.
jest-worker
, как следует из названия, является частью тестового фреймворка Jest. Этот пакет хорошо протестирован, надежен и поддерживается.
jest-worker
также поддерживает worker_threads
— новую функцию в Node 12. В отличие от child_process
, worker_threads
могут совместно использовать память, что ускоряет сборку в новых версиях Node.
Благодаря переходу на jest-worker
мы смогли повторно включить параллельную сборку для пользователей Windows.
Gzip-сжатие по умолчанию
Исследуя причины использования пользовательских серверов, мы обнаружили, что чаще всего это делалось для сжатия. Компании добавляли промежуточное ПО Express под названием compression
для Gzip-сжатия HTTP-ответов.
Это промежуточное ПО уменьшает объем передаваемых данных. Обычно такое сжатие должно обрабатываться обратным прокси, например Nginx, чтобы снизить нагрузку на однопоточный процесс Node.
Однако анализ использования Next.js показал, что многие компании не настраивали сжатие.
На платформах вроде Vercel gzip
и brotli
автоматически обрабатываются на уровне прокси.
При самостоятельном хостинге компаниям приходится настраивать Gzip вручную (через compression
или обратный прокси).
Начиная с Next.js 9.0.4, gzip
-сжатие включено по умолчанию при использовании next start
или пользовательского server.js
.
Поддержка brotli
скоро появится, так как Node.js теперь поддерживает Brotli нативно.
Если сжатие уже настроено в вашем приложении через пользовательский сервер, Next.js не будет добавлять свой компрессор.
Next.js не включает сжатие для serverless-целевой платформы по умолчанию, так как ассеты загружаются отдельно и не обслуживаются через Node.js.
Если вы развертываете на платформе с поддержкой сжатия, например Vercel, изменения не требуются.
Отчеты TypeScript только для активных страниц
Next.js 9 включает встроенную поддержку TypeScript. Достаточно переименовать страницу из .js
в .tsx
, и Next.js автоматически выполнит или подскажет оставшиеся настройки.
Next.js также выполняет проверку типов, запуская tsc --watch
параллельно с процессом разработки. Во время разработки Next.js использует концепцию on-demand entries, компилируя только активные страницы.
Поток on-demand entries
Начиная с версии 9.0.4, Next.js теперь сообщает об ошибках типов только для страниц, активно компилируемых через on-demand entries. Это уменьшает количество лишних сообщений при работе с конкретными страницами.
Полная проверка типов приложения по-прежнему выполняется во время next build
или может быть обработана в вашем редакторе.
Телеметрия
Next.js был выпущен почти 3 года назад, и за это время фреймворк значительно вырос — от новых функций до улучшенных настроек по умолчанию.
До сих пор процесс улучшений был в основном ручным.
У Vercel есть несколько крупных приложений на Next.js, например vercel.com, vercel.com/docs и https://nextjs.org. Мы активно используем Next.js внутри Vercel (dogfooding) и улучшаем его на основе нашего опыта.
Кроме того, мы собираем отзывы сообщества. Возможно, вы уже общались с Тимом, чтобы поделиться опытом использования Next.js в вашей компании.
Например, если вы используете пользовательский сервер, настраиваете webpack и т. д. Эти отзывы крайне важны для развития Next.js.
Однако у этого подхода есть проблема: мы можем собирать отзывы только от части пользователей, чьи потребности могут отличаться от ваших или вашей компании.
Например, импорт CSS-файлов — нестандартный подход, но многие пользователи используют его через next-css
(или Sass/Less) или пользовательскую конфигурацию. Зная процент таких пользователей, мы можем расставить приоритеты в улучшениях.
Поэтому мы ввели анонимный автоматизированный сбор отзывов, чтобы улучшать Next.js ещё эффективнее.
Это также позволит нам проверять, действительно ли изменения улучшают работу приложений.
Подробнее о телеметрии можно узнать на nextjs.org/telemetry. Там же вы найдете инструкции по отказу от участия, если это необходимо.
Индикатор прогресса сборки
Общаясь с пользователями Next.js, мы получили небольшой отзыв: иногда казалось, что next build
ничего не делает (визуально).
Чтобы решить это, мы добавили индикатор загрузки в вывод консоли во время next build
. Теперь процесс сборки визуально отображается, и понятно, что он не завис.
Мы планируем расширить этот вывод, чтобы показывать больше этапов сборки.
Новый индикатор прогресса сборки
Улучшенное отслеживание элементов next/head
Next.js предоставляет встроенный способ управления элементами <head>
, так как отвечает за рендеринг HTML вашего приложения. Этот API доступен через модуль next/head
.
Например, для добавления заголовка страницы:
import Head from 'next/head';
export default function MyPage() {
return (
<>
<Head>
<title>Мой заголовок</title>
</Head>
<h1>Привет, мир</h1>
</>
);
}
При рендеринге HTML Next.js собирает все компоненты внутри <Head>
и добавляет их в <head>
страницы.
Однако Next.js поддерживает переходы между страницами (SPA) через компонент <Link>
.
При клике на <Link>
Next.js загружает необходимый JavaScript для рендеринга страницы на стороне клиента. Затем отображается соответствующий React-компонент.
Поскольку этот переход происходит на клиенте, нужно очистить элементы <head>
, добавленные предыдущей страницей, чтобы избежать устаревших элементов.
Раньше Next.js отслеживал эти элементы через класс next-head
:
<head>
<title class="next-head">Мой заголовок</title>
</head>
Это работало хорошо, так как все элементы из next/head
были помечены и легко удалялись.
Однако некоторые пользователи сообщали, что дополнительный атрибут class
мешал валидации скриптов из внешних сервисов.
Джеральд Монако из команды Google Chrome предложил решение, сохраняющее очистку без классов.
Теперь Next.js добавляет <meta>
-тег с количеством элементов из next/head
. Это позволяет очищать элементы без классов.
В результате уменьшается размер начального HTML при множественных элементах в <head>
.
Запрет нестраничных файлов в директории pages
При начале работы с Next.js первым шагом является создание директории pages
.
Согласно соглашению, каждый файл в pages
становится маршрутом приложения. Например, pages/about.js
становится /about
.
Со временем мы получали сообщения о плохой производительности сборки в некоторых приложениях.
Выяснилось, что пользователи размещали всю структуру компонентов в pages
.
Поскольку каждый файл в pages
считается страницей, все компоненты компилировались как страницы, создавая избыточную нагрузку и генерируя лишние JavaScript-файлы.
Кроме того, это влияло на код-сплиттинг, так как Next.js использует эвристики для распределения библиотек между страницами.
Поэтому мы решили предотвратить эту проблему.
Next.js 9 теперь проверяет, что файлы в pages
экспортируют React-компонент.
Если обнаруживается нестраничный файл, Next.js предупреждает пользователя и предлагает переместить его в другую директорию.
Это ускоряет разработку, сборку и делает код-сплиттинг точнее.
Улучшения времени выполнения
Фреймворк Next.js состоит из многих частей, включая клиентский runtime. Этот runtime отвечает за гидратацию, клиентскую маршрутизацию и другое.
Гидратация делает серверный или предварительно отрендеренный HTML интерактивным, добавляя обработчики событий и вызывая методы жизненного цикла, такие как useEffect()
или componentDidMount
.
Кроме того, Next.js обрабатывает не только базовую гидратацию — например, настраивает клиентский роутер, next/head
и загружает дополнительную логику через next/dynamic
.
Каждая из этих функций имеет свой собственный runtime.
В случае next/dynamic
Next.js должен убедиться, что лениво загружаемые компоненты, отрендеренные на сервере, готовы на клиенте. Каждое использование next/dynamic
создает дополнительный JavaScript-бандл, который должен загрузиться до гидратации.
Раньше этот runtime всегда включался в основной бандл Next.js. Теперь он загружается только при использовании next/dynamic
в приложении. Это уменьшает объем загружаемого, парсимого и выполняемого JavaScript для приложений без next/dynamic
.
Поддержка AppTree
Некоторые библиотеки экосистемы React реализуют серверный рендеринг особым образом. Например, решение для SSR от Apollo под названием getDataFromTree
рендерит React-дерево, ожидает результаты Query
и повторяет рендеринг.
По умолчанию Next.js добавляет контекстные значения в React-дерево, например, роутер, доступный через useRouter
.
Раньше пример with-apollo
рендерил React-дерево через <App>
с ручным заполнением пропсов. С появлением React Context это стало невозможным, так как провайдер контекста — отдельный элемент.
Начиная с Next.js 9.0.4, в контекст getInitialProps
добавлено новое свойство AppTree
. Оно предназначено для случаев, когда внешние библиотеки должны обходить всё React-дерево, как в getDataFromTree
от Apollo.
Пример with-apollo
обновлен в соответствии с изменениями. Если вы уже используете Apollo, рекомендуется перейти на подход с AppTree
, чтобы useRouter
и другие будущие API работали корректно.
Если вы не используете Apollo или подобные библиотеки, мы рекомендуем избегать AppTree
, так как обход React-дерева снижает производительность из-за многократного рендеринга.
Удаление пакета next-server
Когда мы начали оптимизировать Next.js для бессерверных развертываний более года назад, мы создали пакет под названием next-server
. Этот пакет был экспериментальным и публиковался вместе с пакетом next
. Он никогда не документировался публично, но был экспериментом по созданию максимально компактной серверной среды выполнения Next.js.
В итоге пакет оказался успешным и действительно уменьшил размер серверной среды выполнения в production. Однако мы нашли инновационный способ сделать среду выполнения еще компактнее с помощью компилятора Next.js и статического анализа.
В результате next-server
стал устаревшим и был заменен на цель serverless
. Эта цель дает гораздо более оптимизированный вывод по сравнению с использованием пакета next-server
в качестве замены next
.
Хотя этот пакет устарел и не мог использоваться напрямую, мы оставили его. Причина в том, что он содержал внутренние компоненты, общие для нескольких пакетов, и перемещение кода потребовало бы значительных усилий.
Недавно мы приложили эти усилия и перенесли код из next-server
обратно в пакет next
. Теперь весь код фреймворка Next.js находится в одном пакете next
.
Это упрощает вклад в развитие Next.js как для новичков, так и для опытных участников. Теперь используется единый процесс компиляции и унифицированная конфигурация сборки. Раньше были отдельные настройки для next
и next-server
, а также произвольные ограничения на то, какой код должен находиться в каждом пакете.
Обновление Next.js
Если ваш проект работает на старой версии Next.js, мы рекомендуем обновиться до Next.js 9.
В большинстве случаев для обновления не требуется вносить изменения. Вы можете следовать руководству по обновлению, чтобы обеспечить плавный процесс обновления.
Мы благодарим всех участников сообщества, которые обновляли руководство с момента его выпуска.
Что ждет в будущем?
Новые оптимизации, описанные в этом посте, — это только начало более масштабных оптимизаций и функций, над которыми мы работаем.
Очень скоро мы поделим обновлениями по текущим RFC. А пока вы можете заглянуть в раздел RFC на GitHub.
Там представлены некоторые функции, которые мы исследуем, такие как встроенная поддержка CSS, поддержка директории public
и поддержка директории src
.
Сообщество
Мы рады видеть постоянный рост сообщества Next.js.
- Более 800 участников внесли хотя бы один коммит.
- На GitHub проект получил более 41 100 звезд.
Сообщество Next.js удвоилось с момента последнего крупного релиза и насчитывает более 10 900 участников. Присоединяйтесь!
Мы рады постоянному вкладу сообщества и внешним отзывам от компаний и пользователей, которые помогают формировать релизы.