Как Next.js вернул свою клиентскую навигацию Snappy

Фронтенд-разработчик Сэм Селикофф, который недавно присоединился к Vercel в качестве штатного инженера, задал насущный вопрос команде Next.js: почему разработчики не могут обеспечить быструю навигацию при использовании React Server Components (RSC)?

«Мне нравится DX маршрутизатора приложений, а серверные компоненты стали отличным дополнением к React, особенно для простого получения данных и их отображения на странице», — сказал он аудитории на конференции Next.js, состоявшейся 22 октября. «Я просто не понимал, почему использование RSC означало, что нам пришлось отказаться от быстрой клиентской навигации, к которой мы так привыкли в наших приложениях React. Разве не одна из причин, по которой мы любим React, — возможность запускать код прямо в браузере?»

Почему, задавался он вопросом, Next.js не может использовать RSC для первоначального рендеринга страницы и по-прежнему использовать старый добрый клиентский React для всего остального?»

Это история о том, как фреймворк ответил на его вопрос.

Интернет переходит на серверную сторону (снова)

Селикофф перенес аудиторию конференции Next.js в 2023 год, когда впервые был создан маршрутизатор приложений. В то время интерфейсные фреймворки собирали весь код на сервере, а затем отправляли его в браузер, который осуществлял выборку и маршрутизацию данных — что-то вроде приложения для iOS, — сказал он.

Но Интернет — это не iOS.

«Люди хотят иметь возможность мгновенно открывать статьи и ссылки на твиты, и именно поэтому в 2012 году команда инженеров Twitter поделилась в этом посте тем, что они сократили начальное время загрузки на 80%, перенеся большую часть клиентского рендеринга обратно на сервер», — сказал он. «Они также разделили свой код на более мелкие пакеты, чтобы можно было лениво загружать их по мере необходимости».

Это побудило фреймворки добавить такие функции, как рендеринг на стороне сервера и динамический импорт.

В 2017 году Netflix сообщил, что удалил весь клиентский React со своей целевой страницы, перенеся на сервер еще больше рендеринга и выборки данных и позволив предварительно отрендеренному HTML выполнять тяжелую работу. Netflix, по словам Селикова, добился улучшения производительности этой страницы на 50%.

«Итак, мы снова видим, что тенденция сохраняется: все больше API выполняют больше работы на сервере раньше», — сказал он.

По словам Селикоффа, когда дело дошло до навигации в одностраничных приложениях (SPA), команды, которые полагались исключительно на клиентский код для решения задач маршрутизации, также столкнулись с потолками производительности.

«В 2018 году инженеры Square написали об использовании новой функции Ember под названием «Двигатели» для разделения панелей мониторинга на разделы — это может быть отложенной загрузкой», — сказал он.

LinkedIn также перенял эту функцию движков Ember.js, поскольку огромное количество URL-адресов на их сайте вызывало проблемы с производительностью из-за загрузки всего клиента, сказал он. Remix также недавно добавил функцию, которая поможет Shopify решить ту же проблему, добавил он.

«По опыту мы знали, что подход, ориентированный на клиента, является тупиком. Вот почему маршрутизатор приложения по умолчанию выполняет выборку и маршрутизацию данных на сервере с помощью серверных компонентов».
— Сэм Селикофф, Версель

«Я говорю все это, чтобы сказать, что после десятилетнего опыта создания этих богатых интерфейсов и развития всей экосистемы фреймворка это было современное состояние», — сказал он. «У нас были эти гибридные платформы, которые в основном представляли собой SPA, ориентированные на клиента, но они продолжали добавлять серверные функции, которые вы могли использовать, когда неизбежно сталкивались с ограничениями клиента».

Войдите в маршрутизатор приложений

По словам Селикова, целью App Router было решение этих проблем на базовом уровне.

«По опыту мы знали, что клиентоориентированный подход — это тупик», — сказал он. «Вот почему App Router по умолчанию выполняет выборку и маршрутизацию данных на сервере с помощью серверных компонентов».

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

Тем не менее, Селиков хотел иметь быструю клиентскую навигацию; ему нравится, что он может открыть свой iPhone и увидеть предварительно отрендеренные экраны, сидящие и ожидающие.

«Разве мы не должны иметь эту возможность предварительной визуализации определенных экранов или предварительной загрузки предстоящих переходов клиента, чтобы мы могли обеспечить лучший пользовательский опыт?» — спросил он. «Я думаю, что нам следует. И не случайно, то же самое делает и остальная часть команды, потому что это именно то, над чем они работают».

Знакомство с компонентами кэша

