void-plugin-hono-jsx 0.1.0-rc.0 → 0.1.0-rc.1
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.
- package/CHANGELOG.md +7 -0
- package/README.md +79 -0
- package/dist/browser/client.d.ts +4 -1
- package/dist/browser/client.d.ts.map +1 -1
- package/dist/browser/client.js +4 -1
- package/dist/browser/client.js.map +1 -1
- package/dist/browser/deferred.d.ts +12 -2
- package/dist/browser/deferred.d.ts.map +1 -1
- package/dist/browser/deferred.js +35 -4
- package/dist/browser/deferred.js.map +1 -1
- package/dist/browser/navigation-fallback.d.ts +13 -0
- package/dist/browser/navigation-fallback.d.ts.map +1 -0
- package/dist/browser/navigation-fallback.js +28 -0
- package/dist/browser/navigation-fallback.js.map +1 -0
- package/dist/browser/pages.d.ts +4 -0
- package/dist/browser/pages.d.ts.map +1 -1
- package/dist/browser/pages.js +1 -0
- package/dist/browser/pages.js.map +1 -1
- package/dist/plugins/hono-jsx.d.ts +5 -0
- package/dist/plugins/hono-jsx.d.ts.map +1 -1
- package/dist/plugins/hono-jsx.js +15 -2
- package/dist/plugins/hono-jsx.js.map +1 -1
- package/dist/server/deferred.d.ts +24 -0
- package/dist/server/deferred.d.ts.map +1 -0
- package/dist/server/deferred.js +54 -0
- package/dist/server/deferred.js.map +1 -0
- package/dist/server/pages.d.ts +4 -0
- package/dist/server/pages.d.ts.map +1 -1
- package/dist/server/pages.js +1 -0
- package/dist/server/pages.js.map +1 -1
- package/package.json +1 -1
- package/src/plugins/hono-jsx.ts +14 -2
- package/src/runtime/client.tsx +4 -1
- package/src/runtime/deferred.ts +40 -4
- package/src/runtime/navigation-fallback.tsx +31 -0
- package/src/runtime/pages.tsx +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.0-rc.1](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-rc.0...v0.1.0-rc.1) (2026-10-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add navigation fallback and Hono deferred rendering ([8475a73](https://github.com/ts-76/void-plugin-hono-jsx/commit/8475a737931df4bfb62b9d32c877eb03c76ef644))
|
|
9
|
+
|
|
3
10
|
## [0.1.0-rc.0](https://github.com/ts-76/void-plugin-hono-jsx/compare/v0.1.0-alpha.4...v0.1.0-rc.0) (2026-10-17)
|
|
4
11
|
|
|
5
12
|
|
package/README.md
CHANGED
|
@@ -235,3 +235,82 @@ On the tested macOS Void/Miniflare development runtime, a POST to an undefined n
|
|
|
235
235
|
## RC and normal-release policy
|
|
236
236
|
|
|
237
237
|
The planned first candidate is 0.1.0-rc.0 on next, followed by 0.1.0 after public-consumer and real Workers verification. It is not yet a published-release claim. Production ISR remains outside the initial guarantee. Patches in 0.1.x preserve documented APIs; breaking changes move to 0.2.0 or later. Read the [release contract](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/docs/release-contract.md) and [security policy](https://github.com/ts-76/void-plugin-hono-jsx/blob/main/SECURITY.md). Report vulnerabilities [privately](https://github.com/ts-76/void-plugin-hono-jsx/security/advisories/new).
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
### Common navigation fallback (after RC.0)
|
|
241
|
+
|
|
242
|
+
Register a default-exported local TSX/JSX module by path. The plugin imports the
|
|
243
|
+
component into its client entry; it does not serialize a function in Vite config.
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
voidHonoJsx({ navigationFallback: { component: './components/NavigationFallback.tsx', delay: 150 } })
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
```tsx
|
|
250
|
+
import type { NavigationFallbackProps } from 'void-plugin-hono-jsx/pages';
|
|
251
|
+
export default function Fallback({ navigation }: NavigationFallbackProps) {
|
|
252
|
+
return <p>Loading {navigation.location?.pathname}…</p>;
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
The optional fallback appears after 150 ms by default, only while a GET visit is
|
|
257
|
+
loading. Fast/cache/prefetch visits that finish before the delay show nothing.
|
|
258
|
+
It is an additional live status region: the existing page, input DOM and layout
|
|
259
|
+
remain mounted and interactive. It never replaces that tree, commits navigation
|
|
260
|
+
or changes history/scroll. Completion, failure and superseding visits remove it;
|
|
261
|
+
a new slow visit starts its own delay. If the fallback component throws, it is
|
|
262
|
+
hidden for that visit and reported through the existing navigation-error event;
|
|
263
|
+
the page tree remains mounted, and a new visit can try the fallback again.
|
|
264
|
+
JSON/multipart submission UI remains under
|
|
265
|
+
`useNavigation()`/form pending state. SSR stays idle and emits no fallback.
|
|
266
|
+
Without this option, existing behavior is unchanged. The normal page reset and
|
|
267
|
+
preserveState/preserveScroll rules still apply when the destination commits.
|
|
268
|
+
This addition is not included in the already published RC.0.
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
### Hono use() / Suspense for deferred props (after RC.0)
|
|
272
|
+
|
|
273
|
+
`deferredResult(state)` gives Hono a stable, render-only Promise. Void still runs
|
|
274
|
+
the resolver, delivers HTML callbacks/NDJSON and manages prefetch/navigation.
|
|
275
|
+
The existing `Deferred<T>` loading/value/error API remains available.
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
import { ErrorBoundary, Suspense, use, useState } from 'hono/jsx';
|
|
279
|
+
import { deferredResult, type Deferred, type DeferredResult } from 'void-plugin-hono-jsx/pages';
|
|
280
|
+
function Result({ result }: { result: DeferredResult<string> }) {
|
|
281
|
+
if (result.error) throw result.error;
|
|
282
|
+
return <p>{result.value}</p>;
|
|
283
|
+
}
|
|
284
|
+
function Value({ slow }: { slow: Deferred<string> }) {
|
|
285
|
+
const [failed, setFailed] = useState<DeferredResult<string> | null>(null);
|
|
286
|
+
const result = use(deferredResult(slow));
|
|
287
|
+
const fallback = <p role="alert">Could not load data.</p>;
|
|
288
|
+
if (failed === result) return fallback;
|
|
289
|
+
return <ErrorBoundary fallback={fallback}
|
|
290
|
+
onError={() => queueMicrotask(() => setFailed(result))}>
|
|
291
|
+
<Result result={result} />
|
|
292
|
+
</ErrorBoundary>;
|
|
293
|
+
}
|
|
294
|
+
export default function Page({ slow }: { slow: Deferred<string> }) {
|
|
295
|
+
return <Suspense fallback={<p>Loading…</p>}><Value slow={slow} /></Suspense>;
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Results fulfill with `{ value, error }`. Throw the error in a child of
|
|
300
|
+
ErrorBoundary, after `use()` returns. The example remembers that result after
|
|
301
|
+
`onError`: Hono 4 can leave an incomplete tree if the same failed child is thrown
|
|
302
|
+
again during a parent's navigation-state update. This also keeps its async SSR
|
|
303
|
+
ErrorBoundary out of the pending shell. The Promise itself never rejects,
|
|
304
|
+
avoiding an unhandled derived rejection from Hono Suspense's `finally(retry)`.
|
|
305
|
+
The Promise is allocated on first use and remains identical across Void's ref
|
|
306
|
+
replacement and JSON action retention. Each navigation/prop owns a separate
|
|
307
|
+
weakly held resource; cancellation/disposal is reported through Void's existing
|
|
308
|
+
reject callback. Do not cache a resource outside its page or start another fetch.
|
|
309
|
+
|
|
310
|
+
SSR deliberately uses an inert pending Promise so Hono emits its initial
|
|
311
|
+
fallback immediately; never await this helper on the server. Void alone delivers
|
|
312
|
+
the later result to the browser. The adapter does not send Hono replacement HTML
|
|
313
|
+
or wait for deferred data in its server renderer. Only full Pages are supported;
|
|
314
|
+
deferred islands/static remain unsupported. Upstream failed-prefetch null values
|
|
315
|
+
remain null (the success value type includes null); this helper does not repair
|
|
316
|
+
that upstream limitation. This API is not in published RC.0.
|
package/dist/browser/client.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type VoidRouterConfig } from 'void/pages-client';
|
|
2
|
-
|
|
2
|
+
import { type NavigationFallbackOptions } from './navigation-fallback.tsx';
|
|
3
|
+
type NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'> & {
|
|
4
|
+
navigationFallback?: NavigationFallbackOptions;
|
|
5
|
+
};
|
|
3
6
|
type Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;
|
|
4
7
|
export declare function startHonoPages(manifest: Manifest, options: NavigationOptions): Promise<void>;
|
|
5
8
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA6C,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA6C,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErG,OAAO,EAAsB,KAAK,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAK/F,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,GAAG,oBAAoB,GAAG,yBAAyB,CAAC,GAAG;IAAE,kBAAkB,CAAC,EAAE,yBAAyB,CAAA;CAAE,CAAC;AAE3K,KAAK,QAAQ,GAAG,IAAI,CAAC,gBAAgB,EAAE,YAAY,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,GAAG,gBAAgB,GAAG,wBAAwB,CAAC,CAAC;AAO/I,wBAAsB,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,iBA4GlF"}
|
package/dist/browser/client.js
CHANGED
|
@@ -4,6 +4,7 @@ import { jsx } from 'hono/jsx/dom/jsx-runtime';
|
|
|
4
4
|
import { useLayoutEffect, useState } from 'hono/jsx';
|
|
5
5
|
import { idleNavigationState } from 'void/pages-client';
|
|
6
6
|
import { PageContext, RouterContext, NavigationContext, setActionRouter } from "void-plugin-hono-jsx/pages";
|
|
7
|
+
import { NavigationFallback } from './navigation-fallback.js';
|
|
7
8
|
import { createHonoRouter } from './navigation.js';
|
|
8
9
|
import { createDocumentHead } from './document-head.js';
|
|
9
10
|
import { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.js';
|
|
@@ -13,6 +14,8 @@ function pageComponent(component) {
|
|
|
13
14
|
return component;
|
|
14
15
|
}
|
|
15
16
|
export async function startHonoPages(manifest, options) {
|
|
17
|
+
if (options.navigationFallback && typeof options.navigationFallback.component !== 'function')
|
|
18
|
+
throw new Error('Hono Pages: navigationFallback must default-export a component function.');
|
|
16
19
|
const root = document.getElementById('app');
|
|
17
20
|
if (!root)
|
|
18
21
|
throw new Error('Hono Pages: app root is missing.');
|
|
@@ -121,7 +124,7 @@ export async function startHonoPages(manifest, options) {
|
|
|
121
124
|
}
|
|
122
125
|
});
|
|
123
126
|
};
|
|
124
|
-
return _jsx(RouterContext.Provider, { value: navigation.router, children: _jsxs(NavigationContext.Provider, { value: pendingNavigation, children: [failed && _jsx("p", { role: "alert", children: "The page could not be loaded. Please try again." }), _jsx(ErrorBoundary, { onError: renderFailed, fallback: _jsx(_Fragment, {}), children: _jsx(PageFrame, { frame: frame }) }, recovery)] }) });
|
|
127
|
+
return _jsx(RouterContext.Provider, { value: navigation.router, children: _jsxs(NavigationContext.Provider, { value: pendingNavigation, children: [failed && _jsx("p", { role: "alert", children: "The page could not be loaded. Please try again." }), _jsx(ErrorBoundary, { onError: renderFailed, fallback: _jsx(_Fragment, {}), children: _jsx(PageFrame, { frame: frame }) }, recovery), options.navigationFallback && _jsx(NavigationFallback, { state: pendingNavigation, options: options.navigationFallback })] }) });
|
|
125
128
|
}
|
|
126
129
|
render(_jsx(App, {}), root);
|
|
127
130
|
navigation.start();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/client.tsx"],"sourcesContent":["import { ErrorBoundary, render } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { useLayoutEffect, useState } from 'hono/jsx';\nimport { idleNavigationState, type NavigationState, type VoidRouterConfig } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext, setActionRouter } from './pages.tsx';\nimport { createHonoRouter } from './navigation.ts';\nimport { createDocumentHead } from './document-head.ts';\nimport { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';\n\ntype NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'>;\n\ntype Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;\n\nfunction pageComponent(component: unknown) {\n if (typeof component !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n return component;\n}\n\nexport async function startHonoPages(manifest: Manifest, options: NavigationOptions) {\n const root = document.getElementById('app');\n if (!root) throw new Error('Hono Pages: app root is missing.');\n type Frame = { page: Awaited<ReturnType<typeof createHonoRouter>>['initialPageData']; sourceProps: Record<string, unknown>; component: unknown; layouts: unknown[]; revision: number; commit: number };\n let update: ((frame: Frame) => void) | undefined;\n let revision = 0;\n let commit = 0;\n const pendingCommits = new Map<number, { resolve(): void; reject(error: unknown): void }>();\n let committedFrame: Frame | undefined;\n const failedFrames = new Set<number>();\n let navigationState = idleNavigationState();\n let updateNavigation: ((state: NavigationState) => void) | undefined;\n let applyDocumentHead: ReturnType<typeof createDocumentHead> | undefined;\n let renderedProps: Record<string, unknown> | undefined;\n let updateDeferred: ((props: Record<string, unknown>) => void) | undefined;\n const initialization = createHonoRouter({\n ...manifest,\n adapter: {\n createDeferred, resolveDeferred, rejectDeferred, isLoading,\n onDeferredUpdate(props) {\n if (props === renderedProps) updateDeferred?.({ ...props });\n },\n async applyUpdate(page, component, layouts, options) {\n layouts.forEach(pageComponent);\n pageComponent(component);\n if (!update) throw new Error('Hono Pages: page rendering has not started.');\n if (!options.preserveState) revision++;\n renderedProps = page.props;\n const nextCommit = ++commit;\n const committed = new Promise<void>((resolve, reject) => pendingCommits.set(nextCommit, { resolve, reject }));\n update({ page: { ...page, props: { ...page.props } }, sourceProps: page.props, component, layouts, revision, commit: nextCommit });\n await committed;\n },\n },\n ...options,\n cacheVisitedPageData: false,\n onNavigationChange(state) { navigationState = state; updateNavigation?.(state); root.dataset.navigation = state.state; },\n });\n const releaseBuffer = bufferInitialDeferred();\n const navigation = await initialization.finally(releaseBuffer);\n setActionRouter(navigation.router);\n renderedProps = navigation.initialPageData.props;\n applyDocumentHead = createDocumentHead(navigation.initialPageData.head);\n\n const initialFrame: Frame = { page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, sourceProps: navigation.initialPageData.props, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision, commit };\n function PageFrame({ frame }: { frame: Frame }) {\n useLayoutEffect(() => {\n if (failedFrames.has(frame.commit)) return;\n if (frame.commit > 0) applyDocumentHead?.(frame.page.head);\n committedFrame = frame;\n for (const id of failedFrames) if (id < frame.commit) failedFrames.delete(id);\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.resolve(); }\n }, [frame]);\n let content = jsx(pageComponent(frame.component), frame.page.props, String(frame.revision));\n const ids = manifest.layoutTree[frame.page.component] ?? [];\n for (let index = frame.layouts.length - 1; index >= 0; index--) {\n content = jsx(pageComponent(frame.layouts[index]), { children: content }, ids[index]);\n }\n return <PageContext.Provider value={frame.page}>{content}</PageContext.Provider>;\n }\n\n function App() {\n const [frame, setFrame] = useState<Frame>(initialFrame);\n const [pendingNavigation, setNavigation] = useState(navigationState);\n const [failed, setFailed] = useState(false);\n const [recovery, setRecovery] = useState(0);\n useLayoutEffect(() => {\n updateNavigation = setNavigation;\n setNavigation(navigationState);\n updateDeferred = (props) => setFrame((frame) => ({ ...frame, page: { ...frame.page, props } }));\n update = (next) => { setFailed(false); setFrame(next); };\n const onError = () => setFailed(true);\n window.addEventListener('hono-pages:navigation-error', onError);\n return () => { for (const pending of pendingCommits.values()) pending.reject(new DOMException('Hono Pages: renderer unmounted.', 'AbortError')); pendingCommits.clear(); updateNavigation = undefined; update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };\n }, []);\n const renderFailed = (error: unknown) => {\n if (failedFrames.has(frame.commit)) return;\n failedFrames.add(frame.commit);\n queueMicrotask(() => {\n // A rejected child never reaches PageFrame's commit effect. Roll back\n // outside the render traversal, then reject every coalesced waiter.\n if (commit === frame.commit) {\n if (committedFrame) { renderedProps = committedFrame.sourceProps; setFrame(committedFrame); }\n // Discard the partially built Hono tree only after a render failure.\n // Successful navigations keep the same boundary and layout state.\n setRecovery(value => value + 1);\n setFailed(true);\n }\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.reject(error); }\n });\n };\n return <RouterContext.Provider value={navigation.router}>\n <NavigationContext.Provider value={pendingNavigation}>\n {failed && <p role=\"alert\">The page could not be loaded. Please try again.</p>}\n <ErrorBoundary key={recovery} onError={renderFailed} fallback={<></>}>\n <PageFrame frame={frame} />\n </ErrorBoundary>\n </NavigationContext.Provider>\n </RouterContext.Provider>;\n }\n\n render(<App />, root);\n navigation.start();\n navigation.commitInitialRender();\n root.dataset.navigation = 'idle';\n root.dataset.honoPages = 'mounted';\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","mappings":"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","names":[],"ignoreList":[],"sources":["../../src/runtime/client.tsx"],"sourcesContent":["import { ErrorBoundary, render } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport { useLayoutEffect, useState } from 'hono/jsx';\nimport { idleNavigationState, type NavigationState, type VoidRouterConfig } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext, setActionRouter } from './pages.tsx';\nimport { NavigationFallback, type NavigationFallbackOptions } from './navigation-fallback.tsx';\nimport { createHonoRouter } from './navigation.ts';\nimport { createDocumentHead } from './document-head.ts';\nimport { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';\n\ntype NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'> & { navigationFallback?: NavigationFallbackOptions };\n\ntype Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;\n\nfunction pageComponent(component: unknown) {\n if (typeof component !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n return component;\n}\n\nexport async function startHonoPages(manifest: Manifest, options: NavigationOptions) {\n if (options.navigationFallback && typeof options.navigationFallback.component !== 'function') throw new Error('Hono Pages: navigationFallback must default-export a component function.');\n const root = document.getElementById('app');\n if (!root) throw new Error('Hono Pages: app root is missing.');\n type Frame = { page: Awaited<ReturnType<typeof createHonoRouter>>['initialPageData']; sourceProps: Record<string, unknown>; component: unknown; layouts: unknown[]; revision: number; commit: number };\n let update: ((frame: Frame) => void) | undefined;\n let revision = 0;\n let commit = 0;\n const pendingCommits = new Map<number, { resolve(): void; reject(error: unknown): void }>();\n let committedFrame: Frame | undefined;\n const failedFrames = new Set<number>();\n let navigationState = idleNavigationState();\n let updateNavigation: ((state: NavigationState) => void) | undefined;\n let applyDocumentHead: ReturnType<typeof createDocumentHead> | undefined;\n let renderedProps: Record<string, unknown> | undefined;\n let updateDeferred: ((props: Record<string, unknown>) => void) | undefined;\n const initialization = createHonoRouter({\n ...manifest,\n adapter: {\n createDeferred, resolveDeferred, rejectDeferred, isLoading,\n onDeferredUpdate(props) {\n if (props === renderedProps) updateDeferred?.({ ...props });\n },\n async applyUpdate(page, component, layouts, options) {\n layouts.forEach(pageComponent);\n pageComponent(component);\n if (!update) throw new Error('Hono Pages: page rendering has not started.');\n if (!options.preserveState) revision++;\n renderedProps = page.props;\n const nextCommit = ++commit;\n const committed = new Promise<void>((resolve, reject) => pendingCommits.set(nextCommit, { resolve, reject }));\n update({ page: { ...page, props: { ...page.props } }, sourceProps: page.props, component, layouts, revision, commit: nextCommit });\n await committed;\n },\n },\n ...options,\n cacheVisitedPageData: false,\n onNavigationChange(state) { navigationState = state; updateNavigation?.(state); root.dataset.navigation = state.state; },\n });\n const releaseBuffer = bufferInitialDeferred();\n const navigation = await initialization.finally(releaseBuffer);\n setActionRouter(navigation.router);\n renderedProps = navigation.initialPageData.props;\n applyDocumentHead = createDocumentHead(navigation.initialPageData.head);\n\n const initialFrame: Frame = { page: { ...navigation.initialPageData, props: { ...navigation.initialPageData.props } }, sourceProps: navigation.initialPageData.props, component: navigation.initialComponent, layouts: navigation.initialLayouts, revision, commit };\n function PageFrame({ frame }: { frame: Frame }) {\n useLayoutEffect(() => {\n if (failedFrames.has(frame.commit)) return;\n if (frame.commit > 0) applyDocumentHead?.(frame.page.head);\n committedFrame = frame;\n for (const id of failedFrames) if (id < frame.commit) failedFrames.delete(id);\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.resolve(); }\n }, [frame]);\n let content = jsx(pageComponent(frame.component), frame.page.props, String(frame.revision));\n const ids = manifest.layoutTree[frame.page.component] ?? [];\n for (let index = frame.layouts.length - 1; index >= 0; index--) {\n content = jsx(pageComponent(frame.layouts[index]), { children: content }, ids[index]);\n }\n return <PageContext.Provider value={frame.page}>{content}</PageContext.Provider>;\n }\n\n function App() {\n const [frame, setFrame] = useState<Frame>(initialFrame);\n const [pendingNavigation, setNavigation] = useState(navigationState);\n const [failed, setFailed] = useState(false);\n const [recovery, setRecovery] = useState(0);\n useLayoutEffect(() => {\n updateNavigation = setNavigation;\n setNavigation(navigationState);\n updateDeferred = (props) => setFrame((frame) => ({ ...frame, page: { ...frame.page, props } }));\n update = (next) => { setFailed(false); setFrame(next); };\n const onError = () => setFailed(true);\n window.addEventListener('hono-pages:navigation-error', onError);\n return () => { for (const pending of pendingCommits.values()) pending.reject(new DOMException('Hono Pages: renderer unmounted.', 'AbortError')); pendingCommits.clear(); updateNavigation = undefined; update = undefined; updateDeferred = undefined; window.removeEventListener('hono-pages:navigation-error', onError); };\n }, []);\n const renderFailed = (error: unknown) => {\n if (failedFrames.has(frame.commit)) return;\n failedFrames.add(frame.commit);\n queueMicrotask(() => {\n // A rejected child never reaches PageFrame's commit effect. Roll back\n // outside the render traversal, then reject every coalesced waiter.\n if (commit === frame.commit) {\n if (committedFrame) { renderedProps = committedFrame.sourceProps; setFrame(committedFrame); }\n // Discard the partially built Hono tree only after a render failure.\n // Successful navigations keep the same boundary and layout state.\n setRecovery(value => value + 1);\n setFailed(true);\n }\n for (const [id, pending] of pendingCommits) if (id <= frame.commit) { pendingCommits.delete(id); pending.reject(error); }\n });\n };\n return <RouterContext.Provider value={navigation.router}>\n <NavigationContext.Provider value={pendingNavigation}>\n {failed && <p role=\"alert\">The page could not be loaded. Please try again.</p>}\n <ErrorBoundary key={recovery} onError={renderFailed} fallback={<></>}>\n <PageFrame frame={frame} />\n </ErrorBoundary>\n {options.navigationFallback && <NavigationFallback state={pendingNavigation} options={options.navigationFallback} />}\n </NavigationContext.Provider>\n </RouterContext.Provider>;\n }\n\n render(<App />, root);\n navigation.start();\n navigation.commitInitialRender();\n root.dataset.navigation = 'idle';\n root.dataset.honoPages = 'mounted';\n}\n"]}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import type { DeferredState } from 'void';
|
|
2
|
+
/** Null from an upstream completed prefetch remains null, not a repaired error. */
|
|
3
|
+
export type DeferredResult<T> = {
|
|
4
|
+
value: T | null;
|
|
5
|
+
error: null;
|
|
6
|
+
} | {
|
|
7
|
+
value: null;
|
|
8
|
+
error: Error;
|
|
9
|
+
};
|
|
10
|
+
/** A stable, render-only Promise; Void still owns all execution and delivery. */
|
|
11
|
+
export declare function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>>;
|
|
2
12
|
export declare function createDeferred(): DeferredState<never>;
|
|
3
|
-
export declare function resolveDeferred(
|
|
4
|
-
export declare function rejectDeferred(
|
|
13
|
+
export declare function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown>;
|
|
14
|
+
export declare function rejectDeferred(ref: unknown, message: string): DeferredState<never>;
|
|
5
15
|
export declare function isLoading(ref: unknown): boolean;
|
|
6
16
|
declare global {
|
|
7
17
|
interface Window {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,wBAAgB,cAAc,IAAI,aAAa,CAAC,KAAK,CAAC,CAErD;AACD,wBAAgB,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,mFAAmF;AACnF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAejG,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAQrF;AAWD,wBAAgB,cAAc,IAAI,aAAa,CAAC,KAAK,CAAC,CAErD;AACD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAEpF;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAElF;AACD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QAC3D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAC1D,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;KAClE;CACF;AACD,wBAAgB,qBAAqB,eASpC"}
|
package/dist/browser/deferred.js
CHANGED
|
@@ -1,11 +1,42 @@
|
|
|
1
|
+
const resources = new WeakMap();
|
|
2
|
+
function resourceFor(ref) {
|
|
3
|
+
if (typeof ref !== 'object' || ref === null)
|
|
4
|
+
throw new Error('Hono Pages: deferredResult requires a Deferred state.');
|
|
5
|
+
let resource = resources.get(ref);
|
|
6
|
+
if (!resource)
|
|
7
|
+
resources.set(ref, resource = {});
|
|
8
|
+
return resource;
|
|
9
|
+
}
|
|
10
|
+
/** A stable, render-only Promise; Void still owns all execution and delivery. */
|
|
11
|
+
export function deferredResult(state) {
|
|
12
|
+
const resource = resourceFor(state);
|
|
13
|
+
// SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR
|
|
14
|
+
// HTML callback to client-owned completion or wait for it on the server.
|
|
15
|
+
if (typeof window === 'undefined')
|
|
16
|
+
return (resource.serverPromise ??= new Promise(() => { }));
|
|
17
|
+
if (!state.loading && !resource.result)
|
|
18
|
+
resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };
|
|
19
|
+
resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });
|
|
20
|
+
return resource.promise;
|
|
21
|
+
}
|
|
22
|
+
function complete(ref, next) {
|
|
23
|
+
const resource = resourceFor(ref);
|
|
24
|
+
resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };
|
|
25
|
+
resource.resolve?.(resource.result);
|
|
26
|
+
resource.resolve = undefined;
|
|
27
|
+
// Void replaces its state object on completion. Both objects refer to the
|
|
28
|
+
// same lazy Promise, including completion before component import/use().
|
|
29
|
+
resources.set(next, resource);
|
|
30
|
+
return next;
|
|
31
|
+
}
|
|
1
32
|
export function createDeferred() {
|
|
2
33
|
return { loading: true, value: null, error: null };
|
|
3
34
|
}
|
|
4
|
-
export function resolveDeferred(
|
|
5
|
-
return { loading: false, value, error: null };
|
|
35
|
+
export function resolveDeferred(ref, value) {
|
|
36
|
+
return complete(ref, { loading: false, value, error: null });
|
|
6
37
|
}
|
|
7
|
-
export function rejectDeferred(
|
|
8
|
-
return { loading: false, value: null, error: new Error(message) };
|
|
38
|
+
export function rejectDeferred(ref, message) {
|
|
39
|
+
return complete(ref, { loading: false, value: null, error: new Error(message) });
|
|
9
40
|
}
|
|
10
41
|
export function isLoading(ref) {
|
|
11
42
|
return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DeferredState } from 'void';\n\n/** Null from an upstream completed prefetch remains null, not a repaired error. */\nexport type DeferredResult<T> = { value: T | null; error: null } | { value: null; error: Error };\ntype Resource = {\n result?: DeferredResult<unknown>;\n promise?: Promise<DeferredResult<unknown>>;\n serverPromise?: Promise<DeferredResult<unknown>>;\n resolve?: (result: DeferredResult<unknown>) => void;\n};\nconst resources = new WeakMap<object, Resource>();\nfunction resourceFor(ref: unknown): Resource {\n if (typeof ref !== 'object' || ref === null) throw new Error('Hono Pages: deferredResult requires a Deferred state.');\n let resource = resources.get(ref);\n if (!resource) resources.set(ref, resource = {});\n return resource;\n}\n\n/** A stable, render-only Promise; Void still owns all execution and delivery. */\nexport function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>> {\n const resource = resourceFor(state);\n // SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR\n // HTML callback to client-owned completion or wait for it on the server.\n if (typeof window === 'undefined') return (resource.serverPromise ??= new Promise(() => {})) as Promise<DeferredResult<T>>;\n if (!state.loading && !resource.result) resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };\n resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });\n return resource.promise as Promise<DeferredResult<T>>;\n}\nfunction complete(ref: unknown, next: DeferredState<unknown>) {\n const resource = resourceFor(ref);\n resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };\n resource.resolve?.(resource.result);\n resource.resolve = undefined;\n // Void replaces its state object on completion. Both objects refer to the\n // same lazy Promise, including completion before component import/use().\n resources.set(next, resource);\n return next;\n}\nexport function createDeferred(): DeferredState<never> {\n return { loading: true, value: null, error: null };\n}\nexport function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown> {\n return complete(ref, { loading: false, value, error: null });\n}\nexport function rejectDeferred(ref: unknown, message: string): DeferredState<never> {\n return complete(ref, { loading: false, value: null, error: new Error(message) }) as DeferredState<never>;\n}\nexport function isLoading(ref: unknown): boolean {\n return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;\n}\n\n// Void installs its HTML callbacks before awaiting component imports. Keep early\n// messages in its existing queue until the initial deferred registry is ready.\ndeclare global {\n interface Window {\n __resolveDeferred?: (group: string, data: unknown) => void;\n __rejectDeferred?: (group: string, error: string) => void;\n __deferredQueue?: Array<[string, unknown] | [string, 0, string]>;\n }\n}\nexport function bufferInitialDeferred() {\n const resolve = window.__resolveDeferred;\n const reject = window.__rejectDeferred;\n window.__resolveDeferred = (group, data) => (window.__deferredQueue ??= []).push([group, data]);\n window.__rejectDeferred = (group, error) => (window.__deferredQueue ??= []).push([group, 0, error]);\n return () => {\n window.__resolveDeferred = resolve;\n window.__rejectDeferred = reject;\n };\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type FC } from 'hono/jsx';
|
|
2
|
+
import type { NavigationState } from 'void/pages-client';
|
|
3
|
+
import type { NavigationFallbackProps } from './pages.tsx';
|
|
4
|
+
export type NavigationFallbackOptions = {
|
|
5
|
+
component: FC<NavigationFallbackProps>;
|
|
6
|
+
delay: number;
|
|
7
|
+
};
|
|
8
|
+
/** Presentation only: it neither replaces the page nor acknowledges its commit. */
|
|
9
|
+
export declare function NavigationFallback({ state, options }: {
|
|
10
|
+
state: NavigationState;
|
|
11
|
+
options: NavigationFallbackOptions;
|
|
12
|
+
}): import("hono/jsx/dom/jsx-dev-runtime").JSX.Element | null;
|
|
13
|
+
//# sourceMappingURL=navigation-fallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-fallback.d.ts","sourceRoot":"","sources":["../../src/runtime/navigation-fallback.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,EAAE,EAAE,MAAM,UAAU,CAAC;AAGxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,yBAAyB,GAAG;IAAE,SAAS,EAAE,EAAE,CAAC,uBAAuB,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElG,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,yBAAyB,CAAA;CAAE,6DAqBpH"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "hono/jsx/dom/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'hono/jsx';
|
|
3
|
+
import { ErrorBoundary } from 'hono/jsx/dom';
|
|
4
|
+
import { jsx } from 'hono/jsx/dom/jsx-runtime';
|
|
5
|
+
/** Presentation only: it neither replaces the page nor acknowledges its commit. */
|
|
6
|
+
export function NavigationFallback({ state, options }) {
|
|
7
|
+
const [visibleFor, setVisibleFor] = useState(null);
|
|
8
|
+
const [failedFor, setFailedFor] = useState(null);
|
|
9
|
+
const loading = state.state === 'loading' && state.method === 'GET';
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setVisibleFor(null);
|
|
12
|
+
if (!loading)
|
|
13
|
+
return;
|
|
14
|
+
const timer = setTimeout(() => setVisibleFor(state), options.delay);
|
|
15
|
+
return () => clearTimeout(timer);
|
|
16
|
+
}, [state]);
|
|
17
|
+
// Identity hides the old fallback immediately, before effect cleanup, on every
|
|
18
|
+
// new navigation/idle state. A queued old timer cannot affect another visit.
|
|
19
|
+
if (!loading || visibleFor !== state || failedFor === state)
|
|
20
|
+
return null;
|
|
21
|
+
return _jsx(ErrorBoundary, { fallback: _jsx(_Fragment, {}), onError: error => queueMicrotask(() => {
|
|
22
|
+
// Hono retries a failed child on parent updates. Remove this presentation
|
|
23
|
+
// subtree before reporting the error; a later navigation may try again.
|
|
24
|
+
setFailedFor(state);
|
|
25
|
+
window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));
|
|
26
|
+
}), children: _jsx("div", { "data-hono-navigation-fallback": true, role: "status", "aria-live": "polite", children: jsx(options.component, { navigation: state }) }) });
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=navigation-fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-fallback.js","sourceRoot":"","sources":["../../src/runtime/navigation-fallback.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAW,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,0BAA0B,CAAC;AAM/C,mFAAmF;AACnF,MAAM,UAAU,kBAAkB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAkE;IACnH,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAC;IAC3E,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAyB,IAAI,CAAC,CAAC;IACzE,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC;IACpE,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,CAAC,IAAI,CAAC,CAAC;QACpB,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACpE,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IACZ,+EAA+E;IAC/E,6EAA6E;IAC7E,IAAI,CAAC,OAAO,IAAI,UAAU,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACzE,OAAO,KAAC,aAAa,IAAC,QAAQ,EAAE,mBAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE;YAC3E,0EAA0E;YAC1E,wEAAwE;YACxE,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC1F,CAAC,CAAC,YACA,qDAAmC,IAAI,EAAC,QAAQ,eAAW,QAAQ,YAAE,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,GAAO,GAC3G,CAAC;AACnB,CAAC","sourcesContent":["import { useEffect, useState, type FC } from 'hono/jsx';\nimport { ErrorBoundary } from 'hono/jsx/dom';\nimport { jsx } from 'hono/jsx/dom/jsx-runtime';\nimport type { NavigationState } from 'void/pages-client';\nimport type { NavigationFallbackProps } from './pages.tsx';\n\nexport type NavigationFallbackOptions = { component: FC<NavigationFallbackProps>; delay: number };\n\n/** Presentation only: it neither replaces the page nor acknowledges its commit. */\nexport function NavigationFallback({ state, options }: { state: NavigationState; options: NavigationFallbackOptions }) {\n const [visibleFor, setVisibleFor] = useState<NavigationState | null>(null);\n const [failedFor, setFailedFor] = useState<NavigationState | null>(null);\n const loading = state.state === 'loading' && state.method === 'GET';\n useEffect(() => {\n setVisibleFor(null);\n if (!loading) return;\n const timer = setTimeout(() => setVisibleFor(state), options.delay);\n return () => clearTimeout(timer);\n }, [state]);\n // Identity hides the old fallback immediately, before effect cleanup, on every\n // new navigation/idle state. A queued old timer cannot affect another visit.\n if (!loading || visibleFor !== state || failedFor === state) return null;\n return <ErrorBoundary fallback={<></>} onError={error => queueMicrotask(() => {\n // Hono retries a failed child on parent updates. Remove this presentation\n // subtree before reporting the error; a later navigation may try again.\n setFailedFor(state);\n window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n })}>\n <div data-hono-navigation-fallback role=\"status\" aria-live=\"polite\">{jsx(options.component, { navigation: state })}</div>\n </ErrorBoundary>;\n}\n"]}
|
package/dist/browser/pages.d.ts
CHANGED
|
@@ -3,6 +3,10 @@ import { type NavigationState, type NavigationMethod, type VoidRouter } from 'vo
|
|
|
3
3
|
import type { CacheForInput } from 'void/pages-prefetch';
|
|
4
4
|
import type { PageObject } from 'void/pages-protocol';
|
|
5
5
|
export type { DeferredState as Deferred } from 'void';
|
|
6
|
+
export { deferredResult, type DeferredResult } from './deferred.ts';
|
|
7
|
+
export type NavigationFallbackProps = {
|
|
8
|
+
navigation: NavigationState;
|
|
9
|
+
};
|
|
6
10
|
export declare const action: <U extends import("void/routes").ActionUrl & string>(url: U, ...args: ([import("void/routes").ResolveActionParams<U>] extends [never] ? false : true) extends true ? [options: {
|
|
7
11
|
data?: import("void/routes").ResolveActionBody<U> | undefined;
|
|
8
12
|
method?: "DELETE" | "PATCH" | "POST" | "PUT";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,MAAM,MAAM,uBAAuB,GAAG;IAAE,UAAU,EAAE,eAAe,CAAA;CAAE,CAAC;AAGtE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;yDAAsB,CAAC;AAC1C,eAAO,MAAM,eAAe,8BAA+B,CAAC;AAE5D,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,iBAAiB,oDAA8C,CAAC;AAC7E,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,aAAa,IAAI,eAAe,CAI/C;AAED,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACxE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAc,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EACvH,QAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAC/G,GAAG,UAAU,EAAE,EAAE,SAAS,sDAoD3B"}
|
package/dist/browser/pages.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "hono/jsx/dom/jsx-runtime";
|
|
2
2
|
import { createContext, useContext, useEffect, useRef } from 'hono/jsx';
|
|
3
3
|
import { createActionClient, mergeDataIntoHref } from 'void/pages-client';
|
|
4
|
+
export { deferredResult } from './deferred.js';
|
|
4
5
|
const actionClient = createActionClient();
|
|
5
6
|
export const action = actionClient.action;
|
|
6
7
|
export const setActionRouter = actionClient.setActionRouter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\nexport { deferredResult, type DeferredResult } from './deferred.ts';\nexport type NavigationFallbackProps = { navigation: NavigationState };\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
|
|
@@ -2,6 +2,11 @@ import type { Plugin } from 'vite';
|
|
|
2
2
|
import { type CacheForInput } from 'void/pages-prefetch';
|
|
3
3
|
export type HonoJsxOptions = {
|
|
4
4
|
viewTransitions?: boolean;
|
|
5
|
+
/** A default-exported local TSX/JSX component; keeps the current page mounted. */
|
|
6
|
+
navigationFallback?: {
|
|
7
|
+
component: string;
|
|
8
|
+
delay?: number;
|
|
9
|
+
};
|
|
5
10
|
prefetch?: {
|
|
6
11
|
hoverDelay?: number;
|
|
7
12
|
cacheFor?: CacheForInput;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono-jsx.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAexE,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC;CAC9D,CAAC;AAcF,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"hono-jsx.d.ts","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAexE,MAAM,MAAM,cAAc,GAAG;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kFAAkF;IAClF,kBAAkB,CAAC,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,QAAQ,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,aAAa,CAAA;KAAE,CAAC;CAC9D,CAAC;AAcF,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,OAAO,GAAE,cAAmB,GAAG,MAAM,EAAE,CAqJlE"}
|
package/dist/plugins/hono-jsx.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { realpathSync } from 'node:fs';
|
|
1
|
+
import { realpathSync, statSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { normalizePath } from 'vite';
|
|
4
4
|
import { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.js';
|
|
@@ -38,6 +38,18 @@ function clientOptions(options) {
|
|
|
38
38
|
export function voidHonoJsx(options = {}) {
|
|
39
39
|
const navigationOptions = clientOptions(options);
|
|
40
40
|
const root = process.cwd();
|
|
41
|
+
const fallback = options.navigationFallback;
|
|
42
|
+
let fallbackPath;
|
|
43
|
+
const fallbackDelay = fallback?.delay ?? 150;
|
|
44
|
+
if (fallback !== undefined) {
|
|
45
|
+
if (!fallback || typeof fallback.component !== 'string' || !fallback.component.trim() || !/\.[jt]sx$/.test(fallback.component))
|
|
46
|
+
throw new Error('Hono Pages: navigationFallback.component must name a local TSX/JSX file.');
|
|
47
|
+
if (!Number.isSafeInteger(fallbackDelay) || fallbackDelay < 0 || fallbackDelay > 2147483647)
|
|
48
|
+
throw new Error('Hono Pages: navigationFallback.delay must be an integer from 0 to 2147483647 milliseconds.');
|
|
49
|
+
fallbackPath = normalizePath(realpathSync(resolve(root, fallback.component)));
|
|
50
|
+
if (!statSync(fallbackPath).isFile())
|
|
51
|
+
throw new Error('Hono Pages: navigationFallback.component must be a file.');
|
|
52
|
+
}
|
|
41
53
|
const pagesDir = resolvePagesDir(root);
|
|
42
54
|
const staticData = resolveStaticPageDataBuildOptions(root);
|
|
43
55
|
let scan;
|
|
@@ -177,8 +189,9 @@ export async function renderPage(pageObj, assetTags) {
|
|
|
177
189
|
}
|
|
178
190
|
return `
|
|
179
191
|
import { startHonoPages } from ${JSON.stringify(clientRuntimePath)};
|
|
192
|
+
${fallbackPath ? `import __HonoNavigationFallback from ${JSON.stringify(fallbackPath)};` : ''}
|
|
180
193
|
${manifest}
|
|
181
|
-
await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} },
|
|
194
|
+
await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, { ...${JSON.stringify(navigationOptions)}${fallbackPath ? `, navigationFallback: { component: __HonoNavigationFallback, delay: ${fallbackDelay} }` : ''} });
|
|
182
195
|
`;
|
|
183
196
|
},
|
|
184
197
|
}];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hono-jsx.js","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpathSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { normalizePath } from 'vite';\nimport { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.ts';\nimport { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages, type PageScanResult } from 'void/pages';\nimport type { Plugin } from 'vite';\nimport { parseCacheFor, type CacheForInput } from 'void/pages-prefetch';\nimport { honoJsxTransform } from './jsx-transform.ts';\nimport { honoIslands } from './hono-islands.ts';\nimport { markdownApi, markdownDiagnostic, type HonoMarkdownApi } from './markdown-api.ts';\nimport { assertSupportedFrameworks } from './compatibility.ts';\n\nconst rendererId = 'virtual:void-pages-renderer';\nconst clientId = 'virtual:void-pages-client';\n\nfunction assertComponentFile(file: string, kind: 'page' | 'layout', markdown = false) {\n if (/\\.md$/.test(file)) { if (markdown && kind === 'page') return; if (markdown) throw new Error('Hono Markdown: layouts must remain TSX/JSX: ' + file); throw new Error(`${markdownDiagnostic} ${kind}: ${file}`); }\n if (!/\\.[jt]sx$/.test(file)) throw new Error(`Hono Pages: only standard TSX/JSX ${kind}s are supported: ${file}.`);\n}\n\n\nexport type HonoJsxOptions = {\n viewTransitions?: boolean;\n prefetch?: { hoverDelay?: number; cacheFor?: CacheForInput };\n};\n\nfunction clientOptions(options: HonoJsxOptions) {\n const viewTransitions = options.viewTransitions ?? false;\n const prefetchHoverDelay = options.prefetch?.hoverDelay ?? 75;\n if (typeof viewTransitions !== 'boolean') throw new Error('Hono Pages: viewTransitions must be a boolean.');\n if (!Number.isFinite(prefetchHoverDelay) || prefetchHoverDelay < 0) throw new Error('Hono Pages: prefetch.hoverDelay must be a finite non-negative number.');\n const prefetchDefaultCacheFor = parseCacheFor(options.prefetch?.cacheFor ?? '30s');\n if (![prefetchDefaultCacheFor.stale, prefetchDefaultCacheFor.expires].every(value => Number.isFinite(value) && value >= 0) || prefetchDefaultCacheFor.stale > prefetchDefaultCacheFor.expires) {\n throw new Error('Hono Pages: prefetch.cacheFor must have finite non-negative durations, with stale <= expires.');\n }\n return { viewTransitions, prefetchHoverDelay, prefetchDefaultCacheFor };\n}\n\n/** Compose Hono JSX transformation, Pages and islands using verified Void contracts. */\nexport function voidHonoJsx(options: HonoJsxOptions = {}): Plugin[] {\n const navigationOptions = clientOptions(options);\n const root = process.cwd();\n const pagesDir = resolvePagesDir(root);\n const staticData = resolveStaticPageDataBuildOptions(root);\n let scan: PageScanResult | undefined;\n let markdown: HonoMarkdownApi | undefined;\n\n async function rescan() {\n scan = await scanPages(root, { pagesDir });\n for (const layout of [...scan.layouts, ...scan.namedLayouts]) {\n assertComponentFile(layout.filePath, 'layout');\n }\n for (const page of scan.pages) {\n assertComponentFile(page.componentPath, 'page', Boolean(markdown));\n if (staticData.enabled && page.methods.some((method) => method === 'action' || method === 'actions')) {\n throw new Error(`Hono Pages: actions require a server and cannot be used with static output: ${page.componentPath}.`);\n }\n }\n return scan;\n }\n\n return [honoIslands(), honoJsxTransform(), {\n name: 'void-hono:pages',\n enforce: 'pre',\n config(config) {\n assertSupportedFrameworks({ root: resolve(config.root ?? root), viteVersion: this?.meta?.viteVersion });\n return {\n resolve: { dedupe: ['hono'] },\n build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },\n };\n },\n configResolved: {\n order: 'pre',\n handler(config) {\n markdown = markdownApi(config.plugins);\n },\n },\n configEnvironment() {\n const modules = Object.keys(publicRuntimeModules);\n const packages = [...new Set(modules.map((id) => id.slice(0, id.lastIndexOf('/'))))];\n return { optimizeDeps: { exclude: ['hono', ...modules] }, resolve: { noExternal: ['hono', ...packages] } };\n },\n async buildStart() {\n await rescan();\n },\n configureServer(server) {\n const clear = (file: string) => {\n if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) scan = undefined;\n };\n server.watcher.on('add', clear);\n server.watcher.on('unlink', clear);\n server.httpServer?.once('close', () => { server.watcher.off('add', clear); server.watcher.off('unlink', clear); });\n },\n async hotUpdate({ file, type, modules, timestamp }) {\n if (!normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n await rescan();\n if (type !== 'update') return [];\n const invalidated = new Set<(typeof modules)[number]>();\n for (const module of modules) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n for (const id of [rendererId, clientId]) {\n const module = this.environment.moduleGraph.getModuleById(`\\0${id}`);\n if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n }\n this.environment.hot.send({ type: 'full-reload' });\n return [];\n },\n resolveId(id) {\n if (id === rendererId || id === clientId) return `\\0${id}`;\n if (id === pagesRuntimePath || id === clientRuntimePath || id === markdownRuntimePath) return { id: realpathSync(id), external: false };\n const runtime = publicRuntimeModules[id];\n if (runtime) return { id: realpathSync(this.environment.config.consumer === 'client' ? runtime.client : runtime.server), external: false };\n },\n async load(id) {\n if (id !== `\\0${rendererId}` && id !== `\\0${clientId}`) return;\n const currentScan = scan ?? await rescan();\n const serverSnapshot = id === `\\0${rendererId}` && this.environment.mode === 'dev';\n const manifestScan = id === `\\0${clientId}`\n ? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island), layouts: currentScan.layouts.filter((layout) => !layout.island), namedLayouts: currentScan.namedLayouts.filter((layout) => !layout.island) }\n : serverSnapshot ? { ...currentScan, pages: currentScan.pages.filter((page) => page.renderMode !== 'client') } : currentScan;\n let manifest = generateComponentManifest(manifestScan, pagesDir);\n if (serverSnapshot) {\n // A request can retain the old renderer while the worker module runner\n // reloads. Capture components with its providers instead of importing\n // a new generation into an in-flight render. Browser-only pages remain\n // absent from this server graph; production keeps lazy imports.\n const imports: string[] = [];\n manifest = manifest.replace(/\\(\\) => import\\((\"(?:[^\"\\\\]|\\\\.)*\")\\)/g, (_, path: string) => {\n const name = `__honoPageSnapshot${imports.length}`;\n imports.push(`import * as ${name} from ${path};`);\n return `() => ${name}`;\n });\n manifest = imports.join('\\n') + '\\n' + manifest;\n }\n if (id === `\\0${clientId}` && !currentScan.pages.some((page) => !page.island)) return 'export {};';\n if (id === `\\0${rendererId}`) {\n const markdownScriptIds = [...(markdown?.getClientScripts().keys() ?? [])];\n return `\nimport { jsx } from 'hono/jsx';\n${markdown ? `import { MarkdownContext } from ${JSON.stringify(markdownRuntimePath)};` : ''}\nconst markdownScriptIds = new Set(${JSON.stringify(markdownScriptIds)});\nimport { createSsrRouter, idleNavigationState } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext } from ${JSON.stringify(pagesRuntimePath)};\nimport { serializePageData } from 'void/pages-server';\nimport { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from 'void/pages-head';\n${manifest}\nexport async function renderPage(pageObj, assetTags) {\n if (${JSON.stringify(staticData.enabled)} && pageObj.deferredKeys) throw new Error('Hono Pages: deferred props cannot be statically prerendered; remove defer().');\n const load = components[pageObj.component];\n if (!load) throw new Error('Hono Pages: unknown page component ' + pageObj.component);\n const { default: Page, frontmatter = {}, headings = [] } = await load();\n if (typeof Page !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n let content = jsx(Page, pageObj.props);\n const ids = layoutTree[pageObj.component] ?? [];\n const layouts = await Promise.all(ids.map(async (id) => (await components[id]()).default));\n for (const Layout of layouts.reverse()) {\n if (typeof Layout !== 'function') throw new Error('Hono Pages: a layout must export a component function.');\n content = jsx(Layout, { children: content });\n }\n ${markdown ? 'content = jsx(MarkdownContext.Provider, { value: { frontmatter, headings, props: pageObj.props }, children: content });' : ''}\n const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: jsx(NavigationContext.Provider, { value: idleNavigationState(), children: content }) }) }).toString();\n const appHtml = await jsx('div', { id: 'app', 'data-md-script': markdownScriptIds.has(pageObj.component) ? pageObj.component : undefined, ${markdown ? \"'data-hono-markdown': JSON.stringify({ frontmatter, headings }),\" : ''} dangerouslySetInnerHTML: { __html: markup } }).toString();\n const head = pageObj.head;\n const body = pageObj.deferredKeys ? assetTags.body.replaceAll('<script type=\"module\"', '<script async type=\"module\"') : assetTags.body;\n return '<!doctype html><html' + (head ? renderHtmlAttrs(head) : '') + '><head>'\n + (head ? renderHeadToString(head) : '') + assetTags.css + assetTags.preloads\n + '</head><body' + (head ? renderBodyAttrs(head) : '') + '>'\n + '<script id=\"__VOID_PAGE_DATA__\" type=\"application/json\">' + serializePageData(pageObj) + '</script>'\n + appHtml + body + '</body></html>';\n}\n`;\n }\n return `\nimport { startHonoPages } from ${JSON.stringify(clientRuntimePath)};\n${manifest}\nawait startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, ${JSON.stringify(navigationOptions)});\n`;\n },\n }];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hono-jsx.js","sourceRoot":"","sources":["../../src/plugins/hono-jsx.ts"],"names":[],"mappings":"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","sourcesContent":["import { realpathSync, statSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { normalizePath } from 'vite';\nimport { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.ts';\nimport { generateComponentManifest, resolvePagesDir, resolveStaticPageDataBuildOptions, scanPages, type PageScanResult } from 'void/pages';\nimport type { Plugin } from 'vite';\nimport { parseCacheFor, type CacheForInput } from 'void/pages-prefetch';\nimport { honoJsxTransform } from './jsx-transform.ts';\nimport { honoIslands } from './hono-islands.ts';\nimport { markdownApi, markdownDiagnostic, type HonoMarkdownApi } from './markdown-api.ts';\nimport { assertSupportedFrameworks } from './compatibility.ts';\n\nconst rendererId = 'virtual:void-pages-renderer';\nconst clientId = 'virtual:void-pages-client';\n\nfunction assertComponentFile(file: string, kind: 'page' | 'layout', markdown = false) {\n if (/\\.md$/.test(file)) { if (markdown && kind === 'page') return; if (markdown) throw new Error('Hono Markdown: layouts must remain TSX/JSX: ' + file); throw new Error(`${markdownDiagnostic} ${kind}: ${file}`); }\n if (!/\\.[jt]sx$/.test(file)) throw new Error(`Hono Pages: only standard TSX/JSX ${kind}s are supported: ${file}.`);\n}\n\n\nexport type HonoJsxOptions = {\n viewTransitions?: boolean;\n /** A default-exported local TSX/JSX component; keeps the current page mounted. */\n navigationFallback?: { component: string; delay?: number };\n prefetch?: { hoverDelay?: number; cacheFor?: CacheForInput };\n};\n\nfunction clientOptions(options: HonoJsxOptions) {\n const viewTransitions = options.viewTransitions ?? false;\n const prefetchHoverDelay = options.prefetch?.hoverDelay ?? 75;\n if (typeof viewTransitions !== 'boolean') throw new Error('Hono Pages: viewTransitions must be a boolean.');\n if (!Number.isFinite(prefetchHoverDelay) || prefetchHoverDelay < 0) throw new Error('Hono Pages: prefetch.hoverDelay must be a finite non-negative number.');\n const prefetchDefaultCacheFor = parseCacheFor(options.prefetch?.cacheFor ?? '30s');\n if (![prefetchDefaultCacheFor.stale, prefetchDefaultCacheFor.expires].every(value => Number.isFinite(value) && value >= 0) || prefetchDefaultCacheFor.stale > prefetchDefaultCacheFor.expires) {\n throw new Error('Hono Pages: prefetch.cacheFor must have finite non-negative durations, with stale <= expires.');\n }\n return { viewTransitions, prefetchHoverDelay, prefetchDefaultCacheFor };\n}\n\n/** Compose Hono JSX transformation, Pages and islands using verified Void contracts. */\nexport function voidHonoJsx(options: HonoJsxOptions = {}): Plugin[] {\n const navigationOptions = clientOptions(options);\n const root = process.cwd();\n const fallback = options.navigationFallback;\n let fallbackPath: string | undefined;\n const fallbackDelay = fallback?.delay ?? 150;\n if (fallback !== undefined) {\n if (!fallback || typeof fallback.component !== 'string' || !fallback.component.trim() || !/\\.[jt]sx$/.test(fallback.component)) throw new Error('Hono Pages: navigationFallback.component must name a local TSX/JSX file.');\n if (!Number.isSafeInteger(fallbackDelay) || fallbackDelay < 0 || fallbackDelay > 2147483647) throw new Error('Hono Pages: navigationFallback.delay must be an integer from 0 to 2147483647 milliseconds.');\n fallbackPath = normalizePath(realpathSync(resolve(root, fallback.component)));\n if (!statSync(fallbackPath).isFile()) throw new Error('Hono Pages: navigationFallback.component must be a file.');\n }\n const pagesDir = resolvePagesDir(root);\n const staticData = resolveStaticPageDataBuildOptions(root);\n let scan: PageScanResult | undefined;\n let markdown: HonoMarkdownApi | undefined;\n\n async function rescan() {\n scan = await scanPages(root, { pagesDir });\n for (const layout of [...scan.layouts, ...scan.namedLayouts]) {\n assertComponentFile(layout.filePath, 'layout');\n }\n for (const page of scan.pages) {\n assertComponentFile(page.componentPath, 'page', Boolean(markdown));\n if (staticData.enabled && page.methods.some((method) => method === 'action' || method === 'actions')) {\n throw new Error(`Hono Pages: actions require a server and cannot be used with static output: ${page.componentPath}.`);\n }\n }\n return scan;\n }\n\n return [honoIslands(), honoJsxTransform(), {\n name: 'void-hono:pages',\n enforce: 'pre',\n config(config) {\n assertSupportedFrameworks({ root: resolve(config.root ?? root), viteVersion: this?.meta?.viteVersion });\n return {\n resolve: { dedupe: ['hono'] },\n build: { manifest: true, rollupOptions: { input: { 'pages-client': clientId } } },\n };\n },\n configResolved: {\n order: 'pre',\n handler(config) {\n markdown = markdownApi(config.plugins);\n },\n },\n configEnvironment() {\n const modules = Object.keys(publicRuntimeModules);\n const packages = [...new Set(modules.map((id) => id.slice(0, id.lastIndexOf('/'))))];\n return { optimizeDeps: { exclude: ['hono', ...modules] }, resolve: { noExternal: ['hono', ...packages] } };\n },\n async buildStart() {\n await rescan();\n },\n configureServer(server) {\n const clear = (file: string) => {\n if (normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) scan = undefined;\n };\n server.watcher.on('add', clear);\n server.watcher.on('unlink', clear);\n server.httpServer?.once('close', () => { server.watcher.off('add', clear); server.watcher.off('unlink', clear); });\n },\n async hotUpdate({ file, type, modules, timestamp }) {\n if (!normalizePath(file).startsWith(normalizePath(pagesDir) + '/')) return;\n await rescan();\n if (type !== 'update') return [];\n const invalidated = new Set<(typeof modules)[number]>();\n for (const module of modules) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n for (const id of [rendererId, clientId]) {\n const module = this.environment.moduleGraph.getModuleById(`\\0${id}`);\n if (module) this.environment.moduleGraph.invalidateModule(module, invalidated, timestamp, true);\n }\n this.environment.hot.send({ type: 'full-reload' });\n return [];\n },\n resolveId(id) {\n if (id === rendererId || id === clientId) return `\\0${id}`;\n if (id === pagesRuntimePath || id === clientRuntimePath || id === markdownRuntimePath) return { id: realpathSync(id), external: false };\n const runtime = publicRuntimeModules[id];\n if (runtime) return { id: realpathSync(this.environment.config.consumer === 'client' ? runtime.client : runtime.server), external: false };\n },\n async load(id) {\n if (id !== `\\0${rendererId}` && id !== `\\0${clientId}`) return;\n const currentScan = scan ?? await rescan();\n const serverSnapshot = id === `\\0${rendererId}` && this.environment.mode === 'dev';\n const manifestScan = id === `\\0${clientId}`\n ? { ...currentScan, pages: currentScan.pages.filter((page) => !page.island), layouts: currentScan.layouts.filter((layout) => !layout.island), namedLayouts: currentScan.namedLayouts.filter((layout) => !layout.island) }\n : serverSnapshot ? { ...currentScan, pages: currentScan.pages.filter((page) => page.renderMode !== 'client') } : currentScan;\n let manifest = generateComponentManifest(manifestScan, pagesDir);\n if (serverSnapshot) {\n // A request can retain the old renderer while the worker module runner\n // reloads. Capture components with its providers instead of importing\n // a new generation into an in-flight render. Browser-only pages remain\n // absent from this server graph; production keeps lazy imports.\n const imports: string[] = [];\n manifest = manifest.replace(/\\(\\) => import\\((\"(?:[^\"\\\\]|\\\\.)*\")\\)/g, (_, path: string) => {\n const name = `__honoPageSnapshot${imports.length}`;\n imports.push(`import * as ${name} from ${path};`);\n return `() => ${name}`;\n });\n manifest = imports.join('\\n') + '\\n' + manifest;\n }\n if (id === `\\0${clientId}` && !currentScan.pages.some((page) => !page.island)) return 'export {};';\n if (id === `\\0${rendererId}`) {\n const markdownScriptIds = [...(markdown?.getClientScripts().keys() ?? [])];\n return `\nimport { jsx } from 'hono/jsx';\n${markdown ? `import { MarkdownContext } from ${JSON.stringify(markdownRuntimePath)};` : ''}\nconst markdownScriptIds = new Set(${JSON.stringify(markdownScriptIds)});\nimport { createSsrRouter, idleNavigationState } from 'void/pages-client';\nimport { PageContext, RouterContext, NavigationContext } from ${JSON.stringify(pagesRuntimePath)};\nimport { serializePageData } from 'void/pages-server';\nimport { renderHeadToString, renderHtmlAttrs, renderBodyAttrs } from 'void/pages-head';\n${manifest}\nexport async function renderPage(pageObj, assetTags) {\n if (${JSON.stringify(staticData.enabled)} && pageObj.deferredKeys) throw new Error('Hono Pages: deferred props cannot be statically prerendered; remove defer().');\n const load = components[pageObj.component];\n if (!load) throw new Error('Hono Pages: unknown page component ' + pageObj.component);\n const { default: Page, frontmatter = {}, headings = [] } = await load();\n if (typeof Page !== 'function') throw new Error('Hono Pages: a page must export a component function.');\n let content = jsx(Page, pageObj.props);\n const ids = layoutTree[pageObj.component] ?? [];\n const layouts = await Promise.all(ids.map(async (id) => (await components[id]()).default));\n for (const Layout of layouts.reverse()) {\n if (typeof Layout !== 'function') throw new Error('Hono Pages: a layout must export a component function.');\n content = jsx(Layout, { children: content });\n }\n ${markdown ? 'content = jsx(MarkdownContext.Provider, { value: { frontmatter, headings, props: pageObj.props }, children: content });' : ''}\n const markup = await jsx(RouterContext.Provider, { value: createSsrRouter(pageObj.url, pageObj.params), children: jsx(PageContext.Provider, { value: pageObj, children: jsx(NavigationContext.Provider, { value: idleNavigationState(), children: content }) }) }).toString();\n const appHtml = await jsx('div', { id: 'app', 'data-md-script': markdownScriptIds.has(pageObj.component) ? pageObj.component : undefined, ${markdown ? \"'data-hono-markdown': JSON.stringify({ frontmatter, headings }),\" : ''} dangerouslySetInnerHTML: { __html: markup } }).toString();\n const head = pageObj.head;\n const body = pageObj.deferredKeys ? assetTags.body.replaceAll('<script type=\"module\"', '<script async type=\"module\"') : assetTags.body;\n return '<!doctype html><html' + (head ? renderHtmlAttrs(head) : '') + '><head>'\n + (head ? renderHeadToString(head) : '') + assetTags.css + assetTags.preloads\n + '</head><body' + (head ? renderBodyAttrs(head) : '') + '>'\n + '<script id=\"__VOID_PAGE_DATA__\" type=\"application/json\">' + serializePageData(pageObj) + '</script>'\n + appHtml + body + '</body></html>';\n}\n`;\n }\n return `\nimport { startHonoPages } from ${JSON.stringify(clientRuntimePath)};\n${fallbackPath ? `import __HonoNavigationFallback from ${JSON.stringify(fallbackPath)};` : ''}\n${manifest}\nawait startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, { ...${JSON.stringify(navigationOptions)}${fallbackPath ? `, navigationFallback: { component: __HonoNavigationFallback, delay: ${fallbackDelay} }` : ''} });\n`;\n },\n }];\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DeferredState } from 'void';
|
|
2
|
+
/** Null from an upstream completed prefetch remains null, not a repaired error. */
|
|
3
|
+
export type DeferredResult<T> = {
|
|
4
|
+
value: T | null;
|
|
5
|
+
error: null;
|
|
6
|
+
} | {
|
|
7
|
+
value: null;
|
|
8
|
+
error: Error;
|
|
9
|
+
};
|
|
10
|
+
/** A stable, render-only Promise; Void still owns all execution and delivery. */
|
|
11
|
+
export declare function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>>;
|
|
12
|
+
export declare function createDeferred(): DeferredState<never>;
|
|
13
|
+
export declare function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown>;
|
|
14
|
+
export declare function rejectDeferred(ref: unknown, message: string): DeferredState<never>;
|
|
15
|
+
export declare function isLoading(ref: unknown): boolean;
|
|
16
|
+
declare global {
|
|
17
|
+
interface Window {
|
|
18
|
+
__resolveDeferred?: (group: string, data: unknown) => void;
|
|
19
|
+
__rejectDeferred?: (group: string, error: string) => void;
|
|
20
|
+
__deferredQueue?: Array<[string, unknown] | [string, 0, string]>;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export declare function bufferInitialDeferred(): () => void;
|
|
24
|
+
//# sourceMappingURL=deferred.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE1C,mFAAmF;AACnF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAejG,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAQrF;AAWD,wBAAgB,cAAc,IAAI,aAAa,CAAC,KAAK,CAAC,CAErD;AACD,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAEpF;AACD,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAElF;AACD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C;AAID,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QAC3D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;QAC1D,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;KAClE;CACF;AACD,wBAAgB,qBAAqB,eASpC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const resources = new WeakMap();
|
|
2
|
+
function resourceFor(ref) {
|
|
3
|
+
if (typeof ref !== 'object' || ref === null)
|
|
4
|
+
throw new Error('Hono Pages: deferredResult requires a Deferred state.');
|
|
5
|
+
let resource = resources.get(ref);
|
|
6
|
+
if (!resource)
|
|
7
|
+
resources.set(ref, resource = {});
|
|
8
|
+
return resource;
|
|
9
|
+
}
|
|
10
|
+
/** A stable, render-only Promise; Void still owns all execution and delivery. */
|
|
11
|
+
export function deferredResult(state) {
|
|
12
|
+
const resource = resourceFor(state);
|
|
13
|
+
// SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR
|
|
14
|
+
// HTML callback to client-owned completion or wait for it on the server.
|
|
15
|
+
if (typeof window === 'undefined')
|
|
16
|
+
return (resource.serverPromise ??= new Promise(() => { }));
|
|
17
|
+
if (!state.loading && !resource.result)
|
|
18
|
+
resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };
|
|
19
|
+
resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });
|
|
20
|
+
return resource.promise;
|
|
21
|
+
}
|
|
22
|
+
function complete(ref, next) {
|
|
23
|
+
const resource = resourceFor(ref);
|
|
24
|
+
resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };
|
|
25
|
+
resource.resolve?.(resource.result);
|
|
26
|
+
resource.resolve = undefined;
|
|
27
|
+
// Void replaces its state object on completion. Both objects refer to the
|
|
28
|
+
// same lazy Promise, including completion before component import/use().
|
|
29
|
+
resources.set(next, resource);
|
|
30
|
+
return next;
|
|
31
|
+
}
|
|
32
|
+
export function createDeferred() {
|
|
33
|
+
return { loading: true, value: null, error: null };
|
|
34
|
+
}
|
|
35
|
+
export function resolveDeferred(ref, value) {
|
|
36
|
+
return complete(ref, { loading: false, value, error: null });
|
|
37
|
+
}
|
|
38
|
+
export function rejectDeferred(ref, message) {
|
|
39
|
+
return complete(ref, { loading: false, value: null, error: new Error(message) });
|
|
40
|
+
}
|
|
41
|
+
export function isLoading(ref) {
|
|
42
|
+
return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;
|
|
43
|
+
}
|
|
44
|
+
export function bufferInitialDeferred() {
|
|
45
|
+
const resolve = window.__resolveDeferred;
|
|
46
|
+
const reject = window.__rejectDeferred;
|
|
47
|
+
window.__resolveDeferred = (group, data) => (window.__deferredQueue ??= []).push([group, data]);
|
|
48
|
+
window.__rejectDeferred = (group, error) => (window.__deferredQueue ??= []).push([group, 0, error]);
|
|
49
|
+
return () => {
|
|
50
|
+
window.__resolveDeferred = resolve;
|
|
51
|
+
window.__rejectDeferred = reject;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=deferred.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/runtime/deferred.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DeferredState } from 'void';\n\n/** Null from an upstream completed prefetch remains null, not a repaired error. */\nexport type DeferredResult<T> = { value: T | null; error: null } | { value: null; error: Error };\ntype Resource = {\n result?: DeferredResult<unknown>;\n promise?: Promise<DeferredResult<unknown>>;\n serverPromise?: Promise<DeferredResult<unknown>>;\n resolve?: (result: DeferredResult<unknown>) => void;\n};\nconst resources = new WeakMap<object, Resource>();\nfunction resourceFor(ref: unknown): Resource {\n if (typeof ref !== 'object' || ref === null) throw new Error('Hono Pages: deferredResult requires a Deferred state.');\n let resource = resources.get(ref);\n if (!resource) resources.set(ref, resource = {});\n return resource;\n}\n\n/** A stable, render-only Promise; Void still owns all execution and delivery. */\nexport function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>> {\n const resource = resourceFor(state);\n // SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR\n // HTML callback to client-owned completion or wait for it on the server.\n if (typeof window === 'undefined') return (resource.serverPromise ??= new Promise(() => {})) as Promise<DeferredResult<T>>;\n if (!state.loading && !resource.result) resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };\n resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });\n return resource.promise as Promise<DeferredResult<T>>;\n}\nfunction complete(ref: unknown, next: DeferredState<unknown>) {\n const resource = resourceFor(ref);\n resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };\n resource.resolve?.(resource.result);\n resource.resolve = undefined;\n // Void replaces its state object on completion. Both objects refer to the\n // same lazy Promise, including completion before component import/use().\n resources.set(next, resource);\n return next;\n}\nexport function createDeferred(): DeferredState<never> {\n return { loading: true, value: null, error: null };\n}\nexport function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown> {\n return complete(ref, { loading: false, value, error: null });\n}\nexport function rejectDeferred(ref: unknown, message: string): DeferredState<never> {\n return complete(ref, { loading: false, value: null, error: new Error(message) }) as DeferredState<never>;\n}\nexport function isLoading(ref: unknown): boolean {\n return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;\n}\n\n// Void installs its HTML callbacks before awaiting component imports. Keep early\n// messages in its existing queue until the initial deferred registry is ready.\ndeclare global {\n interface Window {\n __resolveDeferred?: (group: string, data: unknown) => void;\n __rejectDeferred?: (group: string, error: string) => void;\n __deferredQueue?: Array<[string, unknown] | [string, 0, string]>;\n }\n}\nexport function bufferInitialDeferred() {\n const resolve = window.__resolveDeferred;\n const reject = window.__rejectDeferred;\n window.__resolveDeferred = (group, data) => (window.__deferredQueue ??= []).push([group, data]);\n window.__rejectDeferred = (group, error) => (window.__deferredQueue ??= []).push([group, 0, error]);\n return () => {\n window.__resolveDeferred = resolve;\n window.__rejectDeferred = reject;\n };\n}\n"]}
|
package/dist/server/pages.d.ts
CHANGED
|
@@ -3,6 +3,10 @@ import { type NavigationState, type NavigationMethod, type VoidRouter } from 'vo
|
|
|
3
3
|
import type { CacheForInput } from 'void/pages-prefetch';
|
|
4
4
|
import type { PageObject } from 'void/pages-protocol';
|
|
5
5
|
export type { DeferredState as Deferred } from 'void';
|
|
6
|
+
export { deferredResult, type DeferredResult } from './deferred.ts';
|
|
7
|
+
export type NavigationFallbackProps = {
|
|
8
|
+
navigation: NavigationState;
|
|
9
|
+
};
|
|
6
10
|
export declare const action: <U extends import("void/routes").ActionUrl & string>(url: U, ...args: ([import("void/routes").ResolveActionParams<U>] extends [never] ? false : true) extends true ? [options: {
|
|
7
11
|
data?: import("void/routes").ResolveActionBody<U> | undefined;
|
|
8
12
|
method?: "DELETE" | "PATCH" | "POST" | "PUT";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgD,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAyC,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACxI,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,YAAY,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,MAAM,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,MAAM,MAAM,uBAAuB,GAAG;IAAE,UAAU,EAAE,eAAe,CAAA;CAAE,CAAC;AAGtE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;yDAAsB,CAAC;AAC1C,eAAO,MAAM,eAAe,8BAA+B,CAAC;AAE5D,eAAO,MAAM,aAAa,+CAAyC,CAAC;AACpE,eAAO,MAAM,iBAAiB,oDAA8C,CAAC;AAC7E,eAAO,MAAM,WAAW,+CAAyC,CAAC;AAQlE,wBAAgB,aAAa,IAAI,eAAe,CAI/C;AAED,wBAAgB,SAAS,4BAA+B;AACxD,wBAAgB,SAAS,2BAA+B;AACxD,wBAAgB,SAAS,2BAAqC;AAE9D,wBAAgB,SAAS,IAAI,UAAU,CAItC;AAED,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;AACvE,MAAM,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,GAAG,gBAAgB,GAAG,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACxE,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,cAAc,IAAI,IAAI,CAAA;KAAE,KAAK,IAAI,CAAC;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC,CAAC;AAEF,wBAAgB,IAAI,CAAC,EAAE,IAAI,EAAE,MAAc,EAAE,IAAI,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,OAAO,EAAE,cAAc,EACvH,QAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,YAAY,EAC/G,GAAG,UAAU,EAAE,EAAE,SAAS,kDAoD3B"}
|
package/dist/server/pages.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "hono/jsx/jsx-runtime";
|
|
2
2
|
import { createContext, useContext, useEffect, useRef } from 'hono/jsx';
|
|
3
3
|
import { createActionClient, mergeDataIntoHref } from 'void/pages-client';
|
|
4
|
+
export { deferredResult } from './deferred.js';
|
|
4
5
|
const actionClient = createActionClient();
|
|
5
6
|
export const action = actionClient.action;
|
|
6
7
|
export const setActionRouter = actionClient.setActionRouter;
|
package/dist/server/pages.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"pages.js","sourceRoot":"","sources":["../../src/runtime/pages.tsx"],"names":[],"mappings":"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","sourcesContent":["import { createContext, useContext, useEffect, useRef, type JSX } from 'hono/jsx';\nimport { createActionClient, mergeDataIntoHref, type NavigationState, type NavigationMethod, type VoidRouter } from 'void/pages-client';\nimport type { CacheForInput } from 'void/pages-prefetch';\nimport type { PageObject } from 'void/pages-protocol';\nexport type { DeferredState as Deferred } from 'void';\nexport { deferredResult, type DeferredResult } from './deferred.ts';\nexport type NavigationFallbackProps = { navigation: NavigationState };\n\nconst actionClient = createActionClient();\nexport const action = actionClient.action;\nexport const setActionRouter = actionClient.setActionRouter;\n\nexport const RouterContext = createContext<VoidRouter | null>(null);\nexport const NavigationContext = createContext<NavigationState | null>(null);\nexport const PageContext = createContext<PageObject | null>(null);\n\nfunction usePage() {\n const page = useContext(PageContext);\n if (!page) throw new Error('Hono Pages: page data requires a page provider.');\n return page;\n}\n\nexport function useNavigation(): NavigationState {\n const navigation = useContext(NavigationContext);\n if (!navigation) throw new Error('Hono Pages: useNavigation requires a page provider.');\n return navigation;\n}\n\nexport function useShared() { return usePage().shared; }\nexport function useParams() { return usePage().params; }\nexport function useErrors() { return usePage().errors ?? {}; }\n\nexport function useRouter(): VoidRouter {\n const router = useContext(RouterContext);\n if (!router) throw new Error('Hono Pages: useRouter requires a page provider.');\n return router;\n}\n\nexport type PrefetchStrategy = 'hover' | 'click' | 'mount' | 'visible';\nexport type LinkProps = Omit<JSX.IntrinsicElements['a'], 'href' | 'onClick'> & {\n href: string;\n method?: NavigationMethod | Lowercase<NavigationMethod>;\n data?: Record<string, unknown>;\n preserveScroll?: boolean;\n preserveState?: boolean;\n reloadDocument?: boolean;\n replace?: boolean;\n viewTransition?: boolean;\n prefetch?: boolean | PrefetchStrategy | ReadonlyArray<PrefetchStrategy>;\n cacheFor?: CacheForInput;\n onNavigate?: (event: { preventDefault(): void }) => void;\n onClick?: (event: MouseEvent) => void;\n};\n\nexport function Link({ href, method = 'GET', data, preserveScroll, preserveState, reloadDocument, replace, viewTransition,\n prefetch = false, cacheFor, onNavigate, onClick, onMouseEnter, onMouseLeave, onFocus, onMouseDown, onTouchStart,\n ...attributes }: LinkProps) {\n const router = useRouter();\n const element = useRef<HTMLAnchorElement | HTMLButtonElement | null>(null);\n const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const normalized = method.toUpperCase();\n const get = normalized === 'GET';\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(normalized)) throw new Error('Hono Link: unsupported method.');\n if (!get && (prefetch !== false || reloadDocument)) throw new Error('Hono Link: prefetch and reloadDocument only support GET links.');\n const destination = get ? mergeDataIntoHref(href, data) : href;\n const strategies = reloadDocument || prefetch === false ? [] : prefetch === true ? ['hover'] : typeof prefetch === 'string' ? [prefetch] : prefetch;\n if (strategies.some((strategy) => !['hover', 'click', 'mount', 'visible'].includes(strategy))) throw new Error('Hono Link: unsupported prefetch strategy.');\n const clear = () => { clearTimeout(timer.current); timer.current = undefined; };\n const canHandle = () => {\n const url = new URL(destination, window.location.href);\n return !reloadDocument && attributes.download === undefined && (!attributes.target || attributes.target === '_self') &&\n !attributes.rel?.split(/\\s+/).includes('external') && url.origin === window.location.origin && ['http:', 'https:'].includes(url.protocol);\n };\n const report = (error: unknown) => window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));\n const fetchAhead = () => {\n if (canHandle()) void router.prefetch(destination, { cacheFor }).catch(report);\n };\n useEffect(() => {\n if (strategies.includes('mount')) fetchAhead();\n let observer: IntersectionObserver | undefined;\n if (strategies.includes('visible') && element.current) {\n observer = new IntersectionObserver((entries) => {\n if (entries.some((entry) => entry.isIntersecting)) { observer?.disconnect(); fetchAhead(); }\n });\n observer.observe(element.current);\n }\n return () => { clear(); observer?.disconnect(); };\n }, [destination, prefetch, cacheFor, reloadDocument, router]);\n const events = {\n onClick(event: MouseEvent) {\n onClick?.(event);\n if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || !canHandle()) return;\n let cancelled = false;\n onNavigate?.({ preventDefault() { cancelled = true; } });\n event.preventDefault();\n if (!cancelled) void router.visit(new URL(destination, window.location.href), { method: normalized, data: get ? undefined : data, preserveScroll, preserveState, replace, viewTransition }).catch(report);\n },\n onMouseEnter(event: MouseEvent) {\n onMouseEnter?.(event); clear();\n if (!event.defaultPrevented && strategies.includes('hover')) timer.current = setTimeout(fetchAhead, router._hoverDelay);\n },\n onMouseLeave(event: MouseEvent) { onMouseLeave?.(event); clear(); },\n onFocus(event: FocusEvent) { onFocus?.(event); if (!event.defaultPrevented && strategies.includes('hover')) fetchAhead(); },\n onMouseDown(event: MouseEvent) { onMouseDown?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n onTouchStart(event: TouchEvent) { onTouchStart?.(event); if (!event.defaultPrevented && strategies.includes('click')) fetchAhead(); },\n };\n if (get) return <a {...attributes} {...events} ref={element} href={destination} />;\n return <button {...attributes} {...events} ref={element} type=\"button\" />;\n}\n"]}
|
package/package.json
CHANGED
package/src/plugins/hono-jsx.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { realpathSync } from 'node:fs';
|
|
1
|
+
import { realpathSync, statSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { normalizePath } from 'vite';
|
|
4
4
|
import { pagesRuntimePath, clientRuntimePath, markdownRuntimePath, publicRuntimeModules } from './runtime-paths.ts';
|
|
@@ -21,6 +21,8 @@ function assertComponentFile(file: string, kind: 'page' | 'layout', markdown = f
|
|
|
21
21
|
|
|
22
22
|
export type HonoJsxOptions = {
|
|
23
23
|
viewTransitions?: boolean;
|
|
24
|
+
/** A default-exported local TSX/JSX component; keeps the current page mounted. */
|
|
25
|
+
navigationFallback?: { component: string; delay?: number };
|
|
24
26
|
prefetch?: { hoverDelay?: number; cacheFor?: CacheForInput };
|
|
25
27
|
};
|
|
26
28
|
|
|
@@ -40,6 +42,15 @@ function clientOptions(options: HonoJsxOptions) {
|
|
|
40
42
|
export function voidHonoJsx(options: HonoJsxOptions = {}): Plugin[] {
|
|
41
43
|
const navigationOptions = clientOptions(options);
|
|
42
44
|
const root = process.cwd();
|
|
45
|
+
const fallback = options.navigationFallback;
|
|
46
|
+
let fallbackPath: string | undefined;
|
|
47
|
+
const fallbackDelay = fallback?.delay ?? 150;
|
|
48
|
+
if (fallback !== undefined) {
|
|
49
|
+
if (!fallback || typeof fallback.component !== 'string' || !fallback.component.trim() || !/\.[jt]sx$/.test(fallback.component)) throw new Error('Hono Pages: navigationFallback.component must name a local TSX/JSX file.');
|
|
50
|
+
if (!Number.isSafeInteger(fallbackDelay) || fallbackDelay < 0 || fallbackDelay > 2147483647) throw new Error('Hono Pages: navigationFallback.delay must be an integer from 0 to 2147483647 milliseconds.');
|
|
51
|
+
fallbackPath = normalizePath(realpathSync(resolve(root, fallback.component)));
|
|
52
|
+
if (!statSync(fallbackPath).isFile()) throw new Error('Hono Pages: navigationFallback.component must be a file.');
|
|
53
|
+
}
|
|
43
54
|
const pagesDir = resolvePagesDir(root);
|
|
44
55
|
const staticData = resolveStaticPageDataBuildOptions(root);
|
|
45
56
|
let scan: PageScanResult | undefined;
|
|
@@ -171,8 +182,9 @@ export async function renderPage(pageObj, assetTags) {
|
|
|
171
182
|
}
|
|
172
183
|
return `
|
|
173
184
|
import { startHonoPages } from ${JSON.stringify(clientRuntimePath)};
|
|
185
|
+
${fallbackPath ? `import __HonoNavigationFallback from ${JSON.stringify(fallbackPath)};` : ''}
|
|
174
186
|
${manifest}
|
|
175
|
-
await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} },
|
|
187
|
+
await startHonoPages({ components, layoutTree, routeMeta, matchRoute, staticPageData: ${JSON.stringify(staticData.enabled)}, staticPageDataFastPath: ${JSON.stringify(staticData.fastPath)} }, { ...${JSON.stringify(navigationOptions)}${fallbackPath ? `, navigationFallback: { component: __HonoNavigationFallback, delay: ${fallbackDelay} }` : ''} });
|
|
176
188
|
`;
|
|
177
189
|
},
|
|
178
190
|
}];
|
package/src/runtime/client.tsx
CHANGED
|
@@ -3,11 +3,12 @@ import { jsx } from 'hono/jsx/dom/jsx-runtime';
|
|
|
3
3
|
import { useLayoutEffect, useState } from 'hono/jsx';
|
|
4
4
|
import { idleNavigationState, type NavigationState, type VoidRouterConfig } from 'void/pages-client';
|
|
5
5
|
import { PageContext, RouterContext, NavigationContext, setActionRouter } from './pages.tsx';
|
|
6
|
+
import { NavigationFallback, type NavigationFallbackOptions } from './navigation-fallback.tsx';
|
|
6
7
|
import { createHonoRouter } from './navigation.ts';
|
|
7
8
|
import { createDocumentHead } from './document-head.ts';
|
|
8
9
|
import { createDeferred, resolveDeferred, rejectDeferred, isLoading, bufferInitialDeferred } from './deferred.ts';
|
|
9
10
|
|
|
10
|
-
type NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'
|
|
11
|
+
type NavigationOptions = Pick<VoidRouterConfig, 'viewTransitions' | 'prefetchHoverDelay' | 'prefetchDefaultCacheFor'> & { navigationFallback?: NavigationFallbackOptions };
|
|
11
12
|
|
|
12
13
|
type Manifest = Pick<VoidRouterConfig, 'components' | 'layoutTree' | 'routeMeta' | 'matchRoute' | 'staticPageData' | 'staticPageDataFastPath'>;
|
|
13
14
|
|
|
@@ -17,6 +18,7 @@ function pageComponent(component: unknown) {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export async function startHonoPages(manifest: Manifest, options: NavigationOptions) {
|
|
21
|
+
if (options.navigationFallback && typeof options.navigationFallback.component !== 'function') throw new Error('Hono Pages: navigationFallback must default-export a component function.');
|
|
20
22
|
const root = document.getElementById('app');
|
|
21
23
|
if (!root) throw new Error('Hono Pages: app root is missing.');
|
|
22
24
|
type Frame = { page: Awaited<ReturnType<typeof createHonoRouter>>['initialPageData']; sourceProps: Record<string, unknown>; component: unknown; layouts: unknown[]; revision: number; commit: number };
|
|
@@ -113,6 +115,7 @@ export async function startHonoPages(manifest: Manifest, options: NavigationOpti
|
|
|
113
115
|
<ErrorBoundary key={recovery} onError={renderFailed} fallback={<></>}>
|
|
114
116
|
<PageFrame frame={frame} />
|
|
115
117
|
</ErrorBoundary>
|
|
118
|
+
{options.navigationFallback && <NavigationFallback state={pendingNavigation} options={options.navigationFallback} />}
|
|
116
119
|
</NavigationContext.Provider>
|
|
117
120
|
</RouterContext.Provider>;
|
|
118
121
|
}
|
package/src/runtime/deferred.ts
CHANGED
|
@@ -1,13 +1,49 @@
|
|
|
1
1
|
import type { DeferredState } from 'void';
|
|
2
2
|
|
|
3
|
+
/** Null from an upstream completed prefetch remains null, not a repaired error. */
|
|
4
|
+
export type DeferredResult<T> = { value: T | null; error: null } | { value: null; error: Error };
|
|
5
|
+
type Resource = {
|
|
6
|
+
result?: DeferredResult<unknown>;
|
|
7
|
+
promise?: Promise<DeferredResult<unknown>>;
|
|
8
|
+
serverPromise?: Promise<DeferredResult<unknown>>;
|
|
9
|
+
resolve?: (result: DeferredResult<unknown>) => void;
|
|
10
|
+
};
|
|
11
|
+
const resources = new WeakMap<object, Resource>();
|
|
12
|
+
function resourceFor(ref: unknown): Resource {
|
|
13
|
+
if (typeof ref !== 'object' || ref === null) throw new Error('Hono Pages: deferredResult requires a Deferred state.');
|
|
14
|
+
let resource = resources.get(ref);
|
|
15
|
+
if (!resource) resources.set(ref, resource = {});
|
|
16
|
+
return resource;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** A stable, render-only Promise; Void still owns all execution and delivery. */
|
|
20
|
+
export function deferredResult<T>(state: DeferredState<T>): Promise<DeferredResult<T>> {
|
|
21
|
+
const resource = resourceFor(state);
|
|
22
|
+
// SSR emits only the initial Suspense fallback. Do not subscribe a Hono SSR
|
|
23
|
+
// HTML callback to client-owned completion or wait for it on the server.
|
|
24
|
+
if (typeof window === 'undefined') return (resource.serverPromise ??= new Promise(() => {})) as Promise<DeferredResult<T>>;
|
|
25
|
+
if (!state.loading && !resource.result) resource.result = state.error ? { value: null, error: state.error } : { value: state.value, error: null };
|
|
26
|
+
resource.promise ??= resource.result ? Promise.resolve(resource.result) : new Promise(resolve => { resource.resolve = resolve; });
|
|
27
|
+
return resource.promise as Promise<DeferredResult<T>>;
|
|
28
|
+
}
|
|
29
|
+
function complete(ref: unknown, next: DeferredState<unknown>) {
|
|
30
|
+
const resource = resourceFor(ref);
|
|
31
|
+
resource.result ??= next.error ? { value: null, error: next.error } : { value: next.value, error: null };
|
|
32
|
+
resource.resolve?.(resource.result);
|
|
33
|
+
resource.resolve = undefined;
|
|
34
|
+
// Void replaces its state object on completion. Both objects refer to the
|
|
35
|
+
// same lazy Promise, including completion before component import/use().
|
|
36
|
+
resources.set(next, resource);
|
|
37
|
+
return next;
|
|
38
|
+
}
|
|
3
39
|
export function createDeferred(): DeferredState<never> {
|
|
4
40
|
return { loading: true, value: null, error: null };
|
|
5
41
|
}
|
|
6
|
-
export function resolveDeferred(
|
|
7
|
-
return { loading: false, value, error: null };
|
|
42
|
+
export function resolveDeferred(ref: unknown, value: unknown): DeferredState<unknown> {
|
|
43
|
+
return complete(ref, { loading: false, value, error: null });
|
|
8
44
|
}
|
|
9
|
-
export function rejectDeferred(
|
|
10
|
-
return { loading: false, value: null, error: new Error(message) }
|
|
45
|
+
export function rejectDeferred(ref: unknown, message: string): DeferredState<never> {
|
|
46
|
+
return complete(ref, { loading: false, value: null, error: new Error(message) }) as DeferredState<never>;
|
|
11
47
|
}
|
|
12
48
|
export function isLoading(ref: unknown): boolean {
|
|
13
49
|
return typeof ref === 'object' && ref !== null && 'loading' in ref && ref.loading === true;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect, useState, type FC } from 'hono/jsx';
|
|
2
|
+
import { ErrorBoundary } from 'hono/jsx/dom';
|
|
3
|
+
import { jsx } from 'hono/jsx/dom/jsx-runtime';
|
|
4
|
+
import type { NavigationState } from 'void/pages-client';
|
|
5
|
+
import type { NavigationFallbackProps } from './pages.tsx';
|
|
6
|
+
|
|
7
|
+
export type NavigationFallbackOptions = { component: FC<NavigationFallbackProps>; delay: number };
|
|
8
|
+
|
|
9
|
+
/** Presentation only: it neither replaces the page nor acknowledges its commit. */
|
|
10
|
+
export function NavigationFallback({ state, options }: { state: NavigationState; options: NavigationFallbackOptions }) {
|
|
11
|
+
const [visibleFor, setVisibleFor] = useState<NavigationState | null>(null);
|
|
12
|
+
const [failedFor, setFailedFor] = useState<NavigationState | null>(null);
|
|
13
|
+
const loading = state.state === 'loading' && state.method === 'GET';
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
setVisibleFor(null);
|
|
16
|
+
if (!loading) return;
|
|
17
|
+
const timer = setTimeout(() => setVisibleFor(state), options.delay);
|
|
18
|
+
return () => clearTimeout(timer);
|
|
19
|
+
}, [state]);
|
|
20
|
+
// Identity hides the old fallback immediately, before effect cleanup, on every
|
|
21
|
+
// new navigation/idle state. A queued old timer cannot affect another visit.
|
|
22
|
+
if (!loading || visibleFor !== state || failedFor === state) return null;
|
|
23
|
+
return <ErrorBoundary fallback={<></>} onError={error => queueMicrotask(() => {
|
|
24
|
+
// Hono retries a failed child on parent updates. Remove this presentation
|
|
25
|
+
// subtree before reporting the error; a later navigation may try again.
|
|
26
|
+
setFailedFor(state);
|
|
27
|
+
window.dispatchEvent(new CustomEvent('hono-pages:navigation-error', { detail: error }));
|
|
28
|
+
})}>
|
|
29
|
+
<div data-hono-navigation-fallback role="status" aria-live="polite">{jsx(options.component, { navigation: state })}</div>
|
|
30
|
+
</ErrorBoundary>;
|
|
31
|
+
}
|
package/src/runtime/pages.tsx
CHANGED
|
@@ -3,6 +3,8 @@ import { createActionClient, mergeDataIntoHref, type NavigationState, type Navig
|
|
|
3
3
|
import type { CacheForInput } from 'void/pages-prefetch';
|
|
4
4
|
import type { PageObject } from 'void/pages-protocol';
|
|
5
5
|
export type { DeferredState as Deferred } from 'void';
|
|
6
|
+
export { deferredResult, type DeferredResult } from './deferred.ts';
|
|
7
|
+
export type NavigationFallbackProps = { navigation: NavigationState };
|
|
6
8
|
|
|
7
9
|
const actionClient = createActionClient();
|
|
8
10
|
export const action = actionClient.action;
|