Get CV

Frontend

React admin must not ride Vue SSR

The public site is Vue SSR. The CMS is often React. One webpack graph ships both. TTI on the catalog pays for the editor.

TTI on the public catalog jumped after we added a React CMS to the same webpack graph. This frontend is Vue with SSR, not an SPA. Admin on some products is React. That split is fine. The failure is one bundle. The catalog HTML then downloads a graph that knows dates, tables, and a form toolkit the visitor never opens.

Hydration also fought. Vue printed UTC dates on the server. A shared React island assumed the browser timezone. The markup did not match. The page rendered twice. Users saw a flash and a heavier script. nginx could not cache a public shell that still pulled CMS chunks.

Public pages should hydrate with Vue only.

Public Vue SSR and admin React are two apps. The catalog must not pay for the CMS.
Public Vue SSR and admin React are two apps. The catalog must not pay for the CMS.

Two Vite apps, one cookie

Public stays the Vue SSR app. Admin is a second Vite build on /admin or a second host. Both talk to /api with the Sanctum cookie auth_token. The token never lands in localStorage. React does not get a second session.

Code that both need is types and fetch helpers, not UI. A shared component library that pulls the admin table into the public graph is how the split dies.

I split the Vite configs and watched the public manifest. A date-fns locale pack and a table virtualizer still appeared until a barrel file re-exported an admin widget. Tree-shaking did not save a shared components/index.ts. Public imports a fetch client. Admin imports the table. They do not share a render tree.

Two Vite builds. Same httpOnly cookie. No shared render tree.
Two Vite builds. Same httpOnly cookie. No shared render tree.

What the visitor downloads

The listing payload is one locale. The script is the Vue runtime for that page. React chunks load after a logged-in editor hits admin. nginx can cache the public HTML without the CMS graph. That is the point of SSR here, not a second framework in the footer.

I measured transfer size on /en/notes before login. If React shows up there, the split failed. After login, /admin may load React. The cookie is the same. The document is not. A public HIT in nginx must never include an admin island, or the next anonymous visitor pays for the CMS and may hydrate the wrong tree.

What I took from this

I measure public JS transfer and first hydration of dates, not whether the admin form works. If the catalog pays for a table toolkit, the graphs are still one.

I do not trust a shared UI package or one webpack graph. Types and fetch may be shared. Render trees must not. The Sanctum cookie is the only shared session.

The rule I keep: two Vite apps. Vue hydrates the public site. React loads on admin after login. nginx caches public HTML without CMS chunks.

Back to notes