Недавно я пробовал создать кастомный 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 контент.
Почему это работает?