Напишите нам прямо сейчас, наши специалисты расскажут об услугах и ответят на все Ваши вопросы.
Напишите нам прямо сейчас, наши специалисты расскажут об услугах и ответят на все Ваши вопросы.
Наш специалист свяжется с Вами, обсудит оптимальную стратегию сотрудничества, поможет сформировать бизнес требования и рассчитает стоимость услуг.
Наш специалист свяжется с Вами, обсудит оптимальную стратегию сотрудничества, поможет сформировать бизнес требования и рассчитает стоимость услуг.
Заполните онлайн-заявку и получите выгодное спецпредложение прямо сейчас.
За вами будет закреплен персональный менеджер, который расскажет о платформе, ответит на все ваши вопросы и сформирует для вас коммерческое предложение.
Наш специалист свяжется с Вами и
обсудит время собеседования.
Кроме того, в доках написано, что он пытается сбросить также буфер веб-сервера (как?).
Второй важный момент: слой БВ является не единственным слоем, в котором буферизуются выводимые данные.
И третье: в зависимости от SAPI, который вы используете (веб или cli), слой БВ может вести себя по-разному.
Ниже представлена схема, которая поможет понять всё вышесказанное:
Здесь мы видим, что для управления выводимыми данными в PHP используется три логических слоя буферизации. Два из них принадлежат тому самому «буферу вывода», а третий — SAPI. Когда поток вывода покидает область PHP, чтобы попасть на нижний уровень архитектуры, «по пути» могут возникнуть новые буферы: буфер терминала, буфер FastCGI, буфер веб-сервера, буфер операционной системы, буферы стеков TCP/IP. Не забывайте об этом. Хотя в рамках данной статьи мы будем говорить только о PHP, в стеке на пути данных к нижнему слою и пользователю встретится ещё немало программных средств.
Важное замечание относительно CLI SAPI: он отключает в PHP любой буфер вывода по умолчанию, присвоив в ini параметру output_buffering значение 0. Так что, пока вы в CLI не пропишете вручную функции ob_(), по умолчанию все выводимые данные будут напрямую попадать в слой SAPI. Более того, в CLI для параметра implicit_flush жёстко указано значение 1. Суть этого параметра разработчики вечно понимают неправильно, хотя код говорит совершенно недвусмысленно: когда implicit_flush имеет значение 1, буфер слоя SAPI сбрасывается при каждой записи. То есть каждый раз, когда вы записываете данные для вывода с помощью CLI SAPI, они немедленно отправляются на нижний уровень, где записываются в виде stdout, а потом сбрасываются.
Стандартный PHP-слой буферизации вывода
Если вы используете SAPI не так, как CLI, а например, PHP-FPM, то можете поэкспериментировать с тремя параметрами в ini, имеющими отношение к буферу:
— output_buffering
— implicit_flush
— output_handler
Обратите внимание, что использование с ними ini_set() не даст никакого эффекта, поскольку их значения считываются в момент запуска PHP, до того, как он может запустить какой-либо скрипт. Если использовать ini_set() с любым из этих параметров, то он меняет значение, однако оно уже нигде не будет использоваться. Слишком поздно — слой БВ уже запущен и активен. Изменить эти параметры можно, отредактировав php.ini или применив ключ –d к бинарнику PHP.
По умолчанию в php.ini, идущем в составе поставки PHP, output_buffering присвоено значение «4096» (байт). Если вы не используете php.ini (или запускаете PHP с ключом –n), то значением по умолчанию будет «0», то есть отключено. Если захардкодить значение «On», то будет назначен стандартный размер буфера вывода (16 КБ).
Как вы уже, наверное, догадались, использование буфера для вывода в веб-окружении благотворно влияет на производительность. Начальных 4 КБ вполне достаточно, ведь это означает, что вы можете записать до 4096 ASCII-символов, пока PHP не начнёт взаимодействовать с нижерасположенным слоем SAPI. В условиях веба отправка данных побайтно, напротив, производительность не улучшает. Гораздо лучше, если сервер отправляет весь контент скопом или большими частями. Чем реже уровни обмениваются данными, тем лучше с точки зрения производительности. Поэтому обязательно используйте буфер вывода. PHP отправит его содержимое в конце запроса и вам для этого ничего не придётся делать.
В предыдущей главе я упоминал об implicit_flush в контексте CLI. В случае с любым другим SAPI implicit_flush изначально отключён. Это хорошо, поскольку вряд ли вы будете приветствовать сброс SAPI сразу же после записи в него. Для протокола FastCGI сброс можно сравнить с завершением и отправкой пакета после каждой записи. Однако лучше сначала полностью заполнить буфер FastCGI, а уже потом слать пакеты. Если вам нужно вручную сбросить буфер SAPI, используйте для этого PHP-функцию flush(). Для сброса после каждой записи, как уже говорилось выше, можно использовать параметр implicit_flush в php.ini. Как вариант — однократный вызов PHP-функции ob_implicit_flush().
К содержимому буфера до его вывода можно применять callback output_handler. Вообще, благодаря расширениям PHP нам доступно немало callback-ов (пользователи тоже могут их писать, об этом я расскажу в следующей главе).
— ob_gzhandler: компрессия вывода с помощью ext/zlib
— mb_output_handler: перевод кодировки символов с помощью ext/mbstring
— ob_iconv_handler: перевод кодировки символов с помощью ext/iconv
— ob_tidyhandler: очистка вывода HTML с помощью ext/tidy
— ob_[inflate/deflate]_handler: компрессия вывода с помощью ext/http
— ob_etaghandler: автоматическая генерация заголовков ETag с помощью ext/http
Вы можете использовать только один callback, который получит содержимое буфера и сделает полезные преобразования для вывода, что не может не радовать. Для анализа данных, которые PHP отправляет веб-серверу, а тот отсылает пользователю, полезно использовать callback-и буфера вывода. Кстати, под «выводом» я подразумеваю как заголовок, так и тело. HTTP-заголовки тоже являются частью слоя буферизации вывода.
Тело и заголовки
Когда вы используете буфер вывода (неважно, пользовательский или один из стандартных), то можете отправлять HTTP-заголовки и содержимое как угодно. Любой протокол требует сначала отсылать заголовок, а уже потом тело, но за вас это сделает сам PHP, если вы используете слой БВ. Любая PHP-функция, работающая с заголовками (header(), setcookie(), session_start()), фактически использует внутреннюю функцию sapi_header_op(), которая просто заполняет буфер заголовков. Если после этого записать выводимые данные, например, с помощью printf(), то они запишутся в один из соответствующих буферов вывода. И во время отправки буфера PHP сначала
отсылает заголовки, а уже потом тело. Если вам не нравится такая забота со стороны PHP, то придётся вообще отключить слой БВ.
Пользовательские буферы вывода
Давайте разберём на примерах, как это работает, и что вы можете сделать. Имейте в виду, что если вы хотите использовать стандартный PHP-слой буферизации, то не сможете воспользоваться CLI, поскольку он отключается как слой.
Ниже приведён пример работы со стандартным PHP-слоем с помощью внутреннего веб-сервера SAPI:
Мы запустили PHP со стандартным буфером вывода на 32 байта, после чего сразу же записали в него 31 байт, пока не включилась задержка исполнения. Экран чёрный, пока ничего не отправлено. Затем действие sleep() заканчивается, и мы записываем ещё один байт, тем самым полностью заполняя буфер. После этого он сразу же сбрасывает себя в буфер слоя SAPI, а тот сбрасывает себя в вывод, поскольку implicit_flush имеет значение 1. На экране появляется строка aaaaaaaaaa{31 раз}b, после чего опять начинает действовать sleep(). По его завершении пустой 31-байтный буфер заполняется одним-единственным байтом, после чего PHP завершается и сбрасывает буфер. На экране появляется с.
Так выглядит работа стандартного PHP-буфера без вызова каких-либо ob-функций. Не забудьте, что это именно стандартный буфер, то есть он уже имеется в наличии (только нельзя использовать CLI).
Теперь с помощью ob_start() можно запускать пользовательские буферы, причем столько, сколько нужно, пока память не закончится. Каждый буфер будет помещаться за предыдущим и немедленно сбрасываться в следующий, что постепенно приведёт к переполнению.
Устройство буферизации вывода
Как я уже говорил, начиная с версии 5.4 механизм буферизации вывода был полностью переписан. До этого код был очень неаккуратным, многие вещи сделать было непросто, часто возникали баги. Подробнее об этом можно почитать по ссылке. Новая кодовая база получилась гораздо чище, лучше организована, появились новые возможности. Правда, совместимость с версией 5.3 обеспечивается лишь отчасти.
Пожалуй, одним из самых приятных нововведений стало то, что расширения теперь могут объявлять свои callback-и буфера вывода, конфликтующие с callback-ами других расширений. Ранее было невозможно полностью управлять ситуациями, когда другие расширения тоже могли декларировать свои callback-и.
Вот небольшой пример на скорую руку, демонстрирующий, как можно зарегистрировать callback, преобразующий данные в верхний регистр:
Подводные камни
По большей части они задокументированы, некоторые из них вполне очевидны, а некоторые не слишком. К очевидным можно отнести, например, то, что не следует вызывать какие-либо функции буфера изнутри callback-а БВ, также как и записывать выводимые оттуда данные.
К неочевидным подводным камням можно отнести то, что некоторые функции PHP используют внутренний БВ для самих себя, заполняя его, а затем сбрасывая или возвращая. При этом следующий буфер ставится в стек. К подобным функциям относятся print_r(), highlight_file() и SoapServer::handle(). Не следует использовать их изнутри callback-а БВ – это может привести к непредсказуемым последствиям.
Заключение
Слой вывода можно сравнить со своеобразной сетью, которая улавливает любые возможные «утечки» вывода из PHP и сохраняет их в буфере заданного размера. Когда буфер заполняется, он сбрасывается (записывается) в нижний уровень, если таковой есть. Как минимум в самый нижний из имеющихся — в буфер SAPI. Пользователи могут управлять количеством буферов, их размером и операциями, которые могут быть разрешены в каждом слое буфера (очистка, сброс или удаление). Это очень гибкий инструмент, позволяющий, например, создателям библиотек и фреймворков полностью контролировать поток вывода, направляя его в глобальный буфер и обрабатывая там. При этом PHP сам регулирует порядок отправки заголовков и потока вывода.
По умолчанию имеется один буфер вывода, управляемый тремя настройками в ini-файле. Он устроен так, чтобы реже осуществлять операции записи и не слишком часто обращаться к слою SAPI, а значит и к сети. Это сделано для улучшения общей производительности. Также расширения PHP могут декларировать callback-и, запускаемые в каждом буфере — например, для компрессии данных, замены строк, управления HTTP-заголовками и многих других операций.
— Вы можете заставить PHP сохранять все выходные данные в буфер и выводить их все сразу, повышая производительность сети.
— В определенных ситуациях вы можете получить доступ к содержимому буфера, не отправляя его обратно в браузер.
Рассмотрим этот пример:
Приведенный выше пример преобразует выходные данные в переменную вместо отправки их в браузер. output_buffering по умолчанию отключен.
— Вы можете использовать буферизацию вывода в ситуациях, когда вы хотите изменить заголовки после отправки содержимого.
Рассмотрим этот пример:
Преимущества буферизации вывода для веб-разработчиков
— Включение только буферизации вывода уменьшает количество времени, необходимое для загрузки и рендеринга нашего HTML, потому что он не отправляется в браузер по частям, поскольку PHP обрабатывает HTML.
— Все необычные вещи, которые мы можем делать со строками PHP, теперь мы можем делать со всей нашей HTML-страницей как с одной переменной.
— Если вы когда-либо сталкивались с сообщением «Предупреждение: невозможно изменить информацию заголовка — заголовки уже отправлены (output)» при настройке файлов cookie, вы будете рады узнать, что буферизация вывода — это ваш ответ.
Сам термин «резиновая верстка» появился вместе с концепцией фиксированной верстки из-за тлетворного влияния Запада :) В верстку хлынуло много новичков, которые тащили в рот всякую гадость читали первые попавшиеся руководства, разумеется западные, потому что они там вона какие умные, куда нам до них, какой смысл читать наши учебники. А во всех адекватных российских руководствах фиксированная верстка под конкретное разрешение всегда оценивалась однозначно как грубейшая ошибка.
Резиновая вёрстка — это когда вы задаёте всему макету и отдельным его частям не фиксированную ширину, а эластичную — в процентах. За исключением минимальной и максимальной ширины. Высоту в вебе в принципе не принято задавать — обычно она подстраивается под содержимое. Фикс или резина? — спрашивали верстальщики 2000-х про макет и втайне надеялись на второе, поинтереснее. Сейчас сложно представить, но когда-то это было прорывной идеей, которая усложнила вёрстку, но сделала первый шаг в правильном пути.
Таблицы для раскладки ушли, а резиновая вёрстка осталась. Если у вас эластичные флоаты, флексы… да хоть гриды! — это всё равно резиновая вёрстка. Но если ширина внешнего контейнера зафиксирована — это уже фикс, сколько бы ни было резины внутри. Чуть более универсальный фикс, но всё равно. В общем, главное чтобы сайт двигался так или иначе вместе с окном, а не торчал кирпичом где-то в центре или с краю.
Когда расширился круг устройств с интернетом и появились первые мобильные браузеры — встала задача как-то подстраиваться под них. Простая резина здесь уже не справлялась — нужно было переписывать стили. Одной из первых, в 2006 году появилась техника адаптивной раскладки Марка ван ден Доббельстина. В статье на A List Apart Марк предложил добавлять классы при загрузке или ресайзе окна и на каждый диапазон вешать стили. До первой реализации медиавыражений в Safari оставалось два года.
Когда в начале десятых годов появилось для чего адаптировать и чем адаптировать — мобильные браузеры и медиавыражения — вышли книги, давшие названия подходам: «Адаптивный веб-дизайн» Аарона Густавсона и «Отзывчивый веб-дизайн» Итана Маркота. Подходы Аарона и Итана продолжали идеи Марка, но с более современными технологиями и несколько отличались направлением мысли.
«Адаптивный веб-дизайн» Аарона предлагал гибко адаптировать сайты к возможностям устройств и браузеров. Важной частью этой философии был ненавязчивый JavaScript с прогрессивным улучшением — и всё это поверх семантической разметки. Хотя Аарон писал не совсем об этом, сегодня принято считать, что главное в адаптивной вёрстке — привязка к конкретным разрешениям и устройствам. Стили переключаются от одного брейкпоинта к другому, то есть у вас есть фиксированные макеты для iPad и iPhone, а то, что между ними вас не волнует.
«Отзывчивый веб-дизайн» Итана ставил во главу три вещи: резиновый макет, гибкие картинки и медиавыражения. Все размеры и отступы Итан предлагал указывать в процентах с сумасшедшими дробями для точности. Отличительной чертой подхода стало плавное изменение сайта, с ориентацией не на конкретные устройства, а на содержимое. То есть ваш резиновый макет хорошо выглядит не только на iPhone и iPad, но и в любой точке между ними.
Чуть позже Итан сформулировал ещё один важный принцип в книге «Сначала мобильные». Если до тех пор отправной точкой для адаптации вёрстки служила десктопная версия, то он предложил перевернуть схему и начинать с мобильной версии, а потом её улучшать. Почему так? Потому, что усложнять простое проще, чем упрощать сложное. Вдуматесь! А ещё потому, что нет соблазна просто спрятать сложно адаптируемое и обделить мобильных пользователей.
Ну как, стало понятно? Вот адаптивная, вот отзывчивая… М-м, нет, не очень. Из-за путаницы между техникой адаптивной раскладки и философией адаптивного веб-дизайна, из-за того, что все эти подходы прекрасно сочетаются и уже не проследить чёткую границу между ними — из-за всего этого, я плюнул на терминологическую чистоту и стал называть всё это адаптивным дизайном или адаптивной вёрсткой. Это понятие всегда было достаточно широким, чтобы вместить все остальные способы.
Да и принцип дискретной адаптации от размеров устройств и без резины имел смысл лет 10 назад. При сегодняшнем разнообразии устройств полагаться на конкретные размеры и жёстко переключаться между ними — значит однажды очень больно промахнуться. Притом, никто вам не мешает при полностью резиновой вёрстке дописывать адаптацию под нужные разрешения.
Ну и как теперь верстать? Просто! Сначала делаете мобильный резиновый макет, который хорошо вписывается в небольшие устройства. А когда размеры экрана или окна начинают расти — начинаете использовать появившееся пространство для улучшения интерфейса. Появляется боковая колонка, вторая, растут размеры картинок и подгружаются новые разрешения и так далее. То есть медиавыражения меняют стили не когда вы дошли до экрана самого модного телефона, а когда это нужно для содержимого сайта и удобства пользователя. Мы именно так и учим делать на интенсиве по продвинутой вёрстке.
Чтобы сделать хороший адаптивный сайт, нужно понимать много нюансов: вьюпорт, медиавыражения, адаптивные картинки и другое.
Важно понимать, что универсального решения не существует. Речь идёт скорее о выборе оптимального решения, которое будет соответствовать конкретным потребностям вашего бизнеса и предоставит все необходимые инструменты для успешной реализации проектов.
Компании необходимо быть в курсе последних тенденций в выбранной области, чтобы обеспечить актуальность и безопасность проекта.
Любая из упомянутых технологий может стать подходящим решением для конкретных проектов. Главное, чтобы выбор был обоснован необходимыми характеристиками и преимуществами, которые получит ваш продукт.
Некоторые технологии становятся лидерами рынка и получают более широкое распространение, например, Node.js, ASP.NET и другие. Однако окончательное решение зависит от потребностей и предпочтений команды в отношении Node.js или его альтернатив.
Собственно, а существуют ли исследования о том, на сколько подобная экономия на «переключении задач» эффективна? Вот почему-то мне кажется, что значительное количество одновременно обслуживаемых клиентов у Node будет, если эти клиенты в основной массе простаивают (затраты на переключение задачи в многопоточной реализации сопоставимы с затратами на выполнение полезного действия), но в случае, когда все клиенты работают (затраты на переключения задачи малы по сравнению с затратами на выполнение полезного действия) эффект будет минимальный (если вообще будет).
Если внешняя система не поддерживает неблокирующий I/O, нода использует пул потоков, о котором в статье как раз говорится.
Тем не менее, совсем недавно мне рассказывали, что неблокирующим образом nodejs умеет обращаться только к MongoDB, а когда используются «старые» реляционные БД (Oracle, Postgres), то обращение к ним из nodejs все равно блокирует поток, потому что для них нету асинхронных неблокирующих драйверов (какие есть для монги). Может быть, кто-нибудь из экспертов откомментирует, так это или не так?
Я работаю с платформой Node.js более 6 лет и я на самом деле люблю её.
Мир до Node.js
Многопоточный сервер
Веб-приложения, написанные следуя клиент/серверной архитектуре, работают по следующей схеме — клиент запрашивает нужный ресурс у сервера и сервер отправляет ресурс в ответ. В этой схеме сервер, ответив на запрос, прерывает соединение.
Такая модель эффективна поскольку каждый запрос к серверу потребляет ресурсы (память, процессорное время и т.д.). Для того чтобы обрабатывать каждый последующий запрос от клиента, сервер должен завершить обработку предыдущего.
Значит ли это, что сервер может обрабатывать только один запрос за раз? Не совсем! Когда сервер получает новый запрос он создаёт отдельный поток для его обработки.
Поток, если простыми словами, это время и ресурсы, что CPU выделяет на выполнение небольшого блока инструкций. С учётом сказанного, сервер может обрабатывать несколько запросов одновременно, но только по одному на поток. Такая модель так же называться thread-per-request model.
Для обработки N запросов серверу нужно N потоков. Если сервер получает N+1 запросов, тогда он должен ждать пока один из потоков не станет доступным.
На рисунке выше, сервер может обрабатывать до 4 запросов (потоков) единовременно и когда он получает следующие 3 запроса, эти запросы должны ждать пока любой из этих 4 потоков не станет доступным.
Один из способов избавиться от ограничений — добавить больше ресурсов (памяти, ядер процессора и т. д.) на сервер, но это не самое лучшее решение….
И, конечно, не забываем о технологических ограничениях.
Блокирующий ввод/вывод
Ограниченное число потоков на сервере не единственная проблема. Возможно, Вам стало интересно почему один поток не может обрабатывать несколько запросов одновременно? всё из-за блокирующих операций ввода/вывода.
Допустим, Вы разрабатываете онлайн магазин и Вам нужна страница где пользователь может просматривать список всех товаров.
Пользователь стучится на yourstore.com/products и сервер рендерит HTML файл со всеми продуктами с базы данных в ответ. Совсем не сложно, да?
Но, что же происходит за кулисами?
— Когда пользователь стучится на /products особый метод или функция должна выполниться, что бы обработать запрос. Маленький кусочек кода (Ваш или фреймворка) анализирует URL-адрес запроса и ищет подходящий метод или функцию. Поток работает.
— Теперь нужный метод или функция выполняться, так как и в первом пункте — поток работает.
— Так как Вы хороший разработчик, Вы сохраняете все системные логи в файл, ну и конечно же, что бы быть уверенными, что роутер выполняет нужный метод/функцию — Вы так же логируете строку «Method X executing!!». Но всё это блокирующие операции ввода/вывода. Поток ждёт.
— Все логи сохранены и следующие строки функции выполняются. Поток работает снова.
— Время обращаться к базе данных и получать все продукты – простой запрос, вроде SELECT * FROM products, выполняет свою работу, но угадайте что? Да-да, это блокирующая операция ввода/вывода. Поток ждёт.
— Вы получили массив или список всех продуктов, но убедитесь, что Вы всё это залогировали. Поток ждёт.
— Теперь у Вас есть все продукты и пришло время рендерить шаблон для будущей страницы, но перед этим Вам нужно их прочитать. Поток ждёт.
— Движок рендеринга делает свою работу и шлёт ответ клиенту. Поток работает снова.
— Поток свободен, словно птица в небесах.
Операции сети и чтения с диска слишком медленные. Представьте сколько запросов или обращений к внешним API ваша система могла бы обработать за это время.
Подбивая итоги: операции ввода/вывода заставляют поток ждать и тратить ресурсы впустую.
Node.js мощная технология, которую стоит изучить при возможности.
Моя личная рекомендация – всегда будьте любопытными! Если Вы знаете, как что-то работает изнутри, Вы сможете работать с этим более эффективно.
Консультант по SEO/a11y на проводе. Не могу передать, сколько раз я сталкивался с SEO-специалистами и/или клиентами, которые клялись, что вам нужен SSR, чтобы поисковые роботы правильно индексировали ваш SPA. Это не так уже почти десять лет. Есть множество гигантских Ecommerce брендов, которые используют SPA уже много лет и имеют чрезвычайно высокие показатели SEO (на ум приходит Walmart). Анекдотично, я лично руководил конверсией сайта .NET MVC Ecommerce со 100 000+ SKU на Vue 2 SPA, и мы действительно увидели улучшение наших SEO-метрических показателей. Это было 8 лет назад.
Мы обычно исходим из следующих соображений:
— Является ли HTML семантическим и доступным (a11y)?
— Предоставляется ли схема через JSON+LD и/или теги?
— Соответствуют ли основные показатели сайта (core web vitals) требованиям?
— Требует ли контент действий пользователя перед загрузкой? Например, если навигация по категориям находится в меню, который по умолчанию скрыт, то такая навигация может не индексироваться. В общем случае, если что-то может быть сделано через SSR, то это же также может быть отображено на стороне клиента и проиндексировано.
Все это Google укажет в Search Console / Lighthouse, чтобы сообщить вам о наличии проблемы.
I keep reading advice about how necessary it is to use SSR for SEO, but that advice does not match my personal experience. That advice was probably valid years ago, before search engines became good at running Javascript.
From what I have seen personally, Bing is pretty good at running Javascript too.
Ах да, Angular Universal с ним не дружит, с ISR. Ну тогда вам придётся выбирать между Next.js или Nuxt.js (Ещё конечно можно использовать VuePress или VitePress, на них можно не только документации делать, ну и вполне себе хорошие сайты с динамическими компонентами и всё это хорошо для SEO — проверял)
Кстати, это не сарказм, это опыт, я попробовал, и у меня есть результаты. Да и не только у меня, у всех кто это пробовал тоже есть положительные результаты. Для профи там ничего сложного это всё настроить.
Если title статичный, значит там что-то с промисами начудили, или забыли убрать статические данные.
SEO оптимизация — это что-то среднее между backend и frontend, поэтому фронтенд разработчику сложно настроить семантическое ядро и учесть другие фишки и инструменты SEO. Знание OpenGraph и Schema.org — это далеко не всё. Я уже молчу про генерацию robots.txt и sitemap.xml (Столько тонкостей надо знать, это кстати легче поймёт бэкендер)
Про бэкенд я услышал только про PHP/ — так, уровень знаний мне понятен, стало очевидно, почему SSR для автора проблема. Если знать как работает контекст в динамических страницах SSR, то проблемы автоматически улетучиваются, и в настройках можно явно указать что показать, если такой страницы не будет, можно показать ошибку 404 или не отображать страницу вовсе, или будет ошибка при компиляции. Жаль что не упомянули про Rust, Java, С#, Python — на них же тоже можно сделать backend
Мне на самом деле сложно судить без Code Review
(чтобы понять почему автор не возлюбил SSR)
А вообще забавные кульбиты прогресс вытворяет — вот вам технология, которая может полноценно отображать весь контент без перезагрузки страницы… а, стоп! вам нужна статика для поисковых ботов? Тогда держите новую технологию, которая позволяет одностраничное приложение распарсить в виде многостраничной статики. Что, опять не так? Теперь нужна технология, которая SSR будет обратно в SPA собирать?..
И после каждой такой неоднозначной технологии начинаются холивары под лозунгом «даёшь всё новое!». Что, вы собрались манипулировать DOM во Vue-приложении? Это совершенно не так работает — уясните для себя что такое «декларативная отрисовка». Вы совершенно не понимаете методологии реактивных фреймворков!
Выходит Vue3 — Держите то, о чём вы так долго просили — ref-ссылки для манипуляции DOM…
Однако, сгенерировать и вставить несколько строчек в head секцию html страницы намного проще, и вполне реализуется одним скриптом на Python, PHP, вместо поднимания сервера на Node.js.
Ну в очередной раз можно посоветовать использовать две версии сайта — SPA для людей, и с простой серверной генерацией — для поисковых роботов. Они это разрешают.
Результат: Google — хорошо, Yandex — не очень.
SPA приложения получают данные и отображают их на странице асинхронно, через AJAX запросы. В связи с чем, для индексации таких сайтов поисковик должен понимать JavaScript и грузить и обрабатывать не только основной HTML страницы, как он это делал много лет, но и сопутствующие ресурсы.
Это требует значительно больше усилий на стороне поисковика (на порядки больше обычного html парсинга) из-за необходимости запускать виртуальный браузер для каждой такой страницы. Потому данная техника очень долго была недоступна, в связи с чем сайтам, жаждущим быть проиндексированным, нужно было применять обходные маневры, как то:
— SSG
— Prerendering
— SSR (с Node.js и гидратацией — Nuxt, Next.js и др.)
— Отдельная облегченная версия сайта для поисковиков с генерацией контента на сервере и SPA для людей
— Обычная серверная генерация (PHP и пр.)
Основная причина делать сайты как гибридные SSR — требование иметь SEO. Разрабатывать SPA приложения намного легче, комфортней (DX), они поддерживаемей и расширяемей, их разработка дешевле и быстрей. Поэтому SEO оптимизация — давняя боль фронтенд разработки.
С целью проверки текущего положения дел у поисковиков в плане понимания JavaScript-a при индексации страниц было проведено два эксперимента. Первый со страницей на голом JavaScript и запросами на fetch(), и второй — простое Vue приложение.
Несмотря на достаточно оптимистичные результаты, нужно отметить, что например мой рабочий (уже не такой элементарный) Vue 3 проект на Google не индексируется, то есть, успешность всего этого зависит, естественно, от логики приложения, а также, вероятно, от используемых библиотек.
Требуется проверка работы других фронтенд фреймворков и каждого приложения индивидуально, но поддержка индексирования SPA у Google уже на очень приличном уровне. У Yandex — нет.
В англоязычном сегменте интернета при опоре на Google использование SSR становится не обязательным.