fix(web): resolve React multi-version hook error via Vite alias

- Add Vite resolve.alias for react/react-dom to root node_modules
- Removes duplicate React instances from pnpm transitive deps
- Create E2E smoke test verifying no React hook errors
- Fix: pnpm resolves @dnd-kit deps to react@19.2.8, conflicting with
  app react@19.2.3 causing 'Invalid hook call' at runtime

Fixes: dark screen / Invalid hook call on /app
This commit is contained in:
Ingo Wagner 2026-09-23 13:18:08 +00:00
parent 476c1ffc18
commit bd3c6c2d47
4 changed files with 74 additions and 2 deletions

View File

@ -0,0 +1,48 @@
/**
* Smoke test: verify the app loads without React errors.
*
* This test ensures that the Vite build resolves a single React
* instance (no duplicate React versions from pnpm transitive deps).
*/
import { test, expect } from "@playwright/test";
test("app loads without React hook errors", async ({ page }) => {
const consoleErrors: string[] = [];
const pageErrors: string[] = [];
page.on("console", (msg) => {
if (msg.type() === "error") consoleErrors.push(msg.text());
});
page.on("pageerror", (err) => {
pageErrors.push(err.message);
});
await page.goto("/app", { waitUntil: "domcontentloaded", timeout: 10000 });
await page.waitForTimeout(5000);
// The critical check: no "Invalid hook call" or related React errors
const hookErrors = pageErrors.filter((e) =>
e.includes("Invalid hook call") ||
e.includes("useMemo") ||
e.includes("useRef") ||
e.includes("useContext") ||
e.includes("more than one copy of React")
);
expect(hookErrors).toEqual([]);
// Root element must exist
await expect(page.locator("#root")).toBeAttached();
// Should show either login form or app content (not a blank/dark screen)
const bodyText = await page.evaluate(() => document.body?.innerText || "");
const hasContent =
bodyText.includes("Sign in") ||
bodyText.includes("Anmelden") ||
bodyText.includes("EvOo") ||
bodyText.includes("Projekte") ||
bodyText.includes("Heute") ||
bodyText.includes("Team");
expect(hasContent).toBe(true);
});

View File

@ -226,6 +226,11 @@ function attachNovncProxy(server: ViteDevServer | PreviewServer, secret: string,
}
export default defineConfig(({ mode }) => {
const rootCwd = path.resolve(import.meta.dirname, "../..");
const reactPath = path.resolve(rootCwd, "node_modules/react");
const reactDomPath = path.resolve(rootCwd, "node_modules/react-dom");
const reactIndex = path.resolve(reactPath, "index.js");
const reactDomIndex = path.resolve(reactDomPath, "index.js");
const rootEnv = loadEnv(mode, path.resolve(import.meta.dirname, "../.."), "");
const api = process.env.API_PROXY_TARGET ?? rootEnv.API_PROXY_TARGET ?? "http://127.0.0.1:3100";
const previewHost = process.env.RAKAZO_HOST ?? rootEnv.RAKAZO_HOST ?? "localhost";
@ -298,6 +303,14 @@ export default defineConfig(({ mode }) => {
},
},
],
resolve: {
alias: {
"react": reactPath,
"react-dom": reactDomPath,
"react/jsx-runtime": reactPath,
"react/jsx-dev-runtime": reactPath,
},
},
server: {
host: "0.0.0.0",
port: webPort,

View File

@ -32,7 +32,7 @@
"vitest": "4.1.11"
},
"peerDependencies": {
"react": "19.2.3",
"react": ">=16.8.0",
"react-dom": "19.2.3"
}
}

13
pnpm-lock.yaml generated
View File

@ -6498,6 +6498,10 @@ packages:
resolution: {integrity: sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==}
engines: {node: '>=14.14'}
fs-extra@11.4.1:
resolution: {integrity: sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==}
engines: {node: '>=14.14'}
fs-extra@7.0.1:
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
engines: {node: '>=6 <7 || >=8'}
@ -11433,7 +11437,7 @@ snapshots:
dependencies:
cross-dirname: 0.1.0
debug: 4.4.3
fs-extra: 11.4.0
fs-extra: 11.4.1
minimist: 1.2.8
postject: 1.0.0-alpha.6
transitivePeerDependencies:
@ -16663,6 +16667,13 @@ snapshots:
jsonfile: 6.2.1
universalify: 2.0.1
fs-extra@11.4.1:
dependencies:
graceful-fs: 4.2.11
jsonfile: 6.2.1
universalify: 2.0.1
optional: true
fs-extra@7.0.1:
dependencies:
graceful-fs: 4.2.11