Transcription
[музыка]
Всем доброе утро, добрый день, добрый вечер! Рад видеть столько любителей React в одном помещении и любителям React — привет в онлайне. Меня зовут Хев Алексей, это Тёма Синюков, 2024. Давайте ещё раз поприветствуем друг [аплодисменты] друга.
Я очень люблю React, и когда хожу на конференции, всегда хожу на доклады про React и задаю там много вопросов. Если вы хотите задать вопрос, это можно сделать у нас в чате. Также будет возможность задать вопрос в зале, в микрофон. И по QR-коду ещё можно дать обратную связь, она очень важна для нас. Поэтому после доклада, давайте свою обратную связь, там есть специальная форма. Также после доклада и вопросов в этом зале мы перейдём в дискуссионную зону, где всех ждём.
Ещё я хотел чуть-чуть рассказать, как я познакомился с Тёмой. Я также много смотрю докладов про React, и у Тёмы отличные доклады про внутрянку на канале, про внутрянку React на канале Шри. И когда я ехал на поезде Челябинск — Уфа, эти доклады очень скрасили вот эти вот 4, там 6 часов. Поэтому Тёме отдельный респект за это.
И всё. Я подвожу к тому, что я сам очень жду этот доклад, поэтому больше не задерживаю. Поприветствуем Тёма Синюкова! [аплодисменты]
Всем привет! Рад вас всех сегодня видеть. Очень круто, что много людей собралось. Конференции возрождаются, много людей в оффлайне. Отлично! Ребятам в онлайне тоже большой привет. Рад, что смотрите.
Сегодня мы с вами будем говорить о том, как, как Next.js вообще рендерит. И хочется постараться объяснить всё это на пальцах, потому что там есть много сложных нюансов, подкатных нюансов и так далее. Но наша задача — хорошо в этом разбираться, понимать, как это работает. И сегодня будет об этом.
Пару слов о себе: зовут Тёма Синюков, делаю интерфейсы в КиноПоиске, читаю лекции в Шри, есть Telegram-канал. Практически, наверное, не пишу сейчас. Есть план по возрождению канала. Наверное, если хотите, можете подписаться. Я думаю, что скоро будут посты.
И возвращаемся к нашей теме. Как я уже сказал, Next.js. Как ты вообще рендеришь? И если вы вообще никогда не слышали про Next.js, или попав на этот доклад, у вас возник вопрос: Next, N, что это такое? Если что, N — это другое. Если вы хотели услышать про N, его не будет.
Но прежде чем мы начнём, немножко истории, немножко издалека. Кто-либо из вас знает этого серьёзного, уважаемого человека? Можете поднять руку. Отлично! Я так и думал. Ань Шодлик, и в 1828 году он изобретает электродвигатель. Этот электродвигатель он поставил на доску и сделал первый прототип электроавтомобиля. Но сразу после него, там через какое-то время, появляется ДВС, они начинают конкурировать. И доля электромобилей до 1922 года была в два раза больше, чем ДВС. То есть электромобили были популярнее. И то, что сейчас мы видим какие-то машины, тогда они были популярнее, популярнее, чем ДВС. Но ДВС победил, захватил рынок. Электромобили выкинули, сказали: "Всё, устаревшая технология, нам этого не надо, ездим на ДВС". Спросите, к чему вообще это рассказывал? Немножко терпения, в конце мы к этому вернёмся.
Сейчас возвращаемся к студии. Next.js — React Framework для построения fullstack веб-приложений. И в этом определении всё хорошо. То есть я буду много хвалить команду Next, и прямо вот с самого определения всё отлично. Ничего не выкидываем, всё оставляем как есть. Какие здесь плюсы? Хороший роутинг из коробки на основе файловой системы, из коробки SSR, SSG и так далее. Хорошая работа с кэшем, очень много оптимизаций. То есть, если у вас небольшое приложение, берёте как есть, из коробки запускаете и получаете очень много профита. И фичи React достаточно быстро поддерживаются. Ну, настолько быстро, что там работают фичи с канарейки React, то есть они ещё даже не в проде, и Next появился уже какое-то время назад.
И всё время, пока вот он сейчас существует, можно разделить на два этапа: до появления App Router и после появления App Router. Tailwind уходит в горизонт, потому что, ну, я надеюсь, что эта технология не загнётся в ближайшее время, потому что мы сделали на нём приложение Кинопоиска. И до App Router был роутер, нормальные технологии, о'кей. Сегодня рассмотрим её. Соответственно, после App Router был никакой интриги. App Router. И мне хочется сегодня посмотреть на две этих технологии и понять вообще, почему нужно было делать какой-то App Router, почему были проблемы, что за проблемы были. И сравнивая два этих инструмента, мы будем отвечать на два вопроса.
Вопрос: Где среды рендеринга? И здесь мы можем сразу ответить, что среды рендеринга у нас две: это клиент [немножко рекламу я вставил] Яндекс Браузер и сервер. Здесь, да, можно, конечно, говорить, что у нас есть несколько рантаймов и так далее, но на дате тоже есть, поэтому оставим её здесь.
И второй вопрос: Как? И на вопрос "как" может отвечать куча разных способов: клиент-сайд рендеринг, SSG, SSR, инкрементальный рендеринг и огромное количество любых рендеров, которые вы придумали в своём гараже. Можете сами придумать, дать название, оно заходит так, так многие делают.
И начнём с Page Router. И рассмотрим именно эти вопросы. Как раз клиент. Что у нас на клиенте? Здесь всё просто: клиент-рендер. Я думаю, не для кого не будет секретом, как он работает. Запрашиваем страницу, отдаём пустую страницу, отображаем белый лист, запрашиваем скрипты, отдаём скрипт, добавляем элементы, запрашиваем данные сервера, данные отдаёт и рендерит эти данные. Путь достаточно ветвистый. Но из плюсов здесь крайне дёшево по ресурсам, потому что мы просто отдали страницу, отдали, и на стороне клиента всё это крутится. Быстрые переходы между условными страницами. Как таковых страниц здесь нету, здесь есть взаимодействие с браузером и просто перерисовка страницы. Как мы хотим.
Из минусов — заблуждение, что сейчас у нас всё супер классно, вообще у всех и так далее. Вообще нет. В некоторых деревнях даже интернета ещё нету. А если есть, то прям очень плохой, медленный. Первый старт, потому что мы ждём загрузки, белый лист, грузим, но и так далее. И плохое, ну, в скобочках подписано, SEO. Где-то какое-то оно мифическое есть, но по факту нет.
На сервере тут всё просто. [музыка] С ранее уже подготовленных, и потом, когда клиент приходит, мы ему их отдаём, он их отрисовывает. Достаточно классная схема, очень дёшево по ресурсам, быстрое открытие страниц, SEO не требовательно к устройству клиента, потому что на клиента идёт готовая страница.
Минусы: плохая масштабируемость. И если говорить о масштабируемости, здесь не про ресурсы, что там много всего нужно, а про то, что если у вас там миллионы фильмов, то генерить постоянно миллионы страниц плюс юзер-зависимую информацию, то есть у вас будет просто безумное количество страниц. И такой подход вот в масштабе не работает.
Следующее — SSR. Что с SSR? Запрашиваем страницу, на сервере у нас готовятся данные по запросу, рендерим страницу с данными, и потом отображаем готовую страницу на клиенте. Что хорошего? Быстрая загрузка, если у вас хороший сервер. Если плохой сервер — не очень хорошая быстрая загрузка. Точно SEO, хорошая, не требовательно к устройству клиента. И по минусам — это дорого по ресурсам. Потому что, если сравнивать с клиент-сайд рендерингом, то в случае с клиент-сайд рендерингом мы всё делаем на устройстве пользователя, грубо говоря, берём в аренду. То есть, вот тебе всё, что нужно, собирай сам, как хочешь там. А в случае с SSR у нас есть наши сервера, они стоят в нашем контуре, и мы либо покупаем новые сервера, либо всё будет медленно.
Какой подход выбрать? На самом деле, в Next.js не нужно выбирать. Next.js даёт возможность объединить все эти подходы, так называемая гибридность. Есть такое слово или нет? Оно подсвечивается красным. Ну, здесь нет, а в презентации да. Возможно, я его придумал, может быть, и нет. Так вот, Next.js объединяет все эти подходы и позволяет нам не выбирать, а просто писать код, и под капотом он нам предлагает какие-то варианты.
Что с SSG? Команда Next считает, что SSG — это прям топчик, прям супер, это то, что вам нужно, и вам стоит использовать его всегда. Поэтому он по дефолту SSR. Если подготовить страницу на билде не получилось, то есть её нельзя подготовить, очень большая ри, либо есть какие-то параметры, там динамический роутинг и так далее. Ну, и рендеринг отдали клиенту вашу заготовленную заранее страницу, и на клиенте вы уже грузите данные, что-то показываете и так далее.
Как это выглядит в коде? Напомню, это Page Router. У нас есть некая страница, наша основная страница, есть страница movies, есть страница динамическая с неким кодом. Мы просто по параметру открываем страницу и показываем информацию о фильме. Если мы запустим билд, мы увидим следующее. Да, спасибо команде, у них есть легенда. То есть, вы когда запускаете билд, вам не нужно лазить постоянно в документацию, смотреть что-то и так далее. Вы можете просто увидеть, какие у вас есть страницы. В нашем случае это статические и динамические. И смотрим на символы. У нас получается, movies — статическая страница, потому что там нет никакой, ну, там нет динамических параметров, данные из API берутся и так далее. И динамическая со слагом.
Как всё это выглядит? Если всё это объединить, выглядит следующим образом: на билде генерируем набор страниц, потом запрашиваем, запрашиваем страницу с клиентом. Если страница не готова, данные подготавливаем, рендерим, то отдаём сразу готовую страницу. Страницу получаем, отображаем, реагируем на действие пользователя, если что-то нужно, загружаем дополнительные данные, рендерим и так далее. И эти данные отрисовываем.
SSR и клиент-сайд рендеринг. Если всё это разделить по этим типам рендеринга, то получим примерно такую картину, что у нас есть части SSG, части SSR и клиент-сайд рендеринга. Но подход вроде бы классный, да? Они взяли все эти типы рендеринга, объединили, сделали это за нас. Нам не нужно думать, не нужно писать Node.js приложение, делать свой SSR и так далее.
Но какие есть проблемы? И они здесь действительно есть. Первая проблема — это монолитность. Привет тем, кто любит пилить монолиты. Ну, здесь близко, но не совсем то. В чём проблема монолитности? Смотрите, мы на сервере готовим какую-то страницу. То есть, ну, пользователь пришёл, говорит: "Хочу вот такую страницу фильма". Мы ему эту страницу готовим, и на клиента он загружает страницу целиком, то есть полностью, как есть. То есть, он загружает её, ждёт, пока всё там зарендерится и так далее.
Как это выглядит на пальцах? Мы загружаем данные на сервере, рендерим страницу целиком на сервере. Здесь появляется первая метрика — Time to First Byte. Клиент начинает загружать код на клиент. После чего, когда он всё загрузил, First Contentful Paint у нас появляется. И потом у нас происходит гидрация. Time to Interactive. После этого всё о'кей, и выглядит, что можно здесь что-то, наверное, сделать.
И да, уже есть решение в React — это называется Streaming. Если мы обратимся к Википедии, то нам скажет, что это потоковое вещание в глобальной сети. Переносим немножко на нашу специфику и предполагаем, что возможно какая-то передача по частям нашей страницы. И вы будете на самом деле правы, потому что мы берём и говорим, что на сервере у нас готовится некий плейсхолдер, и все компоненты у нас являются отдельными частями этой страницы, и мы загружаем их по частям. То есть, вы на клиент начали загрузили плейсхолдер, пользователь уже что-то видит, возможно, даже может с чем-то взаимодействовать, и по частям грузите ваши компоненты, когда данные для них уже готовы. Таким образом, мы получаем следующую картину: это у нас монолит. И если мы начинаем говорить о стриминге, то загрузка данных у нас распараллеливается. После чего у нас рендеринг не целой страницы, а кусочка страницы. После чего клиент грузит код не всей страницы, а отдельных кусочков. И происходит гидрация опять же отдельных кусочков. И мы уже здесь видим, что метрики улучшаются просто банально от того, что мы распараллелили всю нашу страницу.
Но здесь ещё важный момент, что возможно, все элементы вашей страницы грузят данные. Например, шапка либо футер. Может быть, там просто какой-то конфиг. И тогда мы в принципе можем убрать загрузку данных и просто сразу отрендерить этот кусочек страницы, отдать его на клиент и просто зарендерить.
Если сравнивать с монолитом, то мы получаем следующую картину. Да, возможно, это рисунок от руки, не по каким-то там масштабам и так далее, но я думаю, что здесь в принципе очевидно, что метрики у нас улучшаются просто банально, потому что занимаемся не всей страницей, а занимаемся только её небольшим кусочком и уже от него отталкиваемся. Работает это всё с Suspense в React. Доступно. Всё о'кей, можно использовать.
Что дальше? Какая следующая проблема у роутера? Все компоненты работают на клиенте, даже если это нам вообще не нужно. Ну, то есть, никаким образом. Чем это плохо? Это плохо тем, что мы загружаем лишний код на клиент. Соответственно, механизмы рендеринга выж, все их учитывать постоянно. То есть, мы загрузили кучу кода, построили дерево React, дерево React-элементов, дерево Fiber, рендерим их постоянно и так далее.
Что же нам делать? И здесь тоже уже придумали решение. Называется Server Components. Да, примеров использования на самом деле не так много, но это яркий пример, где они достаточно хорошо используется. Как говорит команда, надо придумали Server Components — такие компоненты, которые рендерятся только на сервере и только один раз. И от этого определения мы с вами будем отталкиваться дальше.
Выглядит примерно таким образом. Из того, что может прям сразу броситься в глаза, это загрузка данных. Она здесь не совсем стандартна для React-разработчика. Здесь нет эффекта. Если мы посмотрим на жизненный цикл обычного клиентского компонента, функционального, да, мы не говорим про классовый, просто функциональный клиентский компонент — это `create`, можно сказать `mount`, потом какое-то количество перерендеров, здесь четыре набросал, может быть, один, может быть, вообще не быть, то есть всё зависит от того, там есть у вас состояние и так далее. И потом, когда он нам не нужен, он строится.
Что с серверными компонентами? У них нет рендера, вернее, перерендера. Один раз только на сервере и всё. И потом, когда их не нужно отображать, их просто выкидывают. Всё, больше ничего. И отсюда следующее ограничение: нельзя поменять. Нет рендеров — значит, ничего не меняется. Компонент статичен. То есть, он один раз отрендерился, API браузера на клиенте он не рендерится. Это готовая статика. Следовательно, никаких обработчиков, ничего у вас там не будет. И нельзя использовать хуки. Ну, как и большую часть React, потому что те же самые `useState`, `useEffect` они сильно завязаны на рендеры. Здесь этого нету вообще. То есть, ещё раз отрендерить, закинули на клиент и всё. Никаких перерендеров, данных, никаких эффектов, ничего. Вам не нужно разбираться с жизненным циклом, его по факту просто нету. То есть, один раз отрендерить, данные загрузили, отобразили, отправили на клиент. Код, необходимый для их рендеринга, остаётся на сервере, на клиент он не попадает, потому что один раз отрендерили на клиент, всё, он не перерендерится. И клиентской части механизма рендеринга React эти компоненты не интересны совсем. И на самом деле, это огромное такое вот поле для оптимизации и так далее, потому что у вас по факту есть часть дерева, за которой можно, ну, грубо говоря, в большинстве случаев не следить. Это очень интересно.
Можно ли использовать только их? Ну, если в общем, то нет. Если вы делаете максимально простой лендинг без вообще какой-то клиентской логики, то есть чисто запросили данные, отобразили и всё, один раз показали и потом избавились от него, тогда, ну, с натяжкой, да. Но в большинстве случаев нет.
Возникает вопрос: кто кроме серверных? Очень просто. Клиентские. У нас две среды рендеринга. И здесь возникает самое главное заблуждение, что серверные рендерятся только на сервере. Ну, это на самом деле, кстати, правда. А клиентские рендер только на клиенте? Нет, не так. Я, конечно, ну, трюкач React, но что-то в названии тут на самом деле не совсем хорошо. Вот, потому что на самом деле серверные — это без клиентской логики, а клиентские — это с клиентской логикой. К месту рендеринга, ну, не совсем соотносится.
Если мы представим жизненный цикл, то он будет выглядеть примерно так: серверные на сервере, тут всё отлично. Клиентские на клиенте, но не только, могут и на сервере. Таким образом, мы получаем, что серверные — только на сервере, нигде больше, только на сервере. Следовательно, у вас должен быть сервер обязательно. А клиентские — либо на сервере, либо на клиенте. Даже если они клиентские, могут на сервере, но просто они перерендериваются на клиенте и, соответственно, может быть клиентская логика.
В каких отношениях они состоят? Потому что мало просто иметь набор каких-то компонентов, нам нужно из них делать какие-то композиции, страничку сделать, дева и далее. Проблемы: не всё можно передать. Псы, функции не сможете передать. Но обычные данные без каких-либо проблем. Клиентские могут рендерить серверные. Но здесь есть одна проблема: клиентские могут перерендерить. Вспоминаем теорию React, что при перерендере родителя, перерендерится дочерний. Если серверный дочерний клиентского, он тоже перерендерится. Не может перерендериться, становится клиентским. И это ещё один важный момент. Серверный, вот этого компонента, она определяется не местом, где он рендерится, не тем кодом, который там есть, она определяется ещё и позицией в дереве. То есть, мало просто отрендерить его на сервере и не добавить клиентскую логику. Если в дереве React серверный компонент будет дочерним клиентского, то он будет клиентским и будет участвовать во всех механизмах. Следовательно, если мы смотрим в масштабе, и у нас в корне есть клиентский компонент, то серверный вы не используете в вашем приложении. Их по факту нету. Все остальные будут клиентские. И здесь нам важно добавить такой термин, как Client Boundary. Когда у вас есть клиентский компонент, и все его дочерние, вся ветка дерева полностью попадает в Client Boundary, и они все становятся клиентскими. Они все будут перерендериваться, учитываться в механизме рендеринга React. И оптимизации вы никакой, естественно, здесь не получаете. То есть, вы наложили на себя ограничение, но профит не получили. Не надо так делать.
И после того, как мы разобрали две вот этих концепции — стриминга и серверных компонентов — мы можем перейти к App Router, который как раз является неким переосмыслением роутера. В случае с роутером там всё прикольно, там всё хорошо. Гибрид вот этих рендеров. Но добавляя две этих концепции, мы получаем App Router, в котором многие проблемы решены. На клиенте у нас Client Rendering остаётся. На сервере у нас Static, Dynamic и добавляется ещё дополнительно Streaming. Плюс ко всему к этому у нас добавляются Server Components. Чуть позже у нас тоже появится, мы на него взглянем. И Server Components.
И прежде чем мы начнём говорить вообще о том, как всё это устроено, в какой момент Static, в какой момент Dynamic и так далее, давайте посмотрим, как Server Components здесь реализованы. Они всегда используются по умолчанию в 100% случаев. Если вы создаёте компонент, у вас будет Server Component, если не снижен. Это тоже Server Component. Загрузка данных есть. Какой жизненный цикл они вообще проходят? В рамках всё начинается с того, что происходит преобразование Server Component в так называемый `rsc`. Что это за такой? Я не буду всякие страшные картинки вытаскивать. Скажу лишь только, что в него входит результат рендеринга Server Component. То есть, у вас есть функция, вы её запускаете, `React.element` из компонентов и ссылки на их файлы. Server Components связаны с клиентскими, и нам нужно понять: вот мы, Server Rendering, куда, почему это оно? И данные, данные, передаваемые от серверного к клиентскому компоненту, они тоже нужны, потому что иначе, иначе клиентские компоненты смысла иметь не будут. После того, как `rsc` мы рендерим HTML на сервере, используем и компоненты. После этого отображаем неинтерактивный HTML. То есть, мы на клиент загрузили, у нас просто красивый HTML. О'кей. После этого нам нужно согласовать деревья, деревья компонентов с помощью `rsc`, который у нас уже есть. И потом, соответственно, гидрация, и ваш пользователь радуется. Всё, интерактивность достигнута.
Выглядит следующим образом: если мы добавляем какую-то клиентскую логику, то здесь возникают проблемы. Скорее всего, когда вы этот компонент запустите, то у вас будет ошибка. Вам будет говорить что-то, что что-то вы делаете не так, ребята, остановитесь. И он вам предложит добавить директиву `use client`. И как бы, да, проблема решается. Ваш компонент стал клиентским, клиентская логика там работает отлично. Но жить с этим не просто. Почему? Потому что если у вас есть дерево компонентов, у вас какой-то компонент начинает кричать о том, что "всё, мне срочно нужен `use client`, добавь, пожалуйста". Вы добавляете, и в большинстве случаев, там различных роликов, статей и так далее, часто говорят, что типа, есть ошибка, добавляю `use client`, мне кажется, я когда тоже увидел всё это вот происходящее, тоже такая ошибка, добавлю `use client`, она поправилась и отлично, приложение заработало. В чём проблема такого решения? Проблема такого решения, что всё у вас становится клиентским, и неожиданно добавляется ещё Client Boundary, который ухудшает всю эту ситуацию. И Server Components, которые могли бы стать серверными, но нет, они тоже становятся клиентскими.
Что делать? Очень важно грамотно разделять код на компоненты. Я достаточно много сейчас буду говорить про композицию, потому что, ну, я в прошлом докладе уже про это говорил, но здесь, к счастью, мне это очень нравится, что композиция выходит на новый уровень. То есть, важность её становится выше, потому что банально с помощью бесплатной композиции можете достигнуть большой просто за счёт использования Server Components, верного использования Server Components. Грамотно разделяете на компоненты. Если у вас есть какой-то компонент, в нём есть клиентская логика, здесь есть комментарии, логика, там какая-то сложная логика подготовки ваших полей, там что-то какая-то информация о фильмах готовится и так далее, и у вас есть состояние, и у вас есть кнопка — это клиентская часть. Её можно очень легко вынести в отдельный компонент. Это не какая-то магия, это просто композиция. Она доступна прям всем. Прям вот только начинаете изучать React, вам сразу будут говорить про композицию. Просто выносите, и ваш компонент становится уже не клиентским. То есть, `use client` здесь писать уже не нужно. Здесь нет клиентской логики совсем.
Далее, старайтесь держать клиентские компоненты ближе к листям, ближе к листьям дерева. Вспоминаем про Client Boundary. Чем ниже ваши клиентские компоненты, тем меньше будет Client Boundary, тем меньше компонентов в неё будет попадать, тем меньше компонентов серверных будут становиться клиентскими. И это важно. И используется псевдо-родители. Здесь есть QR-код, его можно отсканировать, там прошлый доклад, и там есть большой блок про псевдо-родителей. Я здесь немножко расскажу. Если что, все слайды будут доступны потом, можно будет отсканировать, посмотреть без каких-либо проблем. Так вот, псевдо-родитель. Есть у нас такой вот компонент `page`, и у этого компонента есть использование контекста, обычное нормальное практика. Но я думаю, многие люди, кто начинал использовать Next, пытались использовать контекст, и там происходит что-то, ну, вообще то, что вы не ожидали. Почему? Контекст — это клиентская логика. И значение, которое там, это тоже клиентская логика. Потому что что делать? `MyComponent` хочет быть серверным. Нам приходится всю страницу делать клиентской. Если вся страница клиентская, то все компоненты на этой странице будут клиентские. Там вообще нет серверных компонентов. Это прям провал. Берём небольшим таким вот движением руки, магия, и делаем компонент `Provider`. Он принимает `children`, у него внутри есть какое-то состояние, и он по факту является псевдо-родителем. То есть, `UserProvider` — не настоящий родитель `MyComponent`, и он не влияет на распространение вот этой клиентской. И мы можем выкинуть `use client` отсюда совсем, и `MyComponent` остаётся серверным. Возможно, какие-то дочерние компоненты его будут использовать `useContext` и так далее, но без каких-либо проблем. То есть, они будут клиентские, но не он сам, и не всё-всё-всё подряд. Таким образом, можно использовать серверные компоненты, которые дают вам достаточно много плюсов. Мы о них говорили до этого.
Теперь переходим к Static, Dynamic и SSR Rendering. Когда используются они? Статик. Вспоминаем про SSG. Его стараются использовать максимальное количество времени, в максимальное количество страниц сделать статическими, максимальное количество кусков кода сделать статическими. Использовать во время билда и фоново во время работы сервера. Здесь, кстати, интересный момент, его стоит запомнить. Фоново во время работы сервера. Dynamic использует во время работы сервера на запрос, то есть on demand. И Rendering используется на клиенте. И вот здесь интересный момент: я вас просил запомнить, что фоново во время работы сервера и Dynamic тоже во время работы сервера. Возникает вопрос: когда какой использовать?
Начнём со статики. Статик используется в том случае, если роут не динамический. То есть, у вас нет какого-то параметра. Если данные у вас не загружаются, либо кэшируются, там просто какая-то статика, вы настали, отправили, классно. Либо данные у вас намеренно в моём случае там были примеры: запрос `movies`, запрашиваем все фильмы, мне достаточно кэша, я их отображаю.
Dynamic. Не смотрим в кэш и не смотрим в заголовки. Если вы смотрите в кэш и заголовки, статики у вас не будет, прям 100%, прям сразу. Dynamic, если не получилось использовать статик. Статик приоритетный, Dynamic не приоритетный. То есть, он в любое другое время. Но их тоже можно объединять, и их может объединять не только сам Next.
где-то у себя под капотом. Но и вы просто своими ручками есть компонент. Он загружает один конкретный фильм. В КиноПоиске миллион фильмов, там, я не знаю, миллиард, может быть, огромное количество фильмов. Их невозможно все посмотреть, даже мне кажется, за всю жизнь времени просто не хватит. И сгенерить статически такое большое количество страниц — не самое хорошее решение. Плюс, там есть юзер-зависимая информация. Нам нужно продавать подписку, говорить о том, что там что-то поменялось, что-то появилось и так далее, причём конкретно вам, под ваши запросы, рекомендации и так далее и тому подобное.
Что же делать? Генерить всё на сре? Да, это решение, но пока без но. Давайте посмотрим, что у нас здесь. Динамический. Всё верно. Вот теперь вот как раз, но мы хотим сделать часть страниц статическими. Например, у вас есть топ-10 в конкретном регионе, и вы знаете, что достаточно большое количество трафика приходится именно на эти страницы. Если у вас нет таких инструментов, то их точно стоит завести, чтобы посмотреть, куда идёт трафик, на какие страницы и так далее. И в топ-10 идёт достаточно большое количество трафика. Что мы можем сделать? Используем Stams, пишем там простую логику Get top 10. Нам запрос возвращает список фильмов из топ-10, и мы возвращаем набор параметров для страниц, которые нужно сгенерить во время билда. И таким образом, мы видим, что у нас получается. Страница остаётся динамической, но появляется какое-то количество страниц, которые сгенерить по вот этим ID. То у нас получится, что страница отдаётся нам из кэша, она уже готова, всё, она вас ждёт. И для топ-10 это прям супер. То есть вы прям сразу видите фильм. Всё остальное динамически сгенерируется. Фильмы уже не так популярны, нагрузка на серверы значительно уменьшается, и таких мест может быть очень много. Плюсом ко всему важно добавить ещё и тот стриминг, о котором мы говорили, не забываем про него.
Есть у нас компонент Movie. Здесь есть запрос Movie, тот же самый компонент. И если мы сделаем вот так, просто м, да, естественно, у нас там есть корневой лоуд, есть главная страница и так далее. А попробуем всё это дело отобразить. Конечно, это зависит от вашего сервера, однозначно. Всё зависит от вашего сер. Ну, не всё, но очень многое зависит от вашего сервера. Если у вас проблемы с железом, то у вас будут проблемы и с сервером и так далее. В моём случае страница загружалась, у меня 5 секунд, не очень приятно, я вам так скажу, потому что пользователь в этот момент видит вот это. Я попытался передать вам дискомфорт пользователя, я думаю, вы оценили. Проблема в том, что мы использовали то самое монолитное решение. Хотя в ауте нам, ну, прямо из коробки дают, говорят: "Ребята, есть стриминг, берите, используйте". И у вас, возможно, уже есть корневой юзер. Скорее всего, он есть, он обязателен, иначе это не будет работать. И возможно, в этом карм лейте у вас есть шапка, у вас есть футер, есть какие-то дефолтные стили, например, тёмный фон, ещё что-то. И вам хотелось бы загрузить его раньше. Что вы можете сделать? Вы можете сделать страницу. Что это за страница? В ней прям минимум всего. Там просто какой-то скелетон. Но всё, очевидно, потому что вы загружаете ваш леаут, шапку, футер, какие-то стили. Пользователь, возможно, зашёл на главную страницу, чтобы куда-то в навиг. Он не хочет ждать загрузки вашего основного контента. Ему даже витрина не нужна. Он хочет перейти куда-нибудь там в поиск либо ещё куда-нибудь. И вы можете ему его отдать сразу вместе с корневым лейаутом.
Конкретной группы либо конкретной страниц, в принципе. И вместо вот этой тяжёлой страницы витрины, например, вы можете просто отобразить скелетон, и пользователь уже увидит ту часть, с которой сможет взаимодействовать. Ну и также не забываем, что можно использовать sup и ещё больше дробить ваши страницы. Таким образом, более тяжёлые компоненты либо компоненты, которые отображаются только для авторизованного пользователя и так далее, их можно, в принципе, вообще исключить из страницы. Тут возникает вопрос: "А как помочь рендерить?" И самый первый совет, на самом деле, вот из того опыта взаимодействия, попыток там что-то оптимизировать, его рендеринг, попыток там как-то с кэшем поработать и так далее, не думайте про рендеринг зачастую. То есть у меня прошлый доклад был про то, что большинство перерез, они вообще не страшны, не нужно об этом переживать. Также и здесь. Старайтесь как можно меньше думать про рендеринг. Очень много всего хорошего сделано под капотом. Ребята за это деньги получают, то есть они прямо сидят и целенаправленно делают фреймворк, чтобы вы как можно меньше думали про рендеринг. Но, к сожалению, очень многие: "Блин, что-то не то сделали, давайте я всё поправлю". И получается, к сожалению, что-то непонятное. И новые разработчики, приходящие у вас на проект, смотрят такие: "Типа, нет, это не тот Next. Я почитал про другой". Следующее: не мешать кэш. Кэш в Next отдельная тема, тема интересная, тема хорошая. В доклад она не влазит, потому что она, в принципе, как доклад. И здесь я просто оставлю такую пометочку, что не мешайте кэш. Им можно управлять, они максимально упрощают управление кэшем, но зачастую он работает достаточно хорошо. И если мы говорим про небольшие приложения, там прямо вообще всё хорошо, то есть просто берёте из коробки, он работает. Если чуть-чуть посложнее, то да, можно добавить принудительное обновление кэша, можно добавить политики кэша, но тем не менее, из коробки работает достаточно хорошо. Третье: используйте стриминг, loading, J и Suspense. Они тоже есть из коробки. Многие про них забывают, и пользователи страдают. Не забывайте их использовать. Хорошая, классная вещь. И очень важная мысль, крайне важная: акцентируя, грамотно составляйте композицию компонентов. Я говорю об этом уже второй доклад. Сколько там, 35 минут уже прошло, и там ещё 45 было. Приличное количество времени. Уже больше часа я рассказываю про то, что композиция важна. И, к сожалению, многие про это забывают, пытаются использовать мемоизацию, сторонние библиотеки, инструменты и так далее. Хотя многие проблемы можно решить композицией. И серверные компоненты как раз нам об этом и говорят, что: "Ребят, просто грамотно расположите ваши компоненты в дереве, и всё будет отлично. Вы не будете переживать о рендерах и так далее".
И после всего этого мне хочется вернуться. Интрига была сделана. Почему вообще рассказывал про этого перца с движком на коленочки? Проиграли, совсем их выкинули, сказали: "Это всё, это устаревшая, ненужная вещь, всё, мы её не используем". И все очень сильно окунулись в ДВС. Но кто знает вот этого перца? Можете поднять руку. Вот сразу видно, что люди любят Twitter больше, чем историю. Так вот, 2023 год. Если посмотреть, какая машина продавалась больше всего — это Tesla Model Y. И это электромобиль. Так вот, когда люди в 1930 году говорили о том, что всё, электромобиль — это прошлый век, мы никогда в жизни их использовать не будем, теперь только ДВС, только вперёд, только в будущее. В 2023, может быть, зелёная повестка, ещё что-то и так далее и тому подобное. Не знаю, я не только цифры, только факты. Это самый популярный автомобиль в мире. И вот этот парень не совсем согласен, что это устаревшая технология. На это намекаю, но иногда просто происходит так, что некоторые идеи опережают своё время. Им не хватает инфраструктуры, каких-то развития смежных областей и так далее. Я не говорю, что PHP — это та технология, которая, ну, вернее, как PHP опередила своё время и сейчас переосмысливает эти вещи с новой инфраструктурой, с дополнительными какими-то библиотеками, модами и далее. Но, возможно, это так. Поэтому закидывать его чем-либо, а просто посмотрел бы, как оно будет развиваться и попробовал бы на этом. У меня всё. Спасибо за внимание. Спасибо за доклад. Мне очень понравилось. Посоветую своим коллегам. Правда понравилось? Да, правда понравилось. На самом деле, я пересмотрю. Потому что иногда нужно подумать. Да, слайды там есть. Канал, и, наверное, в канале есть, куда мне лично написать, если что-то понравилось, не понравилось. Можете прямо туда написать, сказать: "Парень, просто чушь". Но если понравилось, можете написать "спасибо". Мне тоже будет приятно. Да, пишите. Значит, начнём с вопросов. Сначала будет два вопроса из чата, потом будет два вопроса из зала. Поэтому, если хотите задать вопрос, готовьтесь. Во.
Кто и в какой программе делал этот божественный дизайн презентации? Да, я короче всем сейчас отвечу, потому что после прошлого доклада было много вопросов. На самом деле всё просто. Небольшая минутка дизайна. Смотрите, это Keynote. В нём есть слайды и есть анимация. Есть такая анимация Magic Move. Её просто используйте, и всё. Но если вы её используете, то готовьтесь заплатить чёртову цену. Вам нужно делать раскадровку. Вот это по факту небольшая презентация. Ну, какие-то такие моменты, вот интересные типа графики, они выглядят вот так. Сам их дорабатывает. Так вот, что вы делаете? Вы берёте, делаете просто кучу слайдов. Сейчас один момент, я даже, наверное, покажу. А, нет, мира не покажу. Короче, как делается что-то подобное? Вы заходите в мира, делаете там раскадровки ваших схем, слайдов и так далее. После этого это перерисовываете либо нативно в ноуте, либо там где-то в другом месте, и картиночку накладываете. Говорите: "Давай Magic Move". Он вам всё это собирает. Слайдов получается много, поэтому я сразу советую хорошо продумать вашу презентацию, проверить, как она выглядит, и после этого уже делать вот эту вот раскадровку. И после этого вы просто пересматриваете презентацию и, соответственно, смотрите те моменты, где Magic не сработал хорошо. Их сразу было видно. Это вот где там перенос, нельзя. Вот эти вот, они были кривые вот в изначальной версии, их прямо сильно больше. Так вот, в этих местах вы просто руками допиливаете. Всё. Круто. Спасибо. Если что, мы это не готовили заранее. Не, на самом деле, просто, ну, мне кажется, будет круто, если ещё будут слайды, как у тебя. У всех. Я не говорю, что как у меня, но все будут прям типа: "Так, ну делать, короче, прикольные презентации". Потому что вот я про это рассказал, а выйдет какой-то чувак в следующий раз, такой: "А я вот это придумал". И тоже что-то расскажет. Мы, конечно, тут про технологию, не про дизайн, но тем не менее, всё равно интересно. Я думаю, многие делают слайды и доклады. Второй вопрос: нет ли проблем с локальной разработкой при использовании SSG в плане ожидания старта де сервера, долгий билд? Нет, как такового нету. Ну, смотрите, здесь ещё важный момент заключается в том, что много из этого происходит в фоне, и вы можете сделать принудительное обновление кэша. То есть сделать, например, какую-то такую типа "обновись" ручку. В Next на сервере приходит ваш аналитик в админку, ну, где-то называется аналитик, там менеджер, кто-то ещё, человек не близкий к коду, скажем так. Вот он через интерфейс вбивает, меняет конфиг, там какой-то там шапку, ещё что-то меняет и так далее. После этого нажимает кнопку "сохранить", и на это сохранение вы можете намеренно сделать обновление кэша. Кэш обновляется, сбрасывается, и страницы, это использующие, они перегреются просто. И соответственно, следующий, кто придёт, у него уже будет страница с обновлённым контентом. Вот это, например, тоже хорошо работает. Ну, у вас просто в фоне сервер работает, а фоне у него SSG может перегреть, перегенерить. Круто. Спасибо.
Давайте два вопроса из зала. Кто? Привет, привет. Вообще, ну, сначала скажу, отличная работа, вот, молодец, классный доклад. Вопрос странный немного. А вот насколько стриминг работает хорошо в медленных сетях? Ну, скажем так, в медленных сетях в принципе не очень хорошо всё работает. Вот, если интернета нет, то и целую страницу будет сложно загрузить. И тут важно понимать, что, ну, если сравнивать с обычным, вот, но здесь и количество пакетов сильно меньше будет. Вот. То есть, ну, это равносильно тому, что вы сделаете просто ленивую загрузку каких-то блоков вашей странице. То есть это плюс-минус похоже. А вот с точки зрения UX, что лучше: загрузить изначально, да, страницу какую-то, да, подождать, пользователь сразу поймёт: "Ну ладно, я тут подожду", типа 2 минуты, образно. Либо постоянно заставлять его ждать на медленных сетях? Да, смотрите, я всегда говорю про то, что нет серебряной, или как там, золотой пули, короче, пули нету. Здесь, здесь нужно просто думать под каждую конкретную ситуацию. Если вы говорите про разработку, например, для внутреннего какого-то продукта, систему какую-то делаете, я бы сказал, просто рендеринг вперёд, и не надо нагружать серваки. Если мы говорим про разработку на внешний рынок, где у вас просто устройства там от, ну, кнопочные телефоны, вряд ли, я не знаю, просто, ну, к сожалению, не знаю, вот насколько там всё открывается сейчас, не знаком с вот этой частью. Но от прямо самых простых устройств до самых продвинутых устройств, то здесь вам нужно смотреть уже, а как вам и тем дать, чтобы всё хорошо было, и этим, чтобы они за использовали свои телефоны какие-то супермодные, классные, и чтобы всё было быстро. Вот. И тут нужно просто смотреть, готовы ли ваши пользователи. Например, если у вас оператор, э-э, ВМ, хотел сказать, компьютера, вот он приходит, и в начале рабочего дня открывает приложение, и потом с ним работает. Ну, естественно, 2 минуты — это ерунда. А если человек заходит купить фильмы, и он, например, едет в машине, там ему жена сказала типа: "Дорогой, там, мы давно никуда не ходили", он такой: "Быстро всё". И нужно ещё в аварию не попасть. Я не пропагандирую. В этой ситуации намного важнее, чтобы вот эта полка, афиша, она загрузилась прямо самый быстрый. Мне вообще весь сайт не нужен, мне нужна полка, афиша, чтобы я кликнул "купить билет" просто в ближайший кинотеатр и всё. Вот. И всё решение проблемы. И соответственно, отсюда у нас выходит ещё, что сервера есть, есть нагрузки на сервера и так далее. И если вы боретесь за то, чтобы у вас ваше приложение открывалось максимально быстро на различных устройствах, и SEO было классно и так далее, вы вкладываете в сервера. Соответственно, если внутренняя разработка, ну, я не вижу смысла вкладывать деньги в сервера, потому что это деньги компании, как бы их беречь надо, вкладывать в полезные вещи, в рендеринг, например. Всё. Тогда спасибо. У нас заканчивается время, но мы сможем продолжить в дискуссионной зоне, поэтому приходите, пообщаемся. Всем спасибо. Всё, спасибо, ребят.