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:
parent
476c1ffc18
commit
bd3c6c2d47
48
apps/web/e2e/smoke.spec.ts
Normal file
48
apps/web/e2e/smoke.spec.ts
Normal 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);
|
||||||
|
});
|
||||||
@ -226,6 +226,11 @@ function attachNovncProxy(server: ViteDevServer | PreviewServer, secret: string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineConfig(({ mode }) => {
|
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 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 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";
|
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: {
|
server: {
|
||||||
host: "0.0.0.0",
|
host: "0.0.0.0",
|
||||||
port: webPort,
|
port: webPort,
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
"vitest": "4.1.11"
|
"vitest": "4.1.11"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "19.2.3",
|
"react": ">=16.8.0",
|
||||||
"react-dom": "19.2.3"
|
"react-dom": "19.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
pnpm-lock.yaml
generated
13
pnpm-lock.yaml
generated
@ -6498,6 +6498,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==}
|
resolution: {integrity: sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==}
|
||||||
engines: {node: '>=14.14'}
|
engines: {node: '>=14.14'}
|
||||||
|
|
||||||
|
fs-extra@11.4.1:
|
||||||
|
resolution: {integrity: sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==}
|
||||||
|
engines: {node: '>=14.14'}
|
||||||
|
|
||||||
fs-extra@7.0.1:
|
fs-extra@7.0.1:
|
||||||
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
|
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
|
||||||
engines: {node: '>=6 <7 || >=8'}
|
engines: {node: '>=6 <7 || >=8'}
|
||||||
@ -11433,7 +11437,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
cross-dirname: 0.1.0
|
cross-dirname: 0.1.0
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
fs-extra: 11.4.0
|
fs-extra: 11.4.1
|
||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
postject: 1.0.0-alpha.6
|
postject: 1.0.0-alpha.6
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@ -16663,6 +16667,13 @@ snapshots:
|
|||||||
jsonfile: 6.2.1
|
jsonfile: 6.2.1
|
||||||
universalify: 2.0.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:
|
fs-extra@7.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.11
|
graceful-fs: 4.2.11
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user