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

Почему привет! Это было давно, не так ли?

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

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

Проблема

Как оказалось, поддержание 7-летнего технического долга в команде (максимум) из 3 человек затрудняет продвижение вперед. Этот технический долг становится тяжелее всего, когда его просят быстро перейти к изменяющимся тенденциям.

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

В то время мы полностью занимались рендерингом на стороне клиента. Это означает, что весь контент нашего сайта был отправлен на Javascript, и страница должна была оценивать каждую строку JS перед тем, как что-либо отобразить. Это был (и остается) чрезвычайно дешевый подход к хостингу, который очень хорошо работал для нас на протяжении многих лет. Однако чего он не может сделать, так это удовлетворить повелителей SEO, которые требуют, чтобы контент был в начальной загрузке страницы для анализа для получения значимой информации для людей, ищущих в Интернете.

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

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

Над моей головой

Это был мой первый опыт SEO в качестве человека, который раньше работал только с внутренними веб-сайтами. Что было важно? Чего не было? Как Google на самом деле это делает? Как это влияет на качество обслуживания клиентов? Как мне это сделать, не переписывая годы работы?

Это было довольно сложной задачей для меня, но я был заинтересован в новом вызове. К счастью, моя компания не новичок в SEO, и у нас были внутренние ресурсы компании, чтобы помочь ответить на большое количество вопросов. Я изучил, что потребуется для рендеринга наиболее важных приложений на стороне сервера. Ответ? Много. Мы говорим о новых CI/CD, репозиториях, общих пакетах и ​​так далее.

Потом я посмотрел на проблему более критично, и тут я начал сбиваться с пути. «Если у клиентского рендеринга есть контент, то почему бы нам не разместить клиентскую визуализированную страницу?» В конце концов, это всего лишь React, верно? Рендеринг на стороне сервера работает, оценивая дерево React для создания HTML, затем отправляет его клиенту, и React регидратирует себя, используя существующую структуру DOM. Итак, если я могу предоставить существующую структуру DOM и соответствующий код React, это все, что меня волнует, верно?

Интересно, что эта линия размышлений и есть то, как мы на самом деле решили проблему! Однако был и промежуточный шаг…

Посмотрите на меня, я теперь клиент.

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

Это было то, чего я смог достичь с небольшими усилиями благодаря существующей технологии. Безголовый браузер Express и Chrome в сочетании с Puppeteer дал мне возможность запустить браузер Chrome в док-контейнере и настроить сервер Express, на котором размещены встроенные файлы, для отображения страницы и доступа к результирующему HTML. Затем этот HTML-код можно было записать обратно в файл, к которому обращался браузер, фактически заменив HTML-код целевого узла рендеринга.

В слишком упрощенном стеке технологий это на самом деле работает очень хорошо. Взять приложение React, которое использует CSS через CDN, отобразить его и внедрить HTML в ваш размещенный сайт, на самом деле просто отлично. Он не самый производительный, но вполне удовлетворяет требованиям SEO.

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

С точки зрения производительности, он менее эффективен, чем метод рендеринга на стороне сервера с использованием rehydrate вместо render. Это связано с тем, что он должен удалить существующие элементы из DOM и повторно вставить вновь построенное дерево. Для страниц с достаточным содержанием это может быть очень вредно.

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

В конце концов у меня была система, которая «предварительно визуализировала» наши приложения, чтобы обеспечить загрузку первой страницы с богатым содержанием!

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

Стилизованные компоненты

О, как близко я был. Это была чистая случайность, что обновление нашего заголовка страницы включало в себя переход от решения на основе CSS к использованию библиотеки CSS-in-JS, называемой styled-components. Это долго разрабатывалось, и мы реализовали его на других страницах. О чем я не думал, так это о том, как функционируют стилизованные компоненты.

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

Для нашего решения для предварительного рендеринга? Что ж, мы добились того, что помещаем стили в голову без проблем. Это просто дословный вывод того, каким должен быть HTML-код клиента. Однако неожиданным было то, что styled-components не смогли должным образом восстановить взаимосвязь между созданным элементом стиля и последующим элементом стиля, который он создал во время повторной гидратации. Конечным результатом стали два полноценных элемента стиля, в которых были сотни (если не тысячи, учитывая динамический стиль) правила. Это означало, что к каждому элементу применялись повторяющиеся правила CSS. Несмотря на то, что браузер может разрешить их выглядеть правильно, это было неэффективно. Я перепробовал почти все, чтобы решить эту проблему, но это так и не привело к созданию значимо производительного сайта.

Повторно введите NextJS

Это было время Рождества. Моя жена прилетела домой, чтобы увидеть семью, и это были я и собака в течение недели. Что делать разработчику со всем этим свободным временем?

Я положился на свой набор проблем, чтобы попробовать что-то новое, финансы. Я хотел покопаться в NextJS и посмотреть, как он работает под прикрытием, чтобы увидеть, смогу ли я использовать это. renderToString , да… может сработать. Нет, не создавал стили для styled-components. Итак, как они это делают? ServerStyleSheet , хорошо, у styled-components есть решение для этого. Аккуратный. Так что я могу взять это и… о, мне нужно вставить его в голову. Теперь мне нужно просмотреть DOM в узле или что-то в этом роде, чтобы вставить его правильно. Это не кажется ремонтопригодным…

Достаточно разочаровавшись в попытках предварительного рендеринга, я решил сосредоточиться на финансовой стороне, а не на технологиях. Я построил калькулятор чистой выручки, который включал в себя некоторые serverSideProps… только для того, чтобы прочитать о getStaticProps . Как оказалось, вы можете предоставить реквизиты во время сборки для Next. Покопавшись немного дальше, я нашел… решение!

следующий экспорт

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

Единственная «затрата», связанная с этим подходом, заключалась в изменении нескольких ссылок на объекты Javascript, которые не существуют на стороне сервера (а именно, окно, местоположение, документ). Это были относительно простые вещи, и я смог выпустить прототип примерно через неделю.

Это позволило нам использовать все функции рендеринга на стороне сервера (т. е. предоставить регидратируемое дерево стилизованных компонентов и основной контент) и привело к созданию статического HTML-файла, который мы могли загрузить непосредственно в S3, что было существующей архитектурой. .

Кроме того, getStaticPaths позволил нам определять динамические маршруты и создавать страницы, характерные для нашего перечисляемого опыта. Это означало, что мы могли определить один маршрут, скажем, для списка штатов в США, и создать все 50 штатов во время сборки.

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

Ограничения

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

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

Это также означает, что вы должны переосмыслить свои взгляды на определенные проблемы. Мы хотели провести AB-тестирование сценария, включенного или нет в голову, что-то достаточно простое для рендеринга на стороне сервера, но невозможное при статическом рендеринге. Тем не менее, это была проблема, которая существовала и в нашем решении только на стороне клиента! Это немного расстраивает, потому что вы настолько близко к тому, чтобы иметь все необходимое для выполнения задачи!

Полученные результаты!

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

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

Лично я считаю, что большая победа была связана с основными показателями Web Vitals. Это был неожиданный побочный эффект наличия установленного документа при загрузке. Чтобы узнать больше об этом, ознакомьтесь с блогом о том, как статический рендеринг идет рука об руку с производительностью и предоставляет отличную платформу для создания звездных сайтов!