Files
2026-05-27 23:47:53 +01:00

60 lines
2.7 KiB
TypeScript

import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
root: __dirname,
server: {
port: 5273,
strictPort: true,
host: "127.0.0.1",
},
plugins: [react(), ssrMiddlewarePlugin()],
optimizeDeps: {
// Force pre-bundle of the workspace package so Vite resolves the
// exports map correctly the first hit.
include: ["@suaveplan/react-i18n", "@suaveplan/i18n"],
},
});
/**
* Adds a `/ssr/:locale` endpoint that renders the React tree on the
* server, inlines the markup into the HTML template, and adds a tiny
* bootstrap script that flips `entry-client.tsx` into hydration mode.
*
* This is the SSR scenario surface exercised by the Playwright spec —
* the regular `/` route serves the standard CSR build.
*/
function ssrMiddlewarePlugin(): import("vite").Plugin {
return {
name: "react-i18n-e2e-ssr",
configureServer(server) {
server.middlewares.use(async (req, res, next) => {
if (req.url === undefined || !req.url.startsWith("/ssr/")) {
next();
return;
}
try {
const localeFromUrl = req.url.replace(/^\/ssr\//, "").split("?")[0] ?? "";
const locale = decodeURIComponent(localeFromUrl);
const templatePath = `${__dirname}/index.html`;
const fs = await import("node:fs/promises");
const rawTemplate = await fs.readFile(templatePath, "utf8");
const transformed = await server.transformIndexHtml(req.url, rawTemplate);
const mod = await server.ssrLoadModule("/src/entry-server.tsx");
const renderFn = (mod as { render: (l: string) => { html: string; locale: string } }).render;
const { html, locale: resolvedLocale } = renderFn(locale);
const bootstrap = `<script>window.__SUAVEPLAN_E2E_INITIAL_LOCALE__=${JSON.stringify(resolvedLocale)};window.__SUAVEPLAN_E2E_SSR__=true;</script>`;
const finalHtml = transformed
.replace(`<div id="root"></div>`, `<div id="root">${html}</div>${bootstrap}`)
.replace(`<html lang="en-GB" dir="ltr">`, `<html lang="${resolvedLocale}" dir="${resolvedLocale.startsWith("ar") ? "rtl" : "ltr"}">`);
res.statusCode = 200;
res.setHeader("Content-Type", "text/html");
res.end(finalHtml);
} catch (error) {
next(error as Error);
}
});
},
};
}