Skip to content

Commit d794dd8

Browse files
committed
Avoid probing optional page renderer exports
1 parent e49072f commit d794dd8

4 files changed

Lines changed: 55 additions & 9 deletions

File tree

‎packages/react/test/integration/react-pages-client.test.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,28 @@ describe('react-pages client (dev)', () => {
694694
expect(stderr).not.toMatch(/\(void_worker\).*new dependencies optimized: @void-repro/);
695695
});
696696

697+
it('dev: client-only shells retain the React preamble and mount loader props', async () => {
698+
const response = await fetch(`${DEV_BASE}/client-only`);
699+
const html = await response.text();
700+
expect(response.status).toBe(200);
701+
expect(html).toContain('data-void-ssr="false"');
702+
expect(html).toContain('__vite_plugin_react_preamble_installed__ = true');
703+
expect(html).not.toContain('client-only page component rendered on the server');
704+
705+
const context = await browser.newContext();
706+
try {
707+
const page = await context.newPage();
708+
await page.goto(`${DEV_BASE}/client-only`);
709+
await page.waitForSelector('#app[data-hydrated="true"]');
710+
expect(await page.textContent('[data-testid="client-only-title"]')).toBe('Client-only Route');
711+
expect(await page.textContent('[data-testid="client-only-marker"]')).toBe(
712+
'loader-props-available',
713+
);
714+
} finally {
715+
await context.close();
716+
}
717+
});
718+
697719
it('dev: SSR pages, Inertia protocol, form handling, API coexistence', async () => {
698720
// 1. Initial page load returns SSR HTML with embedded page data
699721
const rootRes = await fetch(`${DEV_BASE}/`);

‎packages/void/src/router/compile.ts‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ function compilePageRoutes(
997997
options: CompileOptions,
998998
): void {
999999
// Import protocol helpers and renderer
1000-
lines.push(`import * as __voidPagesRenderer from "virtual:void-pages-renderer";`);
1000+
lines.push(`import { renderPage } from "virtual:void-pages-renderer";`);
10011001
if (options.dev) {
10021002
lines.push(`import { getVoidPagesDevCss } from "virtual:void-pages-dev-assets";`);
10031003
}
@@ -1008,12 +1008,6 @@ function compilePageRoutes(
10081008
lines.push(`import { renderIslandPage } from "virtual:void-islands-renderer";`);
10091009
}
10101010
lines.push('');
1011-
lines.push(`const renderPage = __voidPagesRenderer.renderPage;`);
1012-
lines.push(`if (typeof __voidPagesRenderer.renderPreambleScript === "string") {`);
1013-
lines.push(` renderPage.preambleScript = __voidPagesRenderer.renderPreambleScript;`);
1014-
lines.push(`}`);
1015-
lines.push('');
1016-
10171011
// Emit head config constant from void.json
10181012
lines.push(`const __voidHeadConfig = ${JSON.stringify(pages.headConfig ?? null)};`);
10191013
lines.push('');

‎packages/void/test/integration/typed-routing-runtime.test.ts‎

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,19 @@ describe('typed routing in generated Workers', () => {
7676
renderMode: 'server',
7777
shouldPrerender: false,
7878
},
79+
{
80+
pattern: '/client-only',
81+
params: [],
82+
catchAll: false,
83+
componentPath: 'client-only.tsx',
84+
componentId: 'client-only',
85+
serverPath: null,
86+
methods: [],
87+
ssrMode: 'client',
88+
prerenderMode: 'disabled',
89+
renderMode: 'client',
90+
shouldPrerender: false,
91+
},
7992
];
8093
const routeTable = join(directory, 'generated-routes.ts');
8194
const entry = join(directory, 'generated-worker.ts');
@@ -113,6 +126,10 @@ describe('typed routing in generated Workers', () => {
113126
),
114127
);
115128
writeFileSync(entry, compileWorkerEntry({ runtimeEnvPath: source('env.ts') }));
129+
const preambleScript = dev
130+
? '<script type="module">window.__fixturePreamble = true</script>'
131+
: '';
132+
const undefinedImports: Array<string> = [];
116133
await build({
117134
configFile: false,
118135
logLevel: 'silent',
@@ -134,7 +151,8 @@ describe('typed routing in generated Workers', () => {
134151
},
135152
load(id) {
136153
if (id === '\0virtual:void-pages-renderer') {
137-
return `export async function renderPage(page) { return '<html><body>' + page.props.title + '</body></html>'; }`;
154+
return `export async function renderPage(page) { return '<html><body>' + page.props.title + '</body></html>'; }
155+
renderPage.preambleScript = ${JSON.stringify(preambleScript)};`;
138156
}
139157
if (id === '\0virtual:void-pages-dev-assets') {
140158
return 'export async function getVoidPagesDevCss() { return []; }';
@@ -150,11 +168,18 @@ describe('typed routing in generated Workers', () => {
150168
ssr: entry,
151169
target: 'esnext',
152170
rollupOptions: {
171+
onwarn(warning, defaultHandler) {
172+
if (warning.code === 'IMPORT_IS_UNDEFINED') {
173+
undefinedImports.push(warning.message);
174+
}
175+
defaultHandler(warning);
176+
},
153177
external: [/^cloudflare:/, /^node:/],
154178
output: { entryFileNames: 'worker.mjs', codeSplitting: false },
155179
},
156180
},
157181
});
182+
expect(undefinedImports).toEqual([]);
158183
runtime = new Miniflare(
159184
convertV4MiniflareOptions({
160185
compatibilityDate: '2026-07-01',
@@ -201,6 +226,11 @@ describe('typed routing in generated Workers', () => {
201226
}
202227
const page = await runtime.dispatchFetch('https://app.test/');
203228
expect(await page.text()).toContain('real page loader');
229+
const clientOnlyPage = await runtime.dispatchFetch('https://app.test/client-only');
230+
const clientOnlyHtml = await clientOnlyPage.text();
231+
expect(clientOnlyPage.status).toBe(200);
232+
expect(clientOnlyHtml).toContain('data-void-ssr="false"');
233+
expect(clientOnlyHtml.includes('window.__fixturePreamble = true')).toBe(dev);
204234
const protocol = await runtime.dispatchFetch('https://app.test/', {
205235
headers: { 'x-voidpages': 'true' },
206236
});

‎packages/void/test/unit/pages-compile.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ describe('Pages metadata wiring', () => {
7777
);
7878
it('emits lazy imports and renderer/action metadata with typed execution calls', () => {
7979
const code = compile();
80-
expect(code).toContain('import * as __voidPagesRenderer from "virtual:void-pages-renderer"');
80+
expect(code).toContain('import { renderPage } from "virtual:void-pages-renderer"');
8181
expect(code).toContain(
8282
'const _pload_index = __createModuleLoader(() => import("/project/pages/index.server.ts"))',
8383
);

0 commit comments

Comments
 (0)