-
Notifications
You must be signed in to change notification settings - Fork 78
feat(FR-2606): restore BUI i18n context isolation under Vite dep optimization #6870
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
graphite-app
merged 1 commit into
main
from
04-20-feat_fr-2606_restore_bui_i18n_context_isolation_under_vite_dep_optimization
Apr 30, 2026
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| import { test, expect } from '@playwright/test'; | ||
|
|
||
| /** | ||
| * Smoke test for the Vite PoC dev server (FR-2606). | ||
| * Runs against `pnpm --prefix ./react run vite:dev` on port 9081. | ||
| * | ||
| * Not part of CI. Kept on the PoC branch as a reproducer and regression | ||
| * guard for the i18n-context-isolation fix (see react/vite-shims/). | ||
| */ | ||
|
nowgnuesLee marked this conversation as resolved.
nowgnuesLee marked this conversation as resolved.
|
||
| test('Vite PoC: app mounts at :9081 with host i18n translations rendered', async ({ | ||
| page, | ||
| }) => { | ||
| test.skip( | ||
| !!process.env.CI || !process.env.VITE_POC_SMOKE, | ||
| 'Local opt-in smoke test for a separately started Vite dev server (set VITE_POC_SMOKE=1 to run)', | ||
| ); | ||
|
|
||
| // Pre-existing warnings unrelated to the Vite migration. Keep this list | ||
| // short — new entries that look Vite-specific should fail the test. | ||
| const KNOWN_PREEXISTING_WARNINGS = [ | ||
| // react-dom warns about some antd CSS-in-JS vendor prefixes under React 19. | ||
| 'Unsupported style property %s. Did you mean %s? -webkit-app-region', | ||
| // antd v6 deprecation notice that is tracked independently. | ||
| 'antd: Dropdown', | ||
| ]; | ||
|
|
||
| const pageErrors: string[] = []; | ||
| const networkFailures: Array<{ url: string; status: number }> = []; | ||
| const filteredErrors: string[] = []; | ||
|
|
||
| page.on('console', (msg) => { | ||
| if (msg.type() !== 'error') return; | ||
| const text = msg.text(); | ||
| if (KNOWN_PREEXISTING_WARNINGS.some((k) => text.includes(k))) return; | ||
| filteredErrors.push(text); | ||
| }); | ||
| page.on('pageerror', (err) => { | ||
| pageErrors.push(`${err.message}\n${err.stack ?? ''}`); | ||
| }); | ||
| page.on('response', (resp) => { | ||
| if (resp.status() >= 400) { | ||
| networkFailures.push({ url: resp.url(), status: resp.status() }); | ||
| } | ||
| }); | ||
|
|
||
| await page.goto('http://127.0.0.1:9081/', { waitUntil: 'domcontentloaded' }); | ||
|
nowgnuesLee marked this conversation as resolved.
|
||
|
|
||
| // Wait for React to mount the login form. | ||
| await page | ||
| .getByRole('button', { name: /session|api|login/i }) | ||
| .first() | ||
| .waitFor({ timeout: 15_000 }); | ||
|
|
||
| const bodyText = await page.evaluate(() => document.body.innerText ?? ''); | ||
|
|
||
| // The regression the shim fix targets: host app keys (`login.X`) were | ||
| // rendering as raw strings instead of resolved translations because | ||
| // BUI's <I18nextProvider> was leaking into the host tree under Vite's | ||
| // deduped module graph. Asserting that the rendered text does NOT | ||
| // contain raw keys is the core regression guard. | ||
| expect( | ||
| bodyText, | ||
| 'host i18n translations must be resolved, not rendered as keys', | ||
| ).not.toMatch(/\blogin\.[A-Za-z]+/); | ||
|
|
||
| // A few positive-example translations that should appear on the login | ||
| // page in English. (If the page adds/removes these someday, adjust the | ||
| // list — the negative match above is the primary check.) | ||
| expect(bodyText).toMatch(/Forgot password\?/); | ||
| expect(bodyText).toMatch(/Sign up/); | ||
|
|
||
| expect(pageErrors, 'no uncaught page errors').toEqual([]); | ||
| expect(networkFailures, 'no failed network requests').toEqual([]); | ||
| expect( | ||
| filteredErrors, | ||
| 'no console errors beyond the known-pre-existing set', | ||
| ).toEqual([]); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| // ESM shim for `use-sync-external-store/shim` (CJS-only export path). | ||
| // | ||
| // Why this exists: the Vite PoC excludes `react-i18next` from dep | ||
| // optimization (to preserve two physical copies for BUI i18n context | ||
| // isolation). `react-i18next`'s ESM bundle imports | ||
| // `useSyncExternalStore` from `use-sync-external-store/shim`, which is a | ||
| // CJS file with `process.env.NODE_ENV` branching and `require(...)` | ||
| // dispatch. When its parent is excluded, Vite's optimizer doesn't | ||
| // transform it, and the browser fails to import it as ESM. | ||
| // | ||
| // This shim re-exports React's native `useSyncExternalStore` (stable | ||
| // since 18.0). The WebUI targets React 19.x, so the shim package's | ||
| // React-17-compat polyfill is not needed — the native hook is identical | ||
| // in behaviour for our use cases. | ||
| export { useSyncExternalStore } from 'react'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| // ESM shim for `void-elements` (CJS-only package). | ||
| // | ||
| // Why this exists: the Vite PoC excludes `react-i18next` from dep | ||
| // optimization so two physical copies can exist (one per pnpm peer-version | ||
| // store path) — that's what keeps BUI's `<I18nextProvider>` context | ||
| // isolated from the host tree. The side effect is that | ||
| // `html-parse-stringify`'s ESM file does `import e from "void-elements"`, | ||
| // and `void-elements@3.1.0` is pure CJS (`module.exports = {...}`, no ESM | ||
| // variant). When its parent is excluded, Vite's optimizer never converts | ||
| // this leaf to ESM — browsers then error with | ||
| // "does not provide an export named 'default'". | ||
| // | ||
| // This shim replaces the import entirely. `void-elements` is a plain | ||
| // lookup object of HTML void-element tag names; reproducing it as ESM | ||
| // is trivial and avoids running any CJS interop at all. | ||
| // | ||
| // Kept in sync with node_modules/.pnpm/void-elements@3.1.0/.../index.js. | ||
| export default { | ||
| area: true, | ||
| base: true, | ||
| br: true, | ||
| col: true, | ||
| embed: true, | ||
| hr: true, | ||
| img: true, | ||
| input: true, | ||
| link: true, | ||
| meta: true, | ||
| param: true, | ||
| source: true, | ||
| track: true, | ||
| wbr: true, | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.