perf: remove react-dom/server from client bundle

Replace ReactDOMServer.renderToString with a client-side helper using
createRoot + flushSync to render small icon elements to HTML strings.

react-dom/server pulls the entire server rendering runtime into the
client JS bundle. Since this file is imported by the main chat
component (thread.tsx), the extra weight hits every chat page load.

react-dom and react-dom/client are already in the client bundle, so
the replacement adds zero new bundle weight.

Fixes #1189
This commit is contained in:
barry3406 2026-04-09 05:10:16 -07:00
parent 7c61668823
commit d9841cb798

View file

@ -10,11 +10,21 @@ import {
useRef,
useState,
} from "react";
import ReactDOMServer from "react-dom/server";
import { flushSync } from "react-dom";
import { createRoot } from "react-dom/client";
import { getConnectorIcon } from "@/contracts/enums/connectorIcons";
import type { Document } from "@/contracts/types/document.types";
import { cn } from "@/lib/utils";
function renderToHTML(element: React.ReactElement): string {
const container = document.createElement("div");
const root = createRoot(container);
flushSync(() => root.render(element));
const html = container.innerHTML;
root.unmount();
return html;
}
export interface MentionedDocument {
id: number;
title: string;
@ -213,7 +223,7 @@ export const InlineMentionEditor = forwardRef<InlineMentionEditorRef, InlineMent
const iconSpan = document.createElement("span");
iconSpan.className = "flex items-center text-muted-foreground";
iconSpan.innerHTML = ReactDOMServer.renderToString(
iconSpan.innerHTML = renderToHTML(
getConnectorIcon(doc.document_type ?? "UNKNOWN", "h-3 w-3")
);
@ -222,7 +232,7 @@ export const InlineMentionEditor = forwardRef<InlineMentionEditorRef, InlineMent
removeBtn.className =
"size-3 items-center justify-center rounded-full text-muted-foreground transition-colors";
removeBtn.style.display = "none";
removeBtn.innerHTML = ReactDOMServer.renderToString(
removeBtn.innerHTML = renderToHTML(
createElement(X, { className: "h-3 w-3", strokeWidth: 2.5 })
);
removeBtn.onclick = (e) => {