@void/react 1.1.11 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -6,5 +6,6 @@ const ErrorsContext = createContext(null);
|
|
|
6
6
|
const ParamsContext = createContext(null);
|
|
7
7
|
const RouterContext = createContext(null);
|
|
8
8
|
const NavigationContext = createContext(idleNavigationState());
|
|
9
|
+
const FrontmatterContext = createContext({});
|
|
9
10
|
//#endregion
|
|
10
|
-
export {
|
|
11
|
+
export { RouterContext as a, ParamsContext as i, FrontmatterContext as n, SharedContext as o, NavigationContext as r, ErrorsContext as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -96,6 +96,7 @@ export declare const ErrorsContext: Context<Record<string, string> | null>;
|
|
|
96
96
|
export declare const ParamsContext: Context<Record<string, string> | null>;
|
|
97
97
|
export declare const RouterContext: Context<VoidRouter | null>;
|
|
98
98
|
export declare const NavigationContext: Context<NavigationState>;
|
|
99
|
+
export declare const FrontmatterContext: Context<Record<string, unknown>>;
|
|
99
100
|
//#endregion
|
|
100
101
|
//#region src/runtime/index.d.ts
|
|
101
102
|
export type Deferred<T> = Promise<T>;
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as RouterContext, i as ParamsContext, n as FrontmatterContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "./context-D2ctU4yT.mjs";
|
|
2
2
|
import { n as setActionRouter, t as action } from "./action-4EvQppia.mjs";
|
|
3
3
|
import { useActionState, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
4
4
|
import { VoidActionError, categorizeActionError, formErrorMessage, formRetryMessage, formSubmissionBlocked, getValidationErrors, interpolateRouteParams, isAbortError, isEqualFormValue, isModifiedEvent, mergeDataIntoHref, scheduleFormRetry, ssrProxy, submitAction } from "void/pages-client";
|
|
@@ -460,4 +460,4 @@ function useIslandForm(defaults) {
|
|
|
460
460
|
};
|
|
461
461
|
}
|
|
462
462
|
//#endregion
|
|
463
|
-
export { ErrorsContext, Form, Link, NavigationContext, ParamsContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
|
|
463
|
+
export { ErrorsContext, Form, FrontmatterContext, Link, NavigationContext, ParamsContext, RouterContext, SharedContext, action, setActionRouter, useForm, useIslandForm, useNavigation, useParams, useRouter, useShared };
|
package/dist/plugin.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { generateComponentManifest, resolveEffectiveLayoutChain, resolvePagesDir
|
|
|
3
3
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
4
4
|
import nodePath from "node:path";
|
|
5
5
|
import { normalizePath } from "vite";
|
|
6
|
-
import { ISLANDS_CLIENT_ENTRY_ID, ISLANDS_RENDERER_ID, computePagesNeedingClientJS, editIslandSource, findIslandImports, findStaticCssImports,
|
|
6
|
+
import { ISLANDS_CLIENT_ENTRY_ID, ISLANDS_RENDERER_ID, computePagesNeedingClientJS, editIslandSource, findIslandImports, findStaticCssImports, hasIslandPages, islandStylesPlugin, recordIslandStyles, recordedIslandStyles, resolveSpecifier, rewriteCssImportForVirtualModule, watchPagesForRescan } from "void/pages-islands-plugin";
|
|
7
7
|
//#region ../../node_modules/.pnpm/pathslash@0.1.0/node_modules/pathslash/dist/index.mjs
|
|
8
8
|
const BACKSLASH_RE = /\\/g;
|
|
9
9
|
const isWindows = process.platform === "win32";
|
|
@@ -52,11 +52,14 @@ const REACT_OPTIMIZE_DEPS = [
|
|
|
52
52
|
"react",
|
|
53
53
|
"react/jsx-runtime",
|
|
54
54
|
"react/jsx-dev-runtime",
|
|
55
|
-
"react-dom"
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
"react-dom"
|
|
56
|
+
];
|
|
57
|
+
const CLIENT_OPTIMIZE_DEPS = [...REACT_OPTIMIZE_DEPS, "react-dom/client"];
|
|
58
|
+
const WORKER_OPTIMIZE_DEPS = [
|
|
59
|
+
...REACT_OPTIMIZE_DEPS,
|
|
60
|
+
"react-dom/server",
|
|
61
|
+
"void/live/client"
|
|
58
62
|
];
|
|
59
|
-
const WORKER_OPTIMIZE_DEPS = [...REACT_OPTIMIZE_DEPS, "void/live/client"];
|
|
60
63
|
const REACT_REFRESH_PREAMBLE = `
|
|
61
64
|
<script type="module">
|
|
62
65
|
import RefreshRuntime from "/@react-refresh"
|
|
@@ -134,7 +137,15 @@ function pagesPlugin(pagesDir, options) {
|
|
|
134
137
|
const normalizedPath = normalizePath(path);
|
|
135
138
|
if (normalizedPath !== normalizedPagesDir && !normalizedPath.startsWith(normalizedPagesDir + "/")) return;
|
|
136
139
|
if (event === "change" && !normalizedPath.endsWith(".md")) return;
|
|
137
|
-
|
|
140
|
+
try {
|
|
141
|
+
await runRescan();
|
|
142
|
+
} catch (error) {
|
|
143
|
+
server.config.logger.error(error instanceof Error ? error.message : String(error), {
|
|
144
|
+
error: error instanceof Error ? error : void 0,
|
|
145
|
+
timestamp: true
|
|
146
|
+
});
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
138
149
|
invalidatePageModules(server);
|
|
139
150
|
};
|
|
140
151
|
server.watcher.on("add", (path) => handlePagesChange(path, "add"));
|
|
@@ -152,9 +163,9 @@ function pagesPlugin(pagesDir, options) {
|
|
|
152
163
|
resolve: { dedupe: REACT_DEDUPE },
|
|
153
164
|
optimizeDeps: {
|
|
154
165
|
exclude: ["@void/react"],
|
|
155
|
-
include:
|
|
166
|
+
include: CLIENT_OPTIMIZE_DEPS
|
|
156
167
|
},
|
|
157
|
-
ssr: { optimizeDeps: { include:
|
|
168
|
+
ssr: { optimizeDeps: { include: [...CLIENT_OPTIMIZE_DEPS, "react-dom/server"] } },
|
|
158
169
|
environments: { [WORKER_ENVIRONMENT_NAME]: { optimizeDeps: {
|
|
159
170
|
exclude: ["@void/react"],
|
|
160
171
|
entries: [pagesOptimizeEntries],
|
|
@@ -291,6 +302,9 @@ function islandsPlugin(pagesDir, options) {
|
|
|
291
302
|
}
|
|
292
303
|
}
|
|
293
304
|
},
|
|
305
|
+
buildEnd() {
|
|
306
|
+
recordIslandStyles(this, pageScan, pagesDir);
|
|
307
|
+
},
|
|
294
308
|
resolveId: {
|
|
295
309
|
filter: { id: /^virtual:void-islands-(renderer|client)$/ },
|
|
296
310
|
handler(source) {
|
|
@@ -309,7 +323,7 @@ function islandsPlugin(pagesDir, options) {
|
|
|
309
323
|
}
|
|
310
324
|
if (id === "\0" + ISLANDS_CLIENT_ENTRY_ID) {
|
|
311
325
|
if (!pageScan) return "";
|
|
312
|
-
return generateIslandClientEntry(islandManifest, islandCssFiles, isDev);
|
|
326
|
+
return generateIslandClientEntry(islandManifest, islandCssFiles, recordedIslandStyles(pagesDir), islandManifest.size > 0 || computePagesNeedingClientJS(pageScan, pagesDir, resolvedConfig).size > 0, isDev);
|
|
313
327
|
}
|
|
314
328
|
}
|
|
315
329
|
},
|
|
@@ -342,14 +356,13 @@ function islandsPlugin(pagesDir, options) {
|
|
|
342
356
|
});
|
|
343
357
|
}
|
|
344
358
|
},
|
|
345
|
-
config(_, env) {
|
|
346
|
-
if (
|
|
347
|
-
if (env.command !== "serve" && needsIslandClientBundle(pagesDir, /\.island\.(tsx|jsx)$/, false)) return { build: {
|
|
359
|
+
async config(_, env) {
|
|
360
|
+
if (env.command !== "serve" && await hasIslandPages(root, pagesDir)) return { environments: { client: { build: {
|
|
348
361
|
manifest: true,
|
|
349
362
|
rollupOptions: { input: { "islands-client": ISLANDS_CLIENT_ENTRY_ID } }
|
|
350
|
-
} };
|
|
363
|
+
} } } };
|
|
351
364
|
}
|
|
352
|
-
}];
|
|
365
|
+
}, islandStylesPlugin(pagesDir)];
|
|
353
366
|
}
|
|
354
367
|
function generateIslandRenderer(scan, pagesDir, isDev, mdScriptIds, pagesNeedingClientJS) {
|
|
355
368
|
const preambleScript = isDev ? REACT_REFRESH_PREAMBLE : "";
|
|
@@ -358,8 +371,9 @@ function generateIslandRenderer(scan, pagesDir, isDev, mdScriptIds, pagesNeeding
|
|
|
358
371
|
return `
|
|
359
372
|
import React from "react";
|
|
360
373
|
import { renderToString } from "react-dom/server";
|
|
361
|
-
import { SharedContext, ErrorsContext, ParamsContext } from "@void/react";
|
|
374
|
+
import { SharedContext, ErrorsContext, ParamsContext, FrontmatterContext } from "@void/react";
|
|
362
375
|
import { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from "void/pages-head";
|
|
376
|
+
import { islandFrontmatterScript } from "void/pages-server";
|
|
363
377
|
|
|
364
378
|
${generateComponentManifest(scan, pagesDir)}
|
|
365
379
|
${mdScriptIdsCode}
|
|
@@ -372,7 +386,9 @@ function escapeAttr(s) {
|
|
|
372
386
|
}
|
|
373
387
|
|
|
374
388
|
export async function renderIslandPage(pageObj, assetTags) {
|
|
375
|
-
const
|
|
389
|
+
const __pageModule = await components[pageObj.component]();
|
|
390
|
+
const PageComponent = __pageModule.default;
|
|
391
|
+
const __frontmatter = __pageModule.frontmatter ?? {};
|
|
376
392
|
const layoutIds = layoutTree[pageObj.component] || [];
|
|
377
393
|
const layoutComponents = await Promise.all(
|
|
378
394
|
layoutIds.map(async (id) => (await components[id]()).default)
|
|
@@ -383,7 +399,8 @@ export async function renderIslandPage(pageObj, assetTags) {
|
|
|
383
399
|
element = React.createElement(layoutComponents[i], null, element);
|
|
384
400
|
}
|
|
385
401
|
|
|
386
|
-
// No RouterContext — islands have no Void Router
|
|
402
|
+
// No RouterContext — islands have no Void Router.
|
|
403
|
+
// Frontmatter wraps the layouts so they can read the Markdown page's values.
|
|
387
404
|
element = React.createElement(
|
|
388
405
|
SharedContext.Provider,
|
|
389
406
|
{ value: pageObj.shared || {} },
|
|
@@ -393,12 +410,17 @@ export async function renderIslandPage(pageObj, assetTags) {
|
|
|
393
410
|
React.createElement(
|
|
394
411
|
ErrorsContext.Provider,
|
|
395
412
|
{ value: pageObj.errors || {} },
|
|
396
|
-
element
|
|
413
|
+
React.createElement(FrontmatterContext.Provider, { value: __frontmatter }, element)
|
|
397
414
|
)
|
|
398
415
|
)
|
|
399
416
|
);
|
|
400
417
|
|
|
401
418
|
const html = renderToString(element);
|
|
419
|
+
// Islands hydrate as separate roots. Send the page frontmatter so their
|
|
420
|
+
// useFrontmatter() returns the same value in the browser.
|
|
421
|
+
const __frontmatterScript = __pagesNeedingClientJS.has(pageObj.component) && html.includes("data-island=")
|
|
422
|
+
? islandFrontmatterScript(__pageModule.frontmatter)
|
|
423
|
+
: "";
|
|
402
424
|
const __mdScriptAttr = __mdClientScriptIds.has(pageObj.component) ? \` data-md-script="\${escapeAttr(pageObj.component)}"\` : "";
|
|
403
425
|
const headHtml = pageObj.head ? renderHeadToString(pageObj.head) : "";
|
|
404
426
|
const htmlAttrs = pageObj.head ? renderHtmlAttrs(pageObj.head) : "";
|
|
@@ -409,35 +431,42 @@ export async function renderIslandPage(pageObj, assetTags) {
|
|
|
409
431
|
<head>\${headHtml}\${PREAMBLE_SCRIPT}\${assetTags.css}\${__pagesNeedingClientJS.has(pageObj.component) ? assetTags.preloads : ""}</head>
|
|
410
432
|
<body\${bodyAttrs}>
|
|
411
433
|
<div id="app"\${__mdScriptAttr}>\${html}</div>
|
|
412
|
-
\${__pagesNeedingClientJS.has(pageObj.component) ? assetTags.body : ""}
|
|
434
|
+
\${__frontmatterScript}\${__pagesNeedingClientJS.has(pageObj.component) ? assetTags.body : ""}
|
|
413
435
|
</body>
|
|
414
436
|
</html>\`;
|
|
415
437
|
}
|
|
416
438
|
`;
|
|
417
439
|
}
|
|
418
|
-
function generateIslandClientEntry(manifest, cssFiles, isDev) {
|
|
440
|
+
function generateIslandClientEntry(manifest, cssFiles, styles, needsRuntime, isDev) {
|
|
419
441
|
const entries = [...manifest.values()];
|
|
420
442
|
const uniqueIslands = /* @__PURE__ */ new Map();
|
|
421
443
|
for (const entry of entries) uniqueIslands.set(entry.islandId, entry.componentPath);
|
|
422
444
|
const lines = [];
|
|
423
|
-
lines.push(
|
|
424
|
-
if (!isDev) for (const file of cssFiles) {
|
|
445
|
+
if (!isDev && styles) for (const id of styles) lines.push(`import ${JSON.stringify(id)};`);
|
|
446
|
+
else if (!isDev) for (const file of cssFiles) {
|
|
425
447
|
const content = readFileSync(file, "utf-8");
|
|
426
448
|
for (const item of findStaticCssImports(content, file)) lines.push(rewriteCssImportForVirtualModule(item.statement, item.specifier, file));
|
|
427
449
|
}
|
|
450
|
+
if (!needsRuntime && !isDev) return lines.join("\n");
|
|
451
|
+
lines.push("import { initIslands } from \"void/pages-client\";");
|
|
428
452
|
lines.push("const islands = {");
|
|
429
453
|
for (const [id, path] of uniqueIslands) lines.push(` ${JSON.stringify(id)}: () => import(${JSON.stringify(path)}),`);
|
|
430
454
|
lines.push("};");
|
|
431
455
|
lines.push(`
|
|
432
|
-
async function hydrateIsland(el, mod, props) {
|
|
456
|
+
async function hydrateIsland(el, mod, props, frontmatter) {
|
|
433
457
|
const { hydrateRoot } = await import("react-dom/client");
|
|
434
458
|
const React = await import("react");
|
|
435
459
|
const Component = mod.default || mod;
|
|
460
|
+
let island = React.createElement(Component, props);
|
|
461
|
+
if (Object.keys(frontmatter).length > 0) {
|
|
462
|
+
const { FrontmatterContext } = await import("@void/react");
|
|
463
|
+
island = React.createElement(FrontmatterContext.Provider, { value: frontmatter }, island);
|
|
464
|
+
}
|
|
436
465
|
function HydratedIsland() {
|
|
437
466
|
React.useLayoutEffect(() => {
|
|
438
467
|
el.setAttribute("data-hydrated", "true");
|
|
439
468
|
}, []);
|
|
440
|
-
return
|
|
469
|
+
return island;
|
|
441
470
|
}
|
|
442
471
|
hydrateRoot(el, React.createElement(HydratedIsland));
|
|
443
472
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as RouterContext, i as ParamsContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "../context-D2ctU4yT.mjs";
|
|
2
2
|
import { n as setActionRouter } from "../action-4EvQppia.mjs";
|
|
3
3
|
import { n as DEFERRED_SHELL_END_ID } from "../deferred-shell-DOuP2YAo.mjs";
|
|
4
|
-
import React, { Suspense, startTransition, use, useCallback, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useReducer, useTransition } from "react";
|
|
4
|
+
import React, { Suspense, startTransition, use, useCallback, useEffect, useInsertionEffect, useLayoutEffect, useMemo, useReducer, useState, useTransition } from "react";
|
|
5
5
|
import { createPageNavigationEngine, createRouterFacade, idleNavigationState, isAbortError, isCallSiteActionError } from "void/pages-client";
|
|
6
6
|
import { createRoot, hydrateRoot } from "react-dom/client";
|
|
7
7
|
//#region src/runtime/pages-client.ts
|
|
@@ -11,6 +11,7 @@ const pendingVisitSettlers = /* @__PURE__ */ new Map();
|
|
|
11
11
|
const committedResources = /* @__PURE__ */ new Set();
|
|
12
12
|
const EMPTY_PARAMS = {};
|
|
13
13
|
let activePendingNavigationId = null;
|
|
14
|
+
let prerenderedUrl = null;
|
|
14
15
|
let scheduleVisit = null;
|
|
15
16
|
function createDeferredResource() {
|
|
16
17
|
let resolve;
|
|
@@ -54,6 +55,36 @@ function normalizeUrl(value) {
|
|
|
54
55
|
const url = value instanceof URL ? value : new URL(value, window.location.origin);
|
|
55
56
|
return url.origin === window.location.origin ? url.pathname + url.search + url.hash : url.href;
|
|
56
57
|
}
|
|
58
|
+
/** Page data holds a decoded path. Compare it with browser URLs in their encoded form. */
|
|
59
|
+
function encodedPageUrl(url) {
|
|
60
|
+
if (!url) return url;
|
|
61
|
+
const parsed = new URL(url, window.location.origin);
|
|
62
|
+
return parsed.pathname + parsed.search;
|
|
63
|
+
}
|
|
64
|
+
/** Static hosts serve one page at `/a`, `/a/`, `/a.html` and `/a/index.html`. */
|
|
65
|
+
function staticPagePath(pathname) {
|
|
66
|
+
let path = pathname;
|
|
67
|
+
if (path.endsWith("/index.html")) path = path.slice(0, -10);
|
|
68
|
+
else if (path.endsWith(".html")) path = path.slice(0, -5);
|
|
69
|
+
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Static page data serves every query of a path, so its url has no query. Returns the query of
|
|
73
|
+
* fetchUrl when the page data is such data for its path, or null.
|
|
74
|
+
*/
|
|
75
|
+
function staticVisitQuery(pageUrl, fetchUrl) {
|
|
76
|
+
if (!pageUrl || pageUrl.includes("?")) return null;
|
|
77
|
+
const queryStart = fetchUrl.indexOf("?");
|
|
78
|
+
if (staticPagePath(queryStart === -1 ? fetchUrl : fetchUrl.slice(0, queryStart)) !== staticPagePath(pageUrl)) return null;
|
|
79
|
+
return queryStart === -1 ? "" : fetchUrl.slice(queryStart);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The URL prerendered HTML was rendered with, when it lacks the visitor's query, or null.
|
|
83
|
+
*/
|
|
84
|
+
function prerenderedRouteUrl(pageData) {
|
|
85
|
+
const pageUrl = encodedPageUrl(pageData.url);
|
|
86
|
+
return staticVisitQuery(pageUrl, window.location.pathname + window.location.search) ? pageUrl + window.location.hash : null;
|
|
87
|
+
}
|
|
57
88
|
function navigationForResource(resource) {
|
|
58
89
|
const method = resource.method.toUpperCase();
|
|
59
90
|
return {
|
|
@@ -159,13 +190,20 @@ function RouteResource({ resource, onCommit }) {
|
|
|
159
190
|
const pageData = result.pageData;
|
|
160
191
|
const PageComponent = result.component;
|
|
161
192
|
const routeParams = pageData.params ?? EMPTY_PARAMS;
|
|
162
|
-
const routeRouter = useMemo(() =>
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
193
|
+
const routeRouter = useMemo(() => {
|
|
194
|
+
const pageUrl = encodedPageUrl(pageData.url);
|
|
195
|
+
return createRouterFacade(outerRouter, () => {
|
|
196
|
+
const outerUrl = outerRouter.url;
|
|
197
|
+
const outerPath = outerUrl.pathname + outerUrl.search;
|
|
198
|
+
if (outerPath === pageUrl) return outerPath + outerUrl.hash;
|
|
199
|
+
const query = staticVisitQuery(pageUrl, resource.fetchUrl);
|
|
200
|
+
if (query !== null) return pageUrl + query + (outerPath === resource.fetchUrl ? outerUrl.hash : resource.hash);
|
|
201
|
+
return pageUrl + resource.hash;
|
|
202
|
+
}, () => routeParams);
|
|
203
|
+
}, [
|
|
167
204
|
outerRouter,
|
|
168
205
|
pageData.url,
|
|
206
|
+
resource.fetchUrl,
|
|
169
207
|
resource.hash,
|
|
170
208
|
routeParams
|
|
171
209
|
]);
|
|
@@ -193,10 +231,11 @@ function startViewTransition(resource, reveal, enabled) {
|
|
|
193
231
|
}
|
|
194
232
|
function App({ engine, router, viewTransitions, navigationFallback: NavigationFallback }) {
|
|
195
233
|
const initialPageData = engine.initialPageData;
|
|
234
|
+
const [hydrated, setHydrated] = useState(prerenderedUrl === null);
|
|
196
235
|
const initialResource = useMemo(() => ({
|
|
197
236
|
id: 0,
|
|
198
237
|
url: initialPageData.url || currentUrl(),
|
|
199
|
-
fetchUrl:
|
|
238
|
+
fetchUrl: window.location.pathname + window.location.search,
|
|
200
239
|
hash: window.location.hash,
|
|
201
240
|
method: "GET",
|
|
202
241
|
options: {},
|
|
@@ -210,6 +249,10 @@ function App({ engine, router, viewTransitions, navigationFallback: NavigationFa
|
|
|
210
249
|
async commit() {
|
|
211
250
|
engine.commitInitialRender();
|
|
212
251
|
document.getElementById("app").setAttribute("data-hydrated", "true");
|
|
252
|
+
if (prerenderedUrl !== null) {
|
|
253
|
+
prerenderedUrl = null;
|
|
254
|
+
React.startTransition(() => setHydrated(true));
|
|
255
|
+
}
|
|
213
256
|
},
|
|
214
257
|
dispose() {}
|
|
215
258
|
}), [engine, initialPageData]);
|
|
@@ -403,7 +446,11 @@ function App({ engine, router, viewTransitions, navigationFallback: NavigationFa
|
|
|
403
446
|
method: "GET"
|
|
404
447
|
};
|
|
405
448
|
}, [isTransitionPending, state.navigation]);
|
|
406
|
-
const routerValue = useMemo(() => createRouterFacade(router, () => state.routeUrl
|
|
449
|
+
const routerValue = useMemo(() => createRouterFacade(router, () => hydrated ? state.routeUrl : prerenderedUrl ?? state.routeUrl), [
|
|
450
|
+
router,
|
|
451
|
+
state.routeUrl,
|
|
452
|
+
hydrated
|
|
453
|
+
]);
|
|
407
454
|
return React.createElement(RouterContext.Provider, { value: routerValue }, React.createElement(NavigationContext.Provider, { value: navigationValue }, React.createElement(Suspense, { fallback: NavigationFallback && state.pendingId !== null ? React.createElement(NavigationFallback, { initialPageData }) : null }, React.createElement(RouteResource, {
|
|
408
455
|
resource: state.resource,
|
|
409
456
|
onCommit: finishNavigation
|
|
@@ -414,6 +461,7 @@ async function startReactPages(config) {
|
|
|
414
461
|
pendingVisitSettlers.clear();
|
|
415
462
|
committedResources.clear();
|
|
416
463
|
activePendingNavigationId = null;
|
|
464
|
+
prerenderedUrl = null;
|
|
417
465
|
const engine = await createPageNavigationEngine({
|
|
418
466
|
adapter: {
|
|
419
467
|
createDeferred: createDeferredResource,
|
|
@@ -436,13 +484,14 @@ async function startReactPages(config) {
|
|
|
436
484
|
setActionRouter(router);
|
|
437
485
|
const appEl = document.getElementById("app");
|
|
438
486
|
if (!appEl) throw new Error("pages: Missing #app element for Void React pages hydration.");
|
|
487
|
+
const isSsr = appEl.getAttribute("data-void-ssr") !== "false";
|
|
488
|
+
if (isSsr) prerenderedUrl = prerenderedRouteUrl(engine.initialPageData);
|
|
439
489
|
const appRoot = React.createElement(App, {
|
|
440
490
|
engine,
|
|
441
491
|
router,
|
|
442
492
|
viewTransitions: config.viewTransitions,
|
|
443
493
|
navigationFallback: config.navigationFallback
|
|
444
494
|
});
|
|
445
|
-
const isSsr = appEl.getAttribute("data-void-ssr") !== "false";
|
|
446
495
|
const hasDeferred = Boolean(engine.initialPageData.deferredKeys);
|
|
447
496
|
const app = isSsr && hasDeferred ? React.createElement(React.Fragment, null, appRoot, React.createElement("template", { id: DEFERRED_SHELL_END_ID })) : appRoot;
|
|
448
497
|
startTransition(() => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as RouterContext, i as ParamsContext, o as SharedContext, r as NavigationContext, t as ErrorsContext } from "../context-D2ctU4yT.mjs";
|
|
2
2
|
import { n as DEFERRED_SHELL_END_ID, r as DEFERRED_SHELL_END_MARKER, t as DEFERRED_SHELL_CANCEL_REASON } from "../deferred-shell-DOuP2YAo.mjs";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { createSsrRouter, idleNavigationState } from "void/pages-client";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@void/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "React pages, server rendering, forms, and navigation for Void.",
|
|
5
5
|
"homepage": "https://void.cloud",
|
|
6
6
|
"bugs": {
|
|
@@ -45,17 +45,17 @@
|
|
|
45
45
|
"@types/react": "^19.3.0",
|
|
46
46
|
"@types/react-dom": "^19.3.0",
|
|
47
47
|
"pathslash": "^0.1.0",
|
|
48
|
-
"react": "^19.3.
|
|
49
|
-
"react-dom": "^19.3.
|
|
50
|
-
"vite": "npm:@voidzero-dev/vite-plus-core@1.
|
|
51
|
-
"vite-plus": "1.
|
|
52
|
-
"void": "1.
|
|
48
|
+
"react": "^19.3.1",
|
|
49
|
+
"react-dom": "^19.3.1",
|
|
50
|
+
"vite": "npm:@voidzero-dev/vite-plus-core@1.3.0",
|
|
51
|
+
"vite-plus": "1.3.0",
|
|
52
|
+
"void": "1.2.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"react": "^19.0.0",
|
|
56
56
|
"react-dom": "^19.0.0",
|
|
57
57
|
"vite": "^8.0.0",
|
|
58
|
-
"void": "1.
|
|
58
|
+
"void": "1.2.0"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "vp pack",
|