@pracht/core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/index.d.mts +11 -2
- package/dist/index.mjs +56 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,6 +16,10 @@ npm install @pracht/core preact preact-render-to-string
|
|
|
16
16
|
- `route()` — declare a route with path, component, loader, and rendering mode
|
|
17
17
|
- `group()` — group routes under a shared shell or middleware
|
|
18
18
|
|
|
19
|
+
Route modules may export the page as a function default export or as a named
|
|
20
|
+
`Component` export. Named exports such as `loader`, `head`, `ErrorBoundary`, and
|
|
21
|
+
`getStaticPaths` keep their special route-module behavior.
|
|
22
|
+
|
|
19
23
|
### Server
|
|
20
24
|
|
|
21
25
|
- `handlePrachtRequest()` — server renderer that produces full HTML with hydration markers
|
package/dist/index.d.mts
CHANGED
|
@@ -169,7 +169,8 @@ type LoaderFn<TContext = any, TData = unknown> = (args: LoaderArgs<TContext>) =>
|
|
|
169
169
|
interface RouteModule<TContext = any, TLoader extends LoaderLike = undefined> {
|
|
170
170
|
loader?: LoaderFn<TContext>;
|
|
171
171
|
head?: (args: HeadArgs<TLoader, TContext>) => MaybePromise<HeadMetadata>;
|
|
172
|
-
Component
|
|
172
|
+
Component?: FunctionComponent<RouteComponentProps<TLoader>>;
|
|
173
|
+
default?: FunctionComponent<RouteComponentProps<TLoader>>;
|
|
173
174
|
ErrorBoundary?: FunctionComponent<ErrorBoundaryProps>;
|
|
174
175
|
getStaticPaths?: () => MaybePromise<RouteParams[]>;
|
|
175
176
|
}
|
|
@@ -234,6 +235,14 @@ declare function forwardRef<P = {}>(fn: ((props: P, ref: any) => any) & {
|
|
|
234
235
|
ref?: any;
|
|
235
236
|
}>;
|
|
236
237
|
//#endregion
|
|
238
|
+
//#region src/hydration.d.ts
|
|
239
|
+
/**
|
|
240
|
+
* Returns `true` once the initial hydration (including all Suspense
|
|
241
|
+
* boundaries) has fully resolved. During SSR and hydration this returns
|
|
242
|
+
* `false`.
|
|
243
|
+
*/
|
|
244
|
+
declare function useIsHydrated(): boolean;
|
|
245
|
+
//#endregion
|
|
237
246
|
//#region src/runtime.d.ts
|
|
238
247
|
type PrachtRuntimeDiagnosticPhase = "match" | "middleware" | "loader" | "action" | "render" | "api";
|
|
239
248
|
interface PrachtRuntimeDiagnostics {
|
|
@@ -384,4 +393,4 @@ interface InitClientRouterOptions {
|
|
|
384
393
|
}
|
|
385
394
|
declare function initClientRouter(options: InitClientRouterOptions): Promise<void>;
|
|
386
395
|
//#endregion
|
|
387
|
-
export { type ApiConfig, type ApiRouteHandler, type ApiRouteMatch, type ApiRouteModule, type BaseRouteArgs, type DataModule, type ErrorBoundaryProps, Form, type FormProps, type GroupDefinition, type GroupMeta, type HandlePrachtRequestOptions, type HeadArgs, type HeadMetadata, type HttpMethod, type ISGManifestEntry, type InitClientRouterOptions, type LoaderArgs, type LoaderData, type LoaderFn, type Location, type MiddlewareArgs, type MiddlewareFn, type MiddlewareModule, type MiddlewareResult, type ModuleImporter, type ModuleRef, type ModuleRegistry, type NavigateFn, type PrachtApp, type PrachtAppConfig, PrachtHttpError, type PrachtHydrationState, type PrachtRuntimeDiagnosticPhase, type PrachtRuntimeDiagnostics, PrachtRuntimeProvider, type PrefetchStrategy, type PrerenderAppOptions, type PrerenderAppResult, type PrerenderResult, type Register, type RenderMode, type ResolvedApiRoute, type ResolvedPrachtApp, type ResolvedRoute, type RouteComponentProps, type RouteConfig, type RouteDefinition, type RouteMatch, type RouteMeta, type RouteModule, type RouteParams, type RouteRevalidate, type RouteStateResult, type RouteTreeNode, type SerializedRouteError, type ShellModule, type ShellProps, type StartAppOptions, Suspense, type TimeRevalidatePolicy, applyDefaultSecurityHeaders, buildPathFromSegments, defineApp, forwardRef, group, handlePrachtRequest, initClientRouter, lazy, matchApiRoute, matchAppRoute, prerenderApp, readHydrationState, resolveApiRoutes, resolveApp, route, startApp, timeRevalidate, useLocation, useNavigate, useParams, useRevalidate, useRevalidateRoute, useRouteData };
|
|
396
|
+
export { type ApiConfig, type ApiRouteHandler, type ApiRouteMatch, type ApiRouteModule, type BaseRouteArgs, type DataModule, type ErrorBoundaryProps, Form, type FormProps, type GroupDefinition, type GroupMeta, type HandlePrachtRequestOptions, type HeadArgs, type HeadMetadata, type HttpMethod, type ISGManifestEntry, type InitClientRouterOptions, type LoaderArgs, type LoaderData, type LoaderFn, type Location, type MiddlewareArgs, type MiddlewareFn, type MiddlewareModule, type MiddlewareResult, type ModuleImporter, type ModuleRef, type ModuleRegistry, type NavigateFn, type PrachtApp, type PrachtAppConfig, PrachtHttpError, type PrachtHydrationState, type PrachtRuntimeDiagnosticPhase, type PrachtRuntimeDiagnostics, PrachtRuntimeProvider, type PrefetchStrategy, type PrerenderAppOptions, type PrerenderAppResult, type PrerenderResult, type Register, type RenderMode, type ResolvedApiRoute, type ResolvedPrachtApp, type ResolvedRoute, type RouteComponentProps, type RouteConfig, type RouteDefinition, type RouteMatch, type RouteMeta, type RouteModule, type RouteParams, type RouteRevalidate, type RouteStateResult, type RouteTreeNode, type SerializedRouteError, type ShellModule, type ShellProps, type StartAppOptions, Suspense, type TimeRevalidatePolicy, applyDefaultSecurityHeaders, buildPathFromSegments, defineApp, forwardRef, group, handlePrachtRequest, initClientRouter, lazy, matchApiRoute, matchAppRoute, prerenderApp, readHydrationState, resolveApiRoutes, resolveApp, route, startApp, timeRevalidate, useIsHydrated, useLocation, useNavigate, useParams, useRevalidate, useRevalidateRoute, useRouteData };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as matchApiRoute, c as resolveApp, i as group, l as route, n as buildPathFromSegments, o as matchAppRoute, r as defineApp, s as resolveApiRoutes, u as timeRevalidate } from "./app-Cep0el7c.mjs";
|
|
2
2
|
import { createContext, h, hydrate, options, render } from "preact";
|
|
3
|
-
import { Suspense, lazy } from "preact-suspense";
|
|
4
3
|
import { useContext, useEffect, useMemo, useState } from "preact/hooks";
|
|
4
|
+
import { Suspense, lazy } from "preact-suspense";
|
|
5
5
|
//#region src/forwardRef.ts
|
|
6
6
|
let oldDiffHook = options.__b;
|
|
7
7
|
options.__b = (vnode) => {
|
|
@@ -27,6 +27,51 @@ function forwardRef(fn) {
|
|
|
27
27
|
return Forwarded;
|
|
28
28
|
}
|
|
29
29
|
//#endregion
|
|
30
|
+
//#region src/hydration.ts
|
|
31
|
+
let _hydrating = false;
|
|
32
|
+
let _suspensionCount = 0;
|
|
33
|
+
let _hydrated = false;
|
|
34
|
+
const oldCatchError = options.__e;
|
|
35
|
+
options.__e = (err, newVNode, oldVNode, errorInfo) => {
|
|
36
|
+
if (_hydrating && !_hydrated && err && err.then) {
|
|
37
|
+
_suspensionCount++;
|
|
38
|
+
let settled = false;
|
|
39
|
+
const onSettled = () => {
|
|
40
|
+
if (settled) return;
|
|
41
|
+
settled = true;
|
|
42
|
+
_suspensionCount--;
|
|
43
|
+
};
|
|
44
|
+
err.then(onSettled, onSettled);
|
|
45
|
+
}
|
|
46
|
+
if (oldCatchError) oldCatchError(err, newVNode, oldVNode, errorInfo);
|
|
47
|
+
};
|
|
48
|
+
const oldDiffed = options.diffed;
|
|
49
|
+
options.diffed = (vnode) => {
|
|
50
|
+
if (_hydrating && !_hydrated && _suspensionCount <= 0) {
|
|
51
|
+
_hydrated = true;
|
|
52
|
+
_hydrating = false;
|
|
53
|
+
}
|
|
54
|
+
if (oldDiffed) oldDiffed(vnode);
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Mark the start of a hydration pass. Call this right before `hydrate()`.
|
|
58
|
+
*/
|
|
59
|
+
function markHydrating() {
|
|
60
|
+
if (!_hydrated) _hydrating = true;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Returns `true` once the initial hydration (including all Suspense
|
|
64
|
+
* boundaries) has fully resolved. During SSR and hydration this returns
|
|
65
|
+
* `false`.
|
|
66
|
+
*/
|
|
67
|
+
function useIsHydrated() {
|
|
68
|
+
const [hydrated, setHydrated] = useState(_hydrated);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
setHydrated(true);
|
|
71
|
+
}, []);
|
|
72
|
+
return hydrated;
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
30
75
|
//#region src/runtime.ts
|
|
31
76
|
const SAFE_METHODS = new Set(["GET", "HEAD"]);
|
|
32
77
|
const HYDRATION_STATE_ELEMENT_ID = "pracht-state";
|
|
@@ -305,9 +350,10 @@ async function handlePrachtRequest(options) {
|
|
|
305
350
|
modulePreloadUrls
|
|
306
351
|
}));
|
|
307
352
|
}
|
|
308
|
-
|
|
353
|
+
const DefaultComponent = typeof routeModule.default === "function" ? routeModule.default : void 0;
|
|
354
|
+
const Component = routeModule.Component ?? DefaultComponent;
|
|
355
|
+
if (!Component) throw new Error("Route has no Component or default export");
|
|
309
356
|
const { renderToStringAsync } = await import("preact-render-to-string");
|
|
310
|
-
const Component = routeModule.Component;
|
|
311
357
|
const Shell = shellModule?.Shell;
|
|
312
358
|
const componentProps = {
|
|
313
359
|
data,
|
|
@@ -868,7 +914,8 @@ async function initClientRouter(options) {
|
|
|
868
914
|
let Shell = null;
|
|
869
915
|
const resolvedShell = await (shellModPromise ?? startShellImport(match));
|
|
870
916
|
if (resolvedShell) Shell = resolvedShell.Shell;
|
|
871
|
-
const
|
|
917
|
+
const DefaultComponent = typeof routeMod.default === "function" ? routeMod.default : void 0;
|
|
918
|
+
const Component = state.error ? routeMod.ErrorBoundary : routeMod.Component ?? DefaultComponent;
|
|
872
919
|
if (!Component) return null;
|
|
873
920
|
const props = state.error ? { error: deserializeRouteError(state.error) } : {
|
|
874
921
|
data: state.data,
|
|
@@ -980,7 +1027,10 @@ async function initClientRouter(options) {
|
|
|
980
1027
|
}
|
|
981
1028
|
const tree = await buildRouteTree(initialMatch, state, void 0, initialShellPromise);
|
|
982
1029
|
if (tree) if (initialMatch.route.render === "spa") render(tree, root);
|
|
983
|
-
else
|
|
1030
|
+
else {
|
|
1031
|
+
markHydrating();
|
|
1032
|
+
hydrate(tree, root);
|
|
1033
|
+
}
|
|
984
1034
|
}
|
|
985
1035
|
document.addEventListener("click", (e) => {
|
|
986
1036
|
const anchor = e.target.closest?.("a");
|
|
@@ -1080,4 +1130,4 @@ var PrachtHttpError = class extends Error {
|
|
|
1080
1130
|
}
|
|
1081
1131
|
};
|
|
1082
1132
|
//#endregion
|
|
1083
|
-
export { Form, PrachtHttpError, PrachtRuntimeProvider, Suspense, applyDefaultSecurityHeaders, buildPathFromSegments, defineApp, forwardRef, group, handlePrachtRequest, initClientRouter, lazy, matchApiRoute, matchAppRoute, prerenderApp, readHydrationState, resolveApiRoutes, resolveApp, route, startApp, timeRevalidate, useLocation, useNavigate, useParams, useRevalidate, useRevalidateRoute, useRouteData };
|
|
1133
|
+
export { Form, PrachtHttpError, PrachtRuntimeProvider, Suspense, applyDefaultSecurityHeaders, buildPathFromSegments, defineApp, forwardRef, group, handlePrachtRequest, initClientRouter, lazy, matchApiRoute, matchAppRoute, prerenderApp, readHydrationState, resolveApiRoutes, resolveApp, route, startApp, timeRevalidate, useIsHydrated, useLocation, useNavigate, useParams, useRevalidate, useRevalidateRoute, useRouteData };
|