@octanejs/tanstack-start 0.2.4 → 0.2.6
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/package.json +6 -6
- package/src/GenericHydrate.tsrx +48 -39
- package/src/Hydrate.tsrx +11 -15
- package/src/hydration/never.tsrx +18 -11
- package/src/hydration/visible.tsrx +11 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@octanejs/tanstack-start",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "TanStack Start for Octane, including file-route generation, server functions, SSR streaming, hydration, and Vite or Rsbuild integration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -117,8 +117,8 @@
|
|
|
117
117
|
"@babel/core": "7.29.7",
|
|
118
118
|
"@babel/template": "^7.27.2",
|
|
119
119
|
"@babel/types": "^7.28.5",
|
|
120
|
-
"@octanejs/rspack-plugin": "0.2.
|
|
121
|
-
"@octanejs/tanstack-router": "0.2.
|
|
120
|
+
"@octanejs/rspack-plugin": "0.2.2",
|
|
121
|
+
"@octanejs/tanstack-router": "0.2.6",
|
|
122
122
|
"@tanstack/router-core": "1.171.34",
|
|
123
123
|
"@tanstack/router-utils": "1.162.2",
|
|
124
124
|
"@tanstack/start-client-core": "1.170.34",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"magic-string": "^0.30.21",
|
|
132
132
|
"pathe": "^2.0.3",
|
|
133
133
|
"picomatch": "^4.0.3",
|
|
134
|
-
"prettier": "^3.9.
|
|
134
|
+
"prettier": "^3.9.9",
|
|
135
135
|
"seroval": "^1.5.4",
|
|
136
136
|
"source-map": "^0.7.6",
|
|
137
137
|
"srvx": "^0.11.9",
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
},
|
|
145
145
|
"peerDependencies": {
|
|
146
146
|
"@rsbuild/core": "^2.0.0",
|
|
147
|
-
"octane": "^0.
|
|
147
|
+
"octane": "^0.12.0",
|
|
148
148
|
"vite": ">=7.0.0"
|
|
149
149
|
},
|
|
150
150
|
"peerDependenciesMeta": {
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
"devDependencies": {
|
|
159
159
|
"@rsbuild/core": "^2.1.6",
|
|
160
160
|
"@types/node": "^24.13.3",
|
|
161
|
-
"octane": "0.
|
|
161
|
+
"octane": "0.12.0",
|
|
162
162
|
"vite": "^8.1.5",
|
|
163
163
|
"vitest": "^4.1.10"
|
|
164
164
|
},
|
package/src/GenericHydrate.tsrx
CHANGED
|
@@ -88,9 +88,8 @@ function useHydrationGate(props: InternalHydrateProps) {
|
|
|
88
88
|
const isDynamicHydrate = typeof when === 'function';
|
|
89
89
|
const dynamicHydrateStrategyRef = useRef<HydrationStrategy | undefined>(undefined);
|
|
90
90
|
if (isDynamicHydrate) {
|
|
91
|
-
dynamicHydrateStrategyRef.current ??=
|
|
92
|
-
? dynamicHydrateStrategy
|
|
93
|
-
: when();
|
|
91
|
+
dynamicHydrateStrategyRef.current ??=
|
|
92
|
+
(isServer ?? typeof window === 'undefined') ? dynamicHydrateStrategy : when();
|
|
94
93
|
}
|
|
95
94
|
const hydrateStrategy = isDynamicHydrate ? dynamicHydrateStrategyRef.current! : when;
|
|
96
95
|
const markerHydrateType: HydrationWhen = isDynamicHydrate ? dynamicType : hydrateStrategy._t!;
|
|
@@ -118,29 +117,34 @@ function useHydrationGate(props: InternalHydrateProps) {
|
|
|
118
117
|
shouldDeferInitialHydrationRef.current ??= !hydrated && shouldDeferHydration(hydrateStrategy);
|
|
119
118
|
|
|
120
119
|
if (!gateRef.current) {
|
|
121
|
-
gateRef.current =
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
gateRef.current =
|
|
121
|
+
(isServer ?? typeof window === 'undefined')
|
|
122
|
+
? createResolvedGate(id, hydrateStrategy._t!)
|
|
123
|
+
: getOrCreateGate(id, hydrateStrategy._t!);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
gateRef.current.when = hydrateStrategy._t!;
|
|
127
127
|
|
|
128
128
|
if (
|
|
129
|
-
!(isServer ?? typeof window === 'undefined') &&
|
|
130
|
-
|
|
129
|
+
!(isServer ?? typeof window === 'undefined') &&
|
|
130
|
+
hydrateStrategy._t !== 'never' &&
|
|
131
|
+
(!shouldDeferInitialHydrationRef.current || !shouldDeferHydration(hydrateStrategy))
|
|
131
132
|
) {
|
|
132
133
|
gateRef.current.resolve();
|
|
133
134
|
}
|
|
134
135
|
|
|
135
|
-
const markerRef = useCallback(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (
|
|
139
|
-
|
|
136
|
+
const markerRef = useCallback(
|
|
137
|
+
(element: HTMLDivElement | null) => {
|
|
138
|
+
markerElementRef.current = element;
|
|
139
|
+
if (element) {
|
|
140
|
+
if (hydrateStrategy._t === 'never' && !shouldPreserveServerHTMLRef.current) {
|
|
141
|
+
element.replaceChildren();
|
|
142
|
+
}
|
|
143
|
+
saveFallbackHtml(id, element);
|
|
140
144
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
145
|
+
},
|
|
146
|
+
[hydrateStrategy._t, id],
|
|
147
|
+
);
|
|
144
148
|
|
|
145
149
|
useEffect(() => {
|
|
146
150
|
const gate = gateRef.current!;
|
|
@@ -178,18 +182,21 @@ function useHydrationGate(props: InternalHydrateProps) {
|
|
|
178
182
|
const prefetchInput = latestRef.current.prefetch;
|
|
179
183
|
|
|
180
184
|
if (typeof prefetchInput === 'function') {
|
|
181
|
-
const promise = Promise.resolve()
|
|
182
|
-
() =>
|
|
183
|
-
|
|
184
|
-
signal: controller.abortController.signal,
|
|
185
|
-
preload,
|
|
186
|
-
waitFor: (strategy) => waitForHydrationPrefetchStrategy(strategy, {
|
|
185
|
+
const promise = Promise.resolve()
|
|
186
|
+
.then(() =>
|
|
187
|
+
prefetchInput({
|
|
187
188
|
element: markerElementRef.current,
|
|
188
189
|
signal: controller.abortController.signal,
|
|
189
|
-
|
|
190
|
+
preload,
|
|
191
|
+
waitFor: (strategy) =>
|
|
192
|
+
waitForHydrationPrefetchStrategy(strategy, {
|
|
193
|
+
element: markerElementRef.current,
|
|
194
|
+
signal: controller.abortController.signal,
|
|
195
|
+
onHydrate,
|
|
196
|
+
}),
|
|
190
197
|
}),
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
)
|
|
199
|
+
.then(() => undefined);
|
|
193
200
|
|
|
194
201
|
controller.promise = promise;
|
|
195
202
|
promise.catch((error) => {
|
|
@@ -265,11 +272,14 @@ function useHydrationGate(props: InternalHydrateProps) {
|
|
|
265
272
|
if (controller.hydrationResolvePending) return;
|
|
266
273
|
controller.hydrationResolvePending = true;
|
|
267
274
|
|
|
268
|
-
controller.promise.then(
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
275
|
+
controller.promise.then(
|
|
276
|
+
() => resolveGate(),
|
|
277
|
+
(error) => {
|
|
278
|
+
if (!controller.abortController.signal.aborted) {
|
|
279
|
+
setPrefetchError(error);
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
);
|
|
273
283
|
};
|
|
274
284
|
|
|
275
285
|
gate.resolve = requestHydration;
|
|
@@ -354,14 +364,13 @@ export function GenericHydrate(props: HydrateProps) @{
|
|
|
354
364
|
let fallback: OctaneNode;
|
|
355
365
|
if (shouldPreserveServerHTML) {
|
|
356
366
|
const html = getFallbackHtml(gate.id);
|
|
357
|
-
fallback = html
|
|
358
|
-
|
|
359
|
-
|
|
367
|
+
fallback = html ? (
|
|
368
|
+
<div style={{ display: 'contents' }} dangerouslySetInnerHTML={{ __html: html }} />
|
|
369
|
+
) : null;
|
|
360
370
|
} else {
|
|
361
371
|
fallback = props.fallback ?? null;
|
|
362
372
|
}
|
|
363
|
-
const markerAttributes =
|
|
364
|
-
markerHydrateType === dynamicType ? undefined : hydrateStrategy._a?.();
|
|
373
|
+
const markerAttributes = markerHydrateType === dynamicType ? undefined : hydrateStrategy._a?.();
|
|
365
374
|
|
|
366
375
|
const hydrateType = hydrateStrategy._t!;
|
|
367
376
|
const preserveNever = hydrateType === 'never' && !shouldPreserveServerHTML;
|
|
@@ -375,9 +384,7 @@ export function GenericHydrate(props: HydrateProps) @{
|
|
|
375
384
|
}}
|
|
376
385
|
>
|
|
377
386
|
@if (preserveNever) {
|
|
378
|
-
<>
|
|
379
|
-
{props.fallback ?? null}
|
|
380
|
-
</>
|
|
387
|
+
<>{props.fallback ?? null}</>
|
|
381
388
|
} @else {
|
|
382
389
|
<Suspense fallback={fallback}>
|
|
383
390
|
<HydrationGate gate={gate as Gate}>
|
|
@@ -388,7 +395,9 @@ export function GenericHydrate(props: HydrateProps) @{
|
|
|
388
395
|
markerElementRef.current?.removeAttribute(hydrateWhenAttribute);
|
|
389
396
|
hydrateStrategy._o?.(id);
|
|
390
397
|
}}
|
|
391
|
-
>
|
|
398
|
+
>
|
|
399
|
+
{props.children}
|
|
400
|
+
</HydratedBoundary>
|
|
392
401
|
</HydrationGate>
|
|
393
402
|
</Suspense>
|
|
394
403
|
}
|
package/src/Hydrate.tsrx
CHANGED
|
@@ -30,16 +30,14 @@ import type {
|
|
|
30
30
|
export type OctaneHydrationStrategy<
|
|
31
31
|
TWhen extends HydrationWhen = HydrationWhen,
|
|
32
32
|
TCanPrefetch extends boolean = boolean,
|
|
33
|
-
> =
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
33
|
+
> = CoreHydrationStrategy<TWhen, TCanPrefetch> & {
|
|
34
|
+
_h: (props: HydrateProps) => OctaneNode;
|
|
35
|
+
};
|
|
37
36
|
|
|
38
37
|
export type HydrationStrategy<
|
|
39
38
|
TWhen extends HydrationWhen = HydrationWhen,
|
|
40
39
|
TCanPrefetch extends boolean = boolean,
|
|
41
|
-
> =
|
|
42
|
-
OctaneHydrationStrategy<TWhen, TCanPrefetch>;
|
|
40
|
+
> = OctaneHydrationStrategy<TWhen, TCanPrefetch>;
|
|
43
41
|
|
|
44
42
|
export type HydrateWhen = OctaneHydrationStrategy | (() => OctaneHydrationStrategy);
|
|
45
43
|
|
|
@@ -63,16 +61,14 @@ export type HydrateOptions =
|
|
|
63
61
|
split?: boolean;
|
|
64
62
|
});
|
|
65
63
|
|
|
66
|
-
export type HydrateProps =
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
64
|
+
export type HydrateProps = HydrateOptions & {
|
|
65
|
+
children: OctaneNode;
|
|
66
|
+
};
|
|
70
67
|
|
|
71
|
-
export type InternalHydrateProps =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
68
|
+
export type InternalHydrateProps = HydrateProps & {
|
|
69
|
+
h?: string;
|
|
70
|
+
p?: () => Promise<void>;
|
|
71
|
+
};
|
|
76
72
|
|
|
77
73
|
const dynamicType = 'dynamic';
|
|
78
74
|
|
package/src/hydration/never.tsrx
CHANGED
|
@@ -38,14 +38,17 @@ export function NeverHydrate(props: HydrateProps) @{
|
|
|
38
38
|
const id = internalProps.h ? `${internalProps.h}${octaneId}` : octaneId;
|
|
39
39
|
const shouldPreserveServerHTMLRef = useRef<boolean | undefined>(undefined);
|
|
40
40
|
shouldPreserveServerHTMLRef.current ??= (isServer ?? typeof window === 'undefined') || !hydrated;
|
|
41
|
-
const markerRef = useCallback(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
const markerRef = useCallback(
|
|
42
|
+
(element: HTMLDivElement | null) => {
|
|
43
|
+
if (!element) return;
|
|
44
|
+
if (!shouldPreserveServerHTMLRef.current) {
|
|
45
|
+
element.replaceChildren();
|
|
46
|
+
} else {
|
|
47
|
+
saveFallbackHtml(id, element);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
[id],
|
|
51
|
+
);
|
|
49
52
|
const savedHtml = getFallbackHtml(id);
|
|
50
53
|
|
|
51
54
|
<div
|
|
@@ -56,9 +59,13 @@ export function NeverHydrate(props: HydrateProps) @{
|
|
|
56
59
|
}}
|
|
57
60
|
>
|
|
58
61
|
<Suspense
|
|
59
|
-
fallback={
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
fallback={
|
|
63
|
+
savedHtml ? (
|
|
64
|
+
<div style={{ display: 'contents' }} dangerouslySetInnerHTML={{ __html: savedHtml }} />
|
|
65
|
+
) : (
|
|
66
|
+
(props.fallback ?? null)
|
|
67
|
+
)
|
|
68
|
+
}
|
|
62
69
|
>
|
|
63
70
|
<NeverGate>{props.children}</NeverGate>
|
|
64
71
|
</Suspense>
|
|
@@ -89,7 +89,9 @@ export function VisibleHydrate(props: HydrateProps) @{
|
|
|
89
89
|
|
|
90
90
|
<div ref={markerRef}>
|
|
91
91
|
<Suspense fallback={props.fallback}>
|
|
92
|
-
<HydrationBoundary g={gate} o={props.onHydrated}>
|
|
92
|
+
<HydrationBoundary g={gate} o={props.onHydrated}>
|
|
93
|
+
{props.children}
|
|
94
|
+
</HydrationBoundary>
|
|
93
95
|
</Suspense>
|
|
94
96
|
</div>
|
|
95
97
|
}
|
|
@@ -110,11 +112,14 @@ export function visible(
|
|
|
110
112
|
return;
|
|
111
113
|
}
|
|
112
114
|
|
|
113
|
-
const observer = new IntersectionObserver(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
const observer = new IntersectionObserver(
|
|
116
|
+
(entries) => {
|
|
117
|
+
if (!entries[0]!.isIntersecting) return;
|
|
118
|
+
observer.disconnect();
|
|
119
|
+
callback();
|
|
120
|
+
},
|
|
121
|
+
{ rootMargin, threshold },
|
|
122
|
+
);
|
|
118
123
|
observer.observe(element);
|
|
119
124
|
return () => observer.disconnect();
|
|
120
125
|
},
|