Команда Cache Components разрабатывалась два года и представляет собой новый набор дополнительных функций, призванных сделать кэширование в Next.js более явным и гибким, заявила команда. Компоненты кэша, по словам Селикоффа, позволяют разработчикам выполнять предварительную визуализацию и предварительную выборку пользовательского интерфейса, что обеспечивает мгновенную навигацию к App Router.

Компоненты кэша используют новую директиву «использовать кэш», которая использует компилятор для автоматической генерации ключей кэша при его использовании. Он может развертывать страницы кэша, компоненты и функции.

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

«Если вы раньше работали над Next, вы знаете, что если вы можете сделать маршрут статическим, обычно это довольно хорошо, обычно это приводит к чрезвычайно быстрому пользовательскому интерфейсу, и это здорово», — сказал Селикофф. «За исключением сегодняшнего дня, когда вы делаете статический маршрут в Next, вы вообще не можете получить ничего динамического во время первоначального запроса. Так что это решение по принципу «все или ничего». Если вы выполняете предварительную визуализацию маршрута сегодня, вам придется предварительно выполнить предварительную визуализацию всего этого маршрута».

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

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

«Здесь мы ничего этого не делали: эта страница не является динамической или статической», — сказал он. «И то и другое».

Вместо этого он частично предварительно визуализируется, поэтому, когда компоненты кэша включены, разработчикам не приходится выбирать между статическим или динамическим, сказал Селикофф.

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

Он показал, как использовать перенос внутри саспенса для создания скелетного экрана для части пользовательского интерфейса.

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

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

Snappy Navs снова здесь

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

«Предположим, что мы только что обновили страницу и хотим вернуться на страницу «Игры». Итак, как только мы нажмем, мы получим мгновенный переход к предварительно отрендеренной странице, а затем заполнится контент. Как это работает?» — сказал он. «Ответ: предварительная загрузка. Благодаря частичному предварительному рендерингу ссылки по умолчанию будут предварительно загружать статический контент для предстоящего маршрута».

Новая модель программирования гарантирует, что каждый маршрут имеет статический контент, говорит Селикофф, поэтому его дешево получить, и он не устареет к тому времени, когда пользователь действительно нажмет на ссылку.

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

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

«Нам не нужно переносить какой-либо код получения данных на клиент. Нам не нужно разветвлять наш компонент страницы в зависимости от того, является ли это первоначальным рендерингом или навигацией на стороне клиента, и нам не нужно было создавать какой-либо специальный загрузочный файл .TSX. Все, что нам нужно было сделать, это использовать Suspense и RSC, как обычно, и Next предоставил нам мгновенную навигацию на стороне клиента бесплатно».

Он также рассказал аудитории, почему эта функция называется «Компоненты кэширования», хотя, похоже, она не имеет ничего общего с директивой использования кэша.

«Если вы думаете о нашем сайте, что на самом деле позволяет нам заранее выполнить предварительную загрузку статического контента для каждой из этих страниц?» — спросил Селиков. «Дело в том, что мы знаем, что этот статический контент не может быть устаревшим. Именно это позволяет нам предварительно получить его. … Этот статический контент не может измениться, поскольку он основан на коде, который мы написали в нашем приложении. Он не может измениться, если мы не изменим код и не повторно развернем приложение. Таким образом, этот статический, предварительно обработанный контент фактически является кэшированным контентом».

Cache — это не «просто обновление нашего API статического рендеринга», добавил он.

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

«То, что App Router — это прежде всего сервер, не означает, что мы должны отказаться от тех видов взаимодействия, которые в первую очередь заставили нас всех полюбить React», — сказал Селикофф. «Предварительная выборка является ярким примером того, что их гораздо больше. Теперь, когда у нас есть архитектура, которая позволяет избежать провалов в производительности прошлого, мы знаем, что эта новая модель может продвинуть нас дальше, чем когда-либо могла бы старая».

ТЕНДЕНЦИОННЫЕ ИСТОРИИ YOUTUBE.COM/THENEWSTACK Технологии развиваются быстро, не пропустите ни одной серии. Подпишитесь на наш канал YouTube, чтобы смотреть все наши подкасты, интервью, демонстрации и многое другое. ПОДПИСАТЬСЯ Группа, созданная в Sketch. Лорейн Лоусон — опытный репортер в области технологий, которая в течение 25 лет освещала технологические вопросы, от интеграции данных до безопасности. До прихода в The New Stack она работала редактором сайта банковских технологий Bank Automation News. У нее есть… Подробнее от Лорейн Лоусон.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *