Imangali-Sauyrbay
@Imangali-Sauyrbay
Увлеченный разработкой софта

ReactDOM renderToString & renderToPipeableStream, как React обробатывает lazy + Suspense на клиенте?

Недавно я пробовал создать кастомный SSR сервер на реакте для php кода, наподобие Inertia.js. Но вот у него проблема в том, что он не поддерживает lazyload.

Казалось бы, вот есть renderToPipeableStream.
Он всё это поддерживает и даже разработчики его рекомендуют.

Но проблема в том что он оставляет fallback и дальше внизу кода (когда lazy код загрузится) добовляет загруженный template и js скрипт что заменяет fallback на template. Что вызывает всё же на миг мерцание.

А учитывая что в php pipeableStream вроде как не поддерживается (из коробки по крайней мере), то пользователь получает как бы всю страницу и при слабом интернете fallback мигает. Напомню что в php запрос на ssr ожидается полностью пока не загрузится всё, что как бы сводит на нет все плюсы renderToPipeableStream с быстрым первым откликом.

И вот я создал такой workaround:
import { ReactElement } from "react";
import { renderToPipeableStream } from "react-dom/server";
import { Writable } from "stream";

export const TestRender = (App: ReactElement) => {
  return new Promise<string>((resolve, reject) => {
    let htmlString = "";
    const writable = new Writable({
      write(chunk, _, callback) {
        htmlString += (chunk as { toString(): string }).toString();
        callback();
      },

      final(callback) {
        resolve(htmlString);
        callback();
      },

      destroy(error, callback) {
        reject(error);
        callback();
      },
    });

    const jsxStream = renderToPipeableStream(App, {
      onAllReady() {
        jsxStream.pipe(writable);
      },

      onShellError(error) {
        resolve(
          `<h2>There was an error while redering on server!<br>${
            (error as Error).message
          }</h2>`,
        );
      },
    });
  });
};


И тут я готовился создать обёртку над React.lazy чтобы передать всё что загружено на фронт и там занятся с preload перед гидрацией.

Я ожидал в консоли увидеть тонны Hydration missmatch error. По крайней мере в 16х версиях React'a так бы и было, но к моему удивлению ReactDOM.hydrate всё нормально обрабатывает. Без каких либо отклонений и missmatch'ов. Он вроде как дожидается пока загрузится lazy и при этом не заменяет то что на html на fallback контент.
Почему это работает?
  • Вопрос задан
  • 159 просмотров
Решения вопроса 1
Imangali-Sauyrbay
@Imangali-Sauyrbay Автор вопроса
Увлеченный разработкой софта
Вопрос закрыт.
Всё работает так как и предполагалось, заменяет на fallback и в консоли куча ошибок.
Просто на локальном и на тестовом сервере всё работало шустро и успевало загружать компонент до рендеринга и было всё ок, кроме медленного продакшна...
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы