@tanstack/start-client-core 1.169.4 → 1.170.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/dist/esm/client/hydrateStart.d.ts +13 -1
- package/dist/esm/client/hydrateStart.js +20 -1
- package/dist/esm/client/hydrateStart.js.map +1 -1
- package/dist/esm/client/index.js +2 -2
- package/dist/esm/hydration/condition.d.ts +5 -0
- package/dist/esm/hydration/condition.js +16 -0
- package/dist/esm/hydration/condition.js.map +1 -0
- package/dist/esm/hydration/constants.d.ts +3 -0
- package/dist/esm/hydration/constants.js +8 -0
- package/dist/esm/hydration/constants.js.map +1 -0
- package/dist/esm/hydration/idle.d.ts +7 -0
- package/dist/esm/hydration/idle.js +22 -0
- package/dist/esm/hydration/idle.js.map +1 -0
- package/dist/esm/hydration/interaction.d.ts +8 -0
- package/dist/esm/hydration/interaction.js +221 -0
- package/dist/esm/hydration/interaction.js.map +1 -0
- package/dist/esm/hydration/load.d.ts +4 -0
- package/dist/esm/hydration/load.js +16 -0
- package/dist/esm/hydration/load.js.map +1 -0
- package/dist/esm/hydration/media.d.ts +4 -0
- package/dist/esm/hydration/media.js +23 -0
- package/dist/esm/hydration/media.js.map +1 -0
- package/dist/esm/hydration/never.d.ts +4 -0
- package/dist/esm/hydration/never.js +13 -0
- package/dist/esm/hydration/never.js.map +1 -0
- package/dist/esm/hydration/renderer.d.ts +5 -0
- package/dist/esm/hydration/renderer.js +9 -0
- package/dist/esm/hydration/renderer.js.map +1 -0
- package/dist/esm/hydration/runtime.d.ts +23 -0
- package/dist/esm/hydration/runtime.js +129 -0
- package/dist/esm/hydration/runtime.js.map +1 -0
- package/dist/esm/hydration/types.d.ts +38 -0
- package/dist/esm/hydration/visible.d.ts +8 -0
- package/dist/esm/hydration/visible.js +67 -0
- package/dist/esm/hydration/visible.js.map +1 -0
- package/dist/esm/hydration.d.ts +18 -0
- package/dist/esm/hydration.js +16 -0
- package/dist/esm/hydration.js.map +1 -0
- package/package.json +24 -3
- package/src/client/hydrateStart.ts +48 -2
- package/src/hydration/condition.ts +20 -0
- package/src/hydration/constants.ts +4 -0
- package/src/hydration/idle.ts +35 -0
- package/src/hydration/interaction.ts +342 -0
- package/src/hydration/load.ts +16 -0
- package/src/hydration/media.ts +25 -0
- package/src/hydration/never.ts +13 -0
- package/src/hydration/renderer.ts +21 -0
- package/src/hydration/runtime.ts +191 -0
- package/src/hydration/types.ts +90 -0
- package/src/hydration/visible.ts +90 -0
- package/src/hydration.ts +50 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { hydrateIdAttribute, hydrateWhenAttribute } from "./constants.js";
|
|
2
|
+
//#region src/hydration/runtime.ts
|
|
3
|
+
var hydrateIdSelector = `[${hydrateIdAttribute}]`;
|
|
4
|
+
var gateRegistry = /* @__PURE__ */ new Map();
|
|
5
|
+
var resolvedGateIds = /* @__PURE__ */ new Set();
|
|
6
|
+
var fallbackHtmlByGateId = /* @__PURE__ */ new Map();
|
|
7
|
+
function createResolvedGate(id, when) {
|
|
8
|
+
return {
|
|
9
|
+
id,
|
|
10
|
+
when,
|
|
11
|
+
promise: Promise.resolve(),
|
|
12
|
+
resolve: () => {},
|
|
13
|
+
resolved: true,
|
|
14
|
+
consumers: 0,
|
|
15
|
+
resolveListeners: /* @__PURE__ */ new Set()
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function getOrCreateGate(id, when) {
|
|
19
|
+
const existing = gateRegistry.get(id);
|
|
20
|
+
if (existing?.when === when) {
|
|
21
|
+
existing.consumers++;
|
|
22
|
+
return existing;
|
|
23
|
+
}
|
|
24
|
+
let resolvePromise;
|
|
25
|
+
const gate = {
|
|
26
|
+
id,
|
|
27
|
+
promise: new Promise((resolve) => {
|
|
28
|
+
resolvePromise = resolve;
|
|
29
|
+
}),
|
|
30
|
+
resolved: false,
|
|
31
|
+
consumers: 1,
|
|
32
|
+
when,
|
|
33
|
+
resolveListeners: /* @__PURE__ */ new Set(),
|
|
34
|
+
resolve: () => {
|
|
35
|
+
if (gate.resolved) return;
|
|
36
|
+
gate.resolved = true;
|
|
37
|
+
resolvePromise();
|
|
38
|
+
gate.resolveListeners.forEach((listener) => listener());
|
|
39
|
+
gate.resolveListeners.clear();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
gateRegistry.set(id, gate);
|
|
43
|
+
if (when !== "never" && resolvedGateIds.has(id)) {
|
|
44
|
+
resolvedGateIds.delete(id);
|
|
45
|
+
gate.resolve();
|
|
46
|
+
}
|
|
47
|
+
return gate;
|
|
48
|
+
}
|
|
49
|
+
function releaseGate(gate) {
|
|
50
|
+
resolvedGateIds.delete(gate.id);
|
|
51
|
+
gate.consumers--;
|
|
52
|
+
if (gate.consumers > 0) return;
|
|
53
|
+
if (gateRegistry.get(gate.id) === gate) {
|
|
54
|
+
gateRegistry.delete(gate.id);
|
|
55
|
+
fallbackHtmlByGateId.delete(gate.id);
|
|
56
|
+
gate.resolveListeners.clear();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function onGateResolve(gate, listener) {
|
|
60
|
+
if (gate.resolved) {
|
|
61
|
+
listener();
|
|
62
|
+
return () => {};
|
|
63
|
+
}
|
|
64
|
+
gate.resolveListeners.add(listener);
|
|
65
|
+
return () => {
|
|
66
|
+
gate.resolveListeners.delete(listener);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function runHydrationStrategyCleanup(cleanup) {
|
|
70
|
+
if (typeof cleanup === "function") return cleanup;
|
|
71
|
+
}
|
|
72
|
+
function waitForHydrationPrefetchStrategy(strategy, options) {
|
|
73
|
+
if (options.signal.aborted) return Promise.resolve("abort");
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
const state = { disposed: false };
|
|
76
|
+
const cleanupStrategyRef = { current: void 0 };
|
|
77
|
+
let cleanupHydrate = () => {};
|
|
78
|
+
const finish = (reason) => {
|
|
79
|
+
if (state.disposed) return;
|
|
80
|
+
state.disposed = true;
|
|
81
|
+
options.signal.removeEventListener("abort", onAbort);
|
|
82
|
+
cleanupHydrate();
|
|
83
|
+
runHydrationStrategyCleanup(cleanupStrategyRef.current)?.();
|
|
84
|
+
resolve(reason);
|
|
85
|
+
};
|
|
86
|
+
const onAbort = () => finish("abort");
|
|
87
|
+
options.signal.addEventListener("abort", onAbort, { once: true });
|
|
88
|
+
cleanupHydrate = options.onHydrate(() => finish("hydrate"));
|
|
89
|
+
const cleanupStrategy = strategy._s?.({
|
|
90
|
+
element: options.element,
|
|
91
|
+
prefetch: () => finish("prefetch")
|
|
92
|
+
});
|
|
93
|
+
cleanupStrategyRef.current = cleanupStrategy;
|
|
94
|
+
if (state.disposed) runHydrationStrategyCleanup(cleanupStrategy)?.();
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function getMarkerGate(marker) {
|
|
98
|
+
const id = marker.getAttribute(hydrateIdAttribute);
|
|
99
|
+
return id ? gateRegistry.get(id) : void 0;
|
|
100
|
+
}
|
|
101
|
+
function resolveHydrationMarker(marker) {
|
|
102
|
+
const id = marker.getAttribute(hydrateIdAttribute);
|
|
103
|
+
const when = marker.getAttribute(hydrateWhenAttribute);
|
|
104
|
+
if (!id || !when || when === "never") return;
|
|
105
|
+
const gate = gateRegistry.get(id);
|
|
106
|
+
if (gate) {
|
|
107
|
+
if (gate.when !== "never") gate.resolve();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
resolvedGateIds.add(id);
|
|
111
|
+
}
|
|
112
|
+
function clearResolvedGateIdsInMarker(marker) {
|
|
113
|
+
const ownId = marker.getAttribute(hydrateIdAttribute);
|
|
114
|
+
if (ownId) resolvedGateIds.delete(ownId);
|
|
115
|
+
marker.querySelectorAll(hydrateIdSelector).forEach((childMarker) => {
|
|
116
|
+
const childId = childMarker.getAttribute(hydrateIdAttribute);
|
|
117
|
+
if (childId) resolvedGateIds.delete(childId);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function saveFallbackHtml(id, element) {
|
|
121
|
+
if (!fallbackHtmlByGateId.has(id)) fallbackHtmlByGateId.set(id, element.innerHTML);
|
|
122
|
+
}
|
|
123
|
+
function getFallbackHtml(id) {
|
|
124
|
+
return fallbackHtmlByGateId.get(id);
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
127
|
+
export { clearResolvedGateIdsInMarker, createResolvedGate, getFallbackHtml, getMarkerGate, getOrCreateGate, onGateResolve, releaseGate, resolveHydrationMarker, runHydrationStrategyCleanup, saveFallbackHtml, waitForHydrationPrefetchStrategy };
|
|
128
|
+
|
|
129
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","names":[],"sources":["../../../src/hydration/runtime.ts"],"sourcesContent":["import { hydrateIdAttribute, hydrateWhenAttribute } from './constants'\nimport type {\n HydrationPrefetchStrategy,\n HydrationPrefetchWaitReason,\n HydrationRuntimeGate,\n HydrationWhen,\n} from './types'\n\nconst hydrateIdSelector = `[${hydrateIdAttribute}]`\n\nexport type HydrationGateRecord = HydrationRuntimeGate & {\n id: string\n when: HydrationWhen\n promise: Promise<void>\n consumers: number\n resolveListeners: Set<() => void>\n}\n\nconst gateRegistry = /* @__PURE__ */ new Map<string, HydrationGateRecord>()\nconst resolvedGateIds = /* @__PURE__ */ new Set<string>()\nconst fallbackHtmlByGateId = /* @__PURE__ */ new Map<string, string>()\n\nexport function createResolvedGate(\n id: string,\n when: HydrationWhen,\n): HydrationGateRecord {\n return {\n id,\n when,\n promise: Promise.resolve(),\n resolve: () => {},\n resolved: true,\n consumers: 0,\n resolveListeners: new Set<() => void>(),\n }\n}\n\nexport function getOrCreateGate(\n id: string,\n when: HydrationWhen,\n): HydrationGateRecord {\n const existing = gateRegistry.get(id)\n if (existing?.when === when) {\n existing.consumers++\n return existing\n }\n\n let resolvePromise!: () => void\n const promise = new Promise<void>((resolve) => {\n resolvePromise = resolve\n })\n\n const gate: HydrationGateRecord = {\n id,\n promise,\n resolved: false,\n consumers: 1,\n when,\n resolveListeners: new Set(),\n resolve: () => {\n if (gate.resolved) return\n gate.resolved = true\n resolvePromise()\n gate.resolveListeners.forEach((listener) => listener())\n gate.resolveListeners.clear()\n },\n }\n\n gateRegistry.set(id, gate)\n if (when !== 'never' && resolvedGateIds.has(id)) {\n resolvedGateIds.delete(id)\n gate.resolve()\n }\n return gate\n}\n\nexport function releaseGate(gate: HydrationGateRecord) {\n resolvedGateIds.delete(gate.id)\n gate.consumers--\n if (gate.consumers > 0) return\n if (gateRegistry.get(gate.id) === gate) {\n gateRegistry.delete(gate.id)\n fallbackHtmlByGateId.delete(gate.id)\n gate.resolveListeners.clear()\n }\n}\n\nexport function onGateResolve(gate: HydrationGateRecord, listener: () => void) {\n if (gate.resolved) {\n listener()\n return () => {}\n }\n\n gate.resolveListeners.add(listener)\n return () => {\n gate.resolveListeners.delete(listener)\n }\n}\n\nexport function runHydrationStrategyCleanup(cleanup: void | (() => void)) {\n if (typeof cleanup === 'function') return cleanup\n return undefined\n}\n\nexport function waitForHydrationPrefetchStrategy(\n strategy: HydrationPrefetchStrategy,\n options: {\n element: Element | null\n signal: AbortSignal\n onHydrate: (listener: () => void) => () => void\n },\n): Promise<HydrationPrefetchWaitReason> {\n if (options.signal.aborted) {\n return Promise.resolve('abort')\n }\n\n return new Promise((resolve) => {\n const state = { disposed: false }\n const cleanupStrategyRef: { current: void | (() => void) } = {\n current: undefined,\n }\n let cleanupHydrate = () => {}\n\n const finish = (reason: HydrationPrefetchWaitReason) => {\n if (state.disposed) return\n state.disposed = true\n options.signal.removeEventListener('abort', onAbort)\n cleanupHydrate()\n runHydrationStrategyCleanup(cleanupStrategyRef.current)?.()\n resolve(reason)\n }\n\n const onAbort = () => finish('abort')\n\n options.signal.addEventListener('abort', onAbort, { once: true })\n cleanupHydrate = options.onHydrate(() => finish('hydrate'))\n const cleanupStrategy = strategy._s?.({\n element: options.element,\n prefetch: () => finish('prefetch'),\n })\n cleanupStrategyRef.current = cleanupStrategy\n if (state.disposed) {\n runHydrationStrategyCleanup(cleanupStrategy)?.()\n }\n })\n}\n\nexport function getMarkerGate(marker: Element) {\n const id = marker.getAttribute(hydrateIdAttribute)\n return id ? gateRegistry.get(id) : undefined\n}\n\nexport function resolveHydrationMarker(marker: Element) {\n const id = marker.getAttribute(hydrateIdAttribute)\n const when = marker.getAttribute(hydrateWhenAttribute)\n if (!id || !when || when === 'never') {\n return\n }\n\n const gate = gateRegistry.get(id)\n if (gate) {\n if (gate.when !== 'never') gate.resolve()\n return\n }\n\n resolvedGateIds.add(id)\n}\n\nexport function clearResolvedGateIdsInMarker(marker: Element) {\n const ownId = marker.getAttribute(hydrateIdAttribute)\n if (ownId) {\n resolvedGateIds.delete(ownId)\n }\n\n marker.querySelectorAll(hydrateIdSelector).forEach((childMarker) => {\n const childId = childMarker.getAttribute(hydrateIdAttribute)\n if (childId) {\n resolvedGateIds.delete(childId)\n }\n })\n}\n\nexport function saveFallbackHtml(id: string, element: Element) {\n if (!fallbackHtmlByGateId.has(id)) {\n fallbackHtmlByGateId.set(id, element.innerHTML)\n }\n}\n\nexport function getFallbackHtml(id: string) {\n return fallbackHtmlByGateId.get(id)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type HydrationWhen = 'load' | 'idle' | 'visible' | 'media' | 'interaction' | 'condition' | 'never' | 'dynamic';
|
|
2
|
+
export type HydrationInteractionEvent = 'auxclick' | 'click' | 'contextmenu' | 'dblclick' | 'focusin' | 'keydown' | 'keyup' | 'mousedown' | 'mouseenter' | 'mouseover' | 'mouseup' | 'pointerdown' | 'pointerenter' | 'pointerover' | 'pointerup';
|
|
3
|
+
export type HydrationInteractionEvents = HydrationInteractionEvent | ReadonlyArray<HydrationInteractionEvent>;
|
|
4
|
+
export type HydrationMarkerAttributes = Record<string, string | undefined>;
|
|
5
|
+
export type HydrationRuntimeGate = {
|
|
6
|
+
id?: string;
|
|
7
|
+
when?: HydrationWhen;
|
|
8
|
+
resolved: boolean;
|
|
9
|
+
resolve: () => void;
|
|
10
|
+
};
|
|
11
|
+
export type HydrationRuntimeContext = {
|
|
12
|
+
element: Element | null;
|
|
13
|
+
gate?: HydrationRuntimeGate;
|
|
14
|
+
prefetch?: () => void;
|
|
15
|
+
delegated?: boolean;
|
|
16
|
+
};
|
|
17
|
+
export type HydrationStrategyTypes<TWhen extends HydrationWhen = HydrationWhen, TCanPrefetch extends boolean = boolean> = {
|
|
18
|
+
when: TWhen;
|
|
19
|
+
canPrefetch: TCanPrefetch;
|
|
20
|
+
};
|
|
21
|
+
export type HydrationStrategy<TWhen extends HydrationWhen = HydrationWhen, TCanPrefetch extends boolean = boolean> = {
|
|
22
|
+
_t?: TWhen;
|
|
23
|
+
readonly '~types'?: HydrationStrategyTypes<TWhen, TCanPrefetch>;
|
|
24
|
+
_d?: () => boolean;
|
|
25
|
+
_s?: (context: HydrationRuntimeContext) => void | (() => void);
|
|
26
|
+
_o?: (id: string) => void;
|
|
27
|
+
_a?: () => HydrationMarkerAttributes | undefined;
|
|
28
|
+
};
|
|
29
|
+
export type HydrationPrefetchWhen = Exclude<HydrationWhen, 'condition' | 'never' | 'dynamic'>;
|
|
30
|
+
export type HydrationPrefetchStrategy<TWhen extends HydrationPrefetchWhen = HydrationPrefetchWhen> = HydrationStrategy<TWhen, true>;
|
|
31
|
+
export type HydrationPrefetchWaitReason = 'prefetch' | 'hydrate' | 'abort';
|
|
32
|
+
export type HydrationPrefetchContext = {
|
|
33
|
+
element: Element | null;
|
|
34
|
+
signal: AbortSignal;
|
|
35
|
+
preload: () => Promise<void>;
|
|
36
|
+
waitFor: (strategy: HydrationPrefetchStrategy) => Promise<HydrationPrefetchWaitReason>;
|
|
37
|
+
};
|
|
38
|
+
export type HydrationPrefetchFunction = (context: HydrationPrefetchContext) => void | Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { HydrationPrefetchStrategy } from './types.js';
|
|
2
|
+
declare const visibleType = "visible";
|
|
3
|
+
export type VisibleHydrationOptions = {
|
|
4
|
+
rootMargin?: string;
|
|
5
|
+
threshold?: number | Array<number>;
|
|
6
|
+
};
|
|
7
|
+
export declare function visible(options?: VisibleHydrationOptions): HydrationPrefetchStrategy<typeof visibleType>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//#region src/hydration/visible.ts
|
|
2
|
+
var visibleType = "visible";
|
|
3
|
+
var observerRegistry = /* @__PURE__ */ new Map();
|
|
4
|
+
function cleanupVisibleObserverEntry(observerEntry) {
|
|
5
|
+
if (observerEntry.elements.size > 0) return;
|
|
6
|
+
observerEntry.observer.disconnect();
|
|
7
|
+
observerRegistry.delete(observerEntry.key);
|
|
8
|
+
}
|
|
9
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
10
|
+
function visible(options = {}) {
|
|
11
|
+
const rootMargin = options.rootMargin ?? "600px";
|
|
12
|
+
const threshold = options.threshold ?? 0;
|
|
13
|
+
return {
|
|
14
|
+
_t: visibleType,
|
|
15
|
+
_s: ({ element, gate, prefetch }) => {
|
|
16
|
+
const callback = prefetch ?? gate.resolve;
|
|
17
|
+
if (!element) {
|
|
18
|
+
callback();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const key = `${rootMargin}|${Array.isArray(threshold) ? threshold.join(",") : String(threshold)}`;
|
|
22
|
+
let observerEntry = observerRegistry.get(key);
|
|
23
|
+
if (!observerEntry) {
|
|
24
|
+
const entry = {
|
|
25
|
+
key,
|
|
26
|
+
elements: /* @__PURE__ */ new Map(),
|
|
27
|
+
observer: new IntersectionObserver((entries) => {
|
|
28
|
+
for (const intersectingEntry of entries) {
|
|
29
|
+
if (!intersectingEntry.isIntersecting) continue;
|
|
30
|
+
const callbacks = entry.elements.get(intersectingEntry.target);
|
|
31
|
+
if (!callbacks) continue;
|
|
32
|
+
callbacks.forEach((callback) => callback());
|
|
33
|
+
entry.elements.delete(intersectingEntry.target);
|
|
34
|
+
entry.observer.unobserve(intersectingEntry.target);
|
|
35
|
+
cleanupVisibleObserverEntry(entry);
|
|
36
|
+
}
|
|
37
|
+
}, {
|
|
38
|
+
rootMargin,
|
|
39
|
+
threshold
|
|
40
|
+
})
|
|
41
|
+
};
|
|
42
|
+
observerRegistry.set(key, entry);
|
|
43
|
+
observerEntry = entry;
|
|
44
|
+
}
|
|
45
|
+
let callbacks = observerEntry.elements.get(element);
|
|
46
|
+
if (!callbacks) {
|
|
47
|
+
callbacks = /* @__PURE__ */ new Set();
|
|
48
|
+
observerEntry.elements.set(element, callbacks);
|
|
49
|
+
observerEntry.observer.observe(element);
|
|
50
|
+
}
|
|
51
|
+
callbacks.add(callback);
|
|
52
|
+
return () => {
|
|
53
|
+
const currentCallbacks = observerEntry.elements.get(element);
|
|
54
|
+
currentCallbacks?.delete(callback);
|
|
55
|
+
if (currentCallbacks?.size === 0) {
|
|
56
|
+
observerEntry.elements.delete(element);
|
|
57
|
+
observerEntry.observer.unobserve(element);
|
|
58
|
+
}
|
|
59
|
+
cleanupVisibleObserverEntry(observerEntry);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { visible };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=visible.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visible.js","names":[],"sources":["../../../src/hydration/visible.ts"],"sourcesContent":["import type { HydrationPrefetchStrategy } from './types'\n\nconst visibleType = 'visible'\n\nexport type VisibleHydrationOptions = {\n rootMargin?: string\n threshold?: number | Array<number>\n}\n\ntype VisibleObserverEntry = {\n key: string\n observer: IntersectionObserver\n elements: Map<Element, Set<() => void>>\n}\n\nconst observerRegistry = /* @__PURE__ */ new Map<string, VisibleObserverEntry>()\n\nfunction cleanupVisibleObserverEntry(observerEntry: VisibleObserverEntry) {\n if (observerEntry.elements.size > 0) return\n observerEntry.observer.disconnect()\n observerRegistry.delete(observerEntry.key)\n}\n\n/* @__NO_SIDE_EFFECTS__ */\nexport function visible(\n options: VisibleHydrationOptions = {},\n): HydrationPrefetchStrategy<typeof visibleType> {\n const rootMargin = options.rootMargin ?? '600px'\n const threshold = options.threshold ?? 0\n\n return {\n _t: visibleType,\n _s: ({ element, gate, prefetch }) => {\n const callback = prefetch ?? gate!.resolve\n\n if (!element) {\n callback()\n return\n }\n\n const key = `${rootMargin}|${\n Array.isArray(threshold) ? threshold.join(',') : String(threshold)\n }`\n let observerEntry = observerRegistry.get(key)\n\n if (!observerEntry) {\n const entry: VisibleObserverEntry = {\n key,\n elements: new Map<Element, Set<() => void>>(),\n observer: new IntersectionObserver(\n (entries) => {\n for (const intersectingEntry of entries) {\n if (!intersectingEntry.isIntersecting) continue\n\n const callbacks = entry.elements.get(intersectingEntry.target)\n if (!callbacks) continue\n\n callbacks.forEach((callback) => callback())\n entry.elements.delete(intersectingEntry.target)\n entry.observer.unobserve(intersectingEntry.target)\n cleanupVisibleObserverEntry(entry)\n }\n },\n { rootMargin, threshold },\n ),\n }\n observerRegistry.set(key, entry)\n observerEntry = entry\n }\n\n let callbacks = observerEntry.elements.get(element)\n if (!callbacks) {\n callbacks = new Set()\n observerEntry.elements.set(element, callbacks)\n observerEntry.observer.observe(element)\n }\n callbacks.add(callback)\n\n return () => {\n const currentCallbacks = observerEntry.elements.get(element)\n currentCallbacks?.delete(callback)\n if (currentCallbacks?.size === 0) {\n observerEntry.elements.delete(element)\n observerEntry.observer.unobserve(element)\n }\n cleanupVisibleObserverEntry(observerEntry)\n }\n },\n }\n}\n"],"mappings":";AAEA,IAAM,cAAc;AAapB,IAAM,mCAAmC,IAAI,KAAmC;AAEhF,SAAS,4BAA4B,eAAqC;AACxE,KAAI,cAAc,SAAS,OAAO,EAAG;AACrC,eAAc,SAAS,YAAY;AACnC,kBAAiB,OAAO,cAAc,IAAI;;;AAI5C,SAAgB,QACd,UAAmC,EAAE,EACU;CAC/C,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,YAAY,QAAQ,aAAa;AAEvC,QAAO;EACL,IAAI;EACJ,KAAK,EAAE,SAAS,MAAM,eAAe;GACnC,MAAM,WAAW,YAAY,KAAM;AAEnC,OAAI,CAAC,SAAS;AACZ,cAAU;AACV;;GAGF,MAAM,MAAM,GAAG,WAAW,GACxB,MAAM,QAAQ,UAAU,GAAG,UAAU,KAAK,IAAI,GAAG,OAAO,UAAU;GAEpE,IAAI,gBAAgB,iBAAiB,IAAI,IAAI;AAE7C,OAAI,CAAC,eAAe;IAClB,MAAM,QAA8B;KAClC;KACA,0BAAU,IAAI,KAA+B;KAC7C,UAAU,IAAI,sBACX,YAAY;AACX,WAAK,MAAM,qBAAqB,SAAS;AACvC,WAAI,CAAC,kBAAkB,eAAgB;OAEvC,MAAM,YAAY,MAAM,SAAS,IAAI,kBAAkB,OAAO;AAC9D,WAAI,CAAC,UAAW;AAEhB,iBAAU,SAAS,aAAa,UAAU,CAAC;AAC3C,aAAM,SAAS,OAAO,kBAAkB,OAAO;AAC/C,aAAM,SAAS,UAAU,kBAAkB,OAAO;AAClD,mCAA4B,MAAM;;QAGtC;MAAE;MAAY;MAAW,CAC1B;KACF;AACD,qBAAiB,IAAI,KAAK,MAAM;AAChC,oBAAgB;;GAGlB,IAAI,YAAY,cAAc,SAAS,IAAI,QAAQ;AACnD,OAAI,CAAC,WAAW;AACd,gCAAY,IAAI,KAAK;AACrB,kBAAc,SAAS,IAAI,SAAS,UAAU;AAC9C,kBAAc,SAAS,QAAQ,QAAQ;;AAEzC,aAAU,IAAI,SAAS;AAEvB,gBAAa;IACX,MAAM,mBAAmB,cAAc,SAAS,IAAI,QAAQ;AAC5D,sBAAkB,OAAO,SAAS;AAClC,QAAI,kBAAkB,SAAS,GAAG;AAChC,mBAAc,SAAS,OAAO,QAAQ;AACtC,mBAAc,SAAS,UAAU,QAAQ;;AAE3C,gCAA4B,cAAc;;;EAG/C"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export { condition } from './hydration/condition.js';
|
|
2
|
+
export type { HydrationCondition } from './hydration/condition.js';
|
|
3
|
+
export { hydrateIdAttribute, hydrateInteractionEventsAttribute, hydrateWhenAttribute, } from './hydration/constants.js';
|
|
4
|
+
export declare const hydrateIdSelector = "[data-ts-hydrate-id]";
|
|
5
|
+
export { idle } from './hydration/idle.js';
|
|
6
|
+
export type { IdleHydrationOptions } from './hydration/idle.js';
|
|
7
|
+
export { interaction } from './hydration/interaction.js';
|
|
8
|
+
export { load } from './hydration/load.js';
|
|
9
|
+
export { media } from './hydration/media.js';
|
|
10
|
+
export { never } from './hydration/never.js';
|
|
11
|
+
export { clearResolvedGateIdsInMarker, createResolvedGate, getFallbackHtml, getMarkerGate, getOrCreateGate, onGateResolve, releaseGate, resolveHydrationMarker, runHydrationStrategyCleanup, saveFallbackHtml, waitForHydrationPrefetchStrategy, } from './hydration/runtime.js';
|
|
12
|
+
export { withHydrationRenderer } from './hydration/renderer.js';
|
|
13
|
+
export { visible } from './hydration/visible.js';
|
|
14
|
+
export { listenForDelegatedHydrationIntent } from './hydration/interaction.js';
|
|
15
|
+
export type { VisibleHydrationOptions } from './hydration/visible.js';
|
|
16
|
+
export type { HydrationGateRecord } from './hydration/runtime.js';
|
|
17
|
+
export type { HydrationStrategyWithRenderer } from './hydration/renderer.js';
|
|
18
|
+
export type { HydrationInteractionEvent, HydrationInteractionEvents, HydrationMarkerAttributes, HydrationPrefetchContext, HydrationPrefetchFunction, HydrationPrefetchWhen, HydrationPrefetchStrategy, HydrationPrefetchWaitReason, HydrationRuntimeContext, HydrationRuntimeGate, HydrationStrategy, HydrationStrategyTypes, HydrationWhen, } from './hydration/types.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { hydrateIdAttribute, hydrateInteractionEventsAttribute, hydrateWhenAttribute } from "./hydration/constants.js";
|
|
2
|
+
import { condition } from "./hydration/condition.js";
|
|
3
|
+
import { idle } from "./hydration/idle.js";
|
|
4
|
+
import { clearResolvedGateIdsInMarker, createResolvedGate, getFallbackHtml, getMarkerGate, getOrCreateGate, onGateResolve, releaseGate, resolveHydrationMarker, runHydrationStrategyCleanup, saveFallbackHtml, waitForHydrationPrefetchStrategy } from "./hydration/runtime.js";
|
|
5
|
+
import { interaction, listenForDelegatedHydrationIntent } from "./hydration/interaction.js";
|
|
6
|
+
import { load } from "./hydration/load.js";
|
|
7
|
+
import { media } from "./hydration/media.js";
|
|
8
|
+
import { never } from "./hydration/never.js";
|
|
9
|
+
import { withHydrationRenderer } from "./hydration/renderer.js";
|
|
10
|
+
import { visible } from "./hydration/visible.js";
|
|
11
|
+
//#region src/hydration.ts
|
|
12
|
+
var hydrateIdSelector = `[${hydrateIdAttribute}]`;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { clearResolvedGateIdsInMarker, condition, createResolvedGate, getFallbackHtml, getMarkerGate, getOrCreateGate, hydrateIdAttribute, hydrateIdSelector, hydrateInteractionEventsAttribute, hydrateWhenAttribute, idle, interaction, listenForDelegatedHydrationIntent, load, media, never, onGateResolve, releaseGate, resolveHydrationMarker, runHydrationStrategyCleanup, saveFallbackHtml, visible, waitForHydrationPrefetchStrategy, withHydrationRenderer };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=hydration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydration.js","names":[],"sources":["../../src/hydration.ts"],"sourcesContent":["import { hydrateIdAttribute } from './hydration/constants'\n\nexport { condition } from './hydration/condition'\nexport type { HydrationCondition } from './hydration/condition'\nexport {\n hydrateIdAttribute,\n hydrateInteractionEventsAttribute,\n hydrateWhenAttribute,\n} from './hydration/constants'\nexport const hydrateIdSelector = `[${hydrateIdAttribute}]`\nexport { idle } from './hydration/idle'\nexport type { IdleHydrationOptions } from './hydration/idle'\nexport { interaction } from './hydration/interaction'\nexport { load } from './hydration/load'\nexport { media } from './hydration/media'\nexport { never } from './hydration/never'\nexport {\n clearResolvedGateIdsInMarker,\n createResolvedGate,\n getFallbackHtml,\n getMarkerGate,\n getOrCreateGate,\n onGateResolve,\n releaseGate,\n resolveHydrationMarker,\n runHydrationStrategyCleanup,\n saveFallbackHtml,\n waitForHydrationPrefetchStrategy,\n} from './hydration/runtime'\nexport { withHydrationRenderer } from './hydration/renderer'\nexport { visible } from './hydration/visible'\nexport { listenForDelegatedHydrationIntent } from './hydration/interaction'\nexport type { VisibleHydrationOptions } from './hydration/visible'\nexport type { HydrationGateRecord } from './hydration/runtime'\nexport type { HydrationStrategyWithRenderer } from './hydration/renderer'\nexport type {\n HydrationInteractionEvent,\n HydrationInteractionEvents,\n HydrationMarkerAttributes,\n HydrationPrefetchContext,\n HydrationPrefetchFunction,\n HydrationPrefetchWhen,\n HydrationPrefetchStrategy,\n HydrationPrefetchWaitReason,\n HydrationRuntimeContext,\n HydrationRuntimeGate,\n HydrationStrategy,\n HydrationStrategyTypes,\n HydrationWhen,\n} from './hydration/types'\n"],"mappings":";;;;;;;;;;;AASA,IAAa,oBAAoB,IAAI,mBAAmB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/start-client-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.170.0",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,16 +44,37 @@
|
|
|
44
44
|
"default": "./dist/esm/client-rpc/index.js"
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
|
+
"./hydration": {
|
|
48
|
+
"import": {
|
|
49
|
+
"types": "./dist/esm/hydration.d.ts",
|
|
50
|
+
"default": "./dist/esm/hydration.js"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"./hydration/constants": {
|
|
54
|
+
"import": {
|
|
55
|
+
"types": "./dist/esm/hydration/constants.d.ts",
|
|
56
|
+
"default": "./dist/esm/hydration/constants.js"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"./hydration/runtime": {
|
|
60
|
+
"import": {
|
|
61
|
+
"types": "./dist/esm/hydration/runtime.d.ts",
|
|
62
|
+
"default": "./dist/esm/hydration/runtime.js"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
47
65
|
"./package.json": "./package.json"
|
|
48
66
|
},
|
|
49
67
|
"imports": {
|
|
50
68
|
"#tanstack-start-entry": {
|
|
69
|
+
"types": "./src/start-entry.d.ts",
|
|
51
70
|
"default": "./dist/esm/fake-entries/start.js"
|
|
52
71
|
},
|
|
53
72
|
"#tanstack-router-entry": {
|
|
73
|
+
"types": "./src/start-entry.d.ts",
|
|
54
74
|
"default": "./dist/esm/fake-entries/router.js"
|
|
55
75
|
},
|
|
56
76
|
"#tanstack-start-plugin-adapters": {
|
|
77
|
+
"types": "./src/start-entry.d.ts",
|
|
57
78
|
"default": "./dist/esm/fake-entries/plugin-adapters.js"
|
|
58
79
|
}
|
|
59
80
|
},
|
|
@@ -70,9 +91,9 @@
|
|
|
70
91
|
},
|
|
71
92
|
"dependencies": {
|
|
72
93
|
"seroval": "^1.5.4",
|
|
73
|
-
"@tanstack/router-core": "1.171.
|
|
94
|
+
"@tanstack/router-core": "1.171.3",
|
|
74
95
|
"@tanstack/start-fn-stubs": "1.162.0",
|
|
75
|
-
"@tanstack/start-storage-context": "1.167.
|
|
96
|
+
"@tanstack/start-storage-context": "1.167.5"
|
|
76
97
|
},
|
|
77
98
|
"devDependencies": {
|
|
78
99
|
"vite": "*",
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { hydrate } from '@tanstack/router-core/ssr/client'
|
|
2
|
-
|
|
3
2
|
import { startInstance } from '#tanstack-start-entry'
|
|
4
3
|
import {
|
|
5
4
|
hasPluginAdapters,
|
|
@@ -10,7 +9,19 @@ import { ServerFunctionSerializationAdapter } from './ServerFunctionSerializatio
|
|
|
10
9
|
import type { AnyRouter, AnySerializationAdapter } from '@tanstack/router-core'
|
|
11
10
|
import type { AnyStartInstanceOptions } from '../createStart'
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
type HotContext = {
|
|
13
|
+
data?: Record<string, unknown>
|
|
14
|
+
dispose?: (cb: (data: Record<string, unknown>) => void) => void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare global {
|
|
18
|
+
interface ImportMeta {
|
|
19
|
+
hot?: HotContext
|
|
20
|
+
webpackHot?: HotContext
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function hydrateStart(): Promise<AnyRouter> {
|
|
14
25
|
const router = await getRouter()
|
|
15
26
|
|
|
16
27
|
let serializationAdapters: Array<AnySerializationAdapter>
|
|
@@ -47,3 +58,38 @@ export async function hydrateStart(): Promise<AnyRouter> {
|
|
|
47
58
|
|
|
48
59
|
return router
|
|
49
60
|
}
|
|
61
|
+
|
|
62
|
+
function hydrateStartWithHmr(): Promise<AnyRouter> {
|
|
63
|
+
const hot = import.meta.hot ?? import.meta.webpackHot
|
|
64
|
+
|
|
65
|
+
if (!hot) {
|
|
66
|
+
return hydrateStart()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const key = 'tss-hydrate-start-promise'
|
|
70
|
+
const hotData = (hot.data ??= {})
|
|
71
|
+
let hydrationPromise = hotData[key] as Promise<AnyRouter> | undefined
|
|
72
|
+
|
|
73
|
+
if (!hydrationPromise) {
|
|
74
|
+
hydrationPromise = hydrateStart().catch((error) => {
|
|
75
|
+
if (hotData[key] === hydrationPromise) {
|
|
76
|
+
hotData[key] = undefined
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
throw error
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
hotData[key] = hydrationPromise
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
hot.dispose?.((data) => {
|
|
86
|
+
data[key] = hotData[key]
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
return hydrationPromise
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const exportedHydrateStart =
|
|
93
|
+
process.env.NODE_ENV !== 'production' ? hydrateStartWithHmr : hydrateStart
|
|
94
|
+
|
|
95
|
+
export { exportedHydrateStart as hydrateStart }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { HydrationStrategy } from './types'
|
|
2
|
+
|
|
3
|
+
const conditionType = 'condition'
|
|
4
|
+
|
|
5
|
+
export type HydrationCondition = boolean | (() => boolean)
|
|
6
|
+
|
|
7
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
8
|
+
export function condition(
|
|
9
|
+
condition: HydrationCondition,
|
|
10
|
+
): HydrationStrategy<typeof conditionType, false> {
|
|
11
|
+
return {
|
|
12
|
+
_t: conditionType,
|
|
13
|
+
_d: () => !(typeof condition === 'function' ? condition() : condition),
|
|
14
|
+
_s: ({ gate }) => {
|
|
15
|
+
if (typeof condition === 'function' ? condition() : condition) {
|
|
16
|
+
gate!.resolve()
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { HydrationPrefetchStrategy } from './types'
|
|
2
|
+
|
|
3
|
+
const idleType = 'idle'
|
|
4
|
+
|
|
5
|
+
export type IdleHydrationOptions = {
|
|
6
|
+
timeout?: number
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function idle(
|
|
10
|
+
options: IdleHydrationOptions = {},
|
|
11
|
+
): HydrationPrefetchStrategy<typeof idleType> {
|
|
12
|
+
const timeout = options.timeout ?? 2000
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
_t: idleType,
|
|
16
|
+
_s: ({ gate, prefetch }) => {
|
|
17
|
+
const schedule = globalThis as unknown as {
|
|
18
|
+
requestIdleCallback?: (
|
|
19
|
+
callback: IdleRequestCallback,
|
|
20
|
+
options?: IdleRequestOptions,
|
|
21
|
+
) => number
|
|
22
|
+
cancelIdleCallback?: (handle: number) => void
|
|
23
|
+
}
|
|
24
|
+
const callback = prefetch ?? gate!.resolve
|
|
25
|
+
|
|
26
|
+
if (schedule.requestIdleCallback) {
|
|
27
|
+
const handle = schedule.requestIdleCallback(callback, { timeout })
|
|
28
|
+
return () => schedule.cancelIdleCallback?.(handle)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const timeoutId = globalThis.setTimeout(callback, timeout)
|
|
32
|
+
return () => globalThis.clearTimeout(timeoutId)
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
}
|