60 lines
2.7 KiB
TypeScript
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);
|
|
}
|
|
});
|
|
},
|
|
};
|
|
}
|