Skip to content

Commit 29ba38a

Browse files
Varixowmertens
authored andcommitted
fix: handle head action changes
1 parent 761cd49 commit 29ba38a

File tree

5 files changed

+59
-33
lines changed

5 files changed

+59
-33
lines changed

packages/qwik-router/src/runtime/src/head.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
import { withLocale } from '@qwik.dev/core';
1+
import { untrack, withLocale } from '@qwik.dev/core';
2+
import { _retryOnPromise } from '@qwik.dev/core/internal';
23
import type {
34
ContentModule,
45
RouteLocation,
5-
EndpointResponse,
66
ResolvedDocumentHead,
77
DocumentHeadProps,
88
DocumentHeadValue,
9-
ClientPageData,
109
LoaderInternal,
1110
Editable,
1211
ResolveSyncValue,
1312
ActionInternal,
13+
LoaderSignal,
14+
ClientActionData,
1415
} from './types';
1516
import { isPromise } from './utils';
1617

17-
export const resolveHead = (
18-
endpoint: EndpointResponse | ClientPageData,
18+
export const resolveHead = async (
19+
loaderState: Record<string, LoaderSignal<unknown>>,
20+
action: ClientActionData | undefined,
1921
routeLocation: RouteLocation,
2022
contentModules: ContentModule[],
2123
locale: string,
@@ -25,13 +27,19 @@ export const resolveHead = (
2527
const getData = ((loaderOrAction: LoaderInternal | ActionInternal) => {
2628
const id = loaderOrAction.__id;
2729
if (loaderOrAction.__brand === 'server_loader') {
28-
if (!(id in endpoint.loaders)) {
30+
if (!(id in loaderState)) {
2931
throw new Error(
3032
'You can not get the returned data of a loader that has not been executed for this request.'
3133
);
3234
}
35+
} else if (
36+
action &&
37+
action.id === loaderOrAction.__id &&
38+
loaderOrAction.__brand === 'server_action'
39+
) {
40+
return action.data;
3341
}
34-
const data = endpoint.loaders[id];
42+
const data = untrack(() => loaderState[id]?.value);
3543
if (isPromise(data)) {
3644
throw new Error('Loaders returning a promise can not be resolved for the head function.');
3745
}
@@ -48,9 +56,10 @@ export const resolveHead = (
4856
const contentModuleHead = contentModules[i] && contentModules[i].head;
4957
if (contentModuleHead) {
5058
if (typeof contentModuleHead === 'function') {
59+
const contentModuleHeadResult = await _retryOnPromise(() => contentModuleHead(headProps));
5160
resolveDocumentHead(
5261
head,
53-
withLocale(locale, () => contentModuleHead(headProps))
62+
withLocale(locale, () => contentModuleHeadResult)
5463
);
5564
} else if (typeof contentModuleHead === 'object') {
5665
resolveDocumentHead(head, contentModuleHead);

packages/qwik-router/src/runtime/src/qwik-router-component.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,14 @@ export const useQwikRouter = (props?: QwikRouterProps) => {
493493
(routeInternal as any).untrackedValue = { type: navType, dest: trackUrl };
494494

495495
// Needs to be done after routeLocation is updated
496-
const resolvedHead = resolveHead(
497-
clientPageData!,
496+
const resolvedHead = await resolveHead(
497+
loaderState,
498+
clientPageData?.action,
499+
498500
routeLocation,
501+
499502
contentModules,
503+
500504
locale,
501505
serverHead
502506
);
@@ -554,6 +558,12 @@ export const useQwikRouter = (props?: QwikRouterProps) => {
554558
signal.invalidate();
555559
}
556560
}
561+
// remove not existing loaders
562+
for (const key of Object.keys(loaderState)) {
563+
if (!(key in loadersObject)) {
564+
delete loaderState[key];
565+
}
566+
}
557567
}
558568

559569
const win = window as ClientSPAWindow;

packages/qwik/src/core/internal.ts

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,64 +15,64 @@ export type {
1515
VNode as _VNode,
1616
VNodeFlags as _VNodeFlags,
1717
} from './client/types';
18-
export {
19-
vnode_toString as _vnode_toString,
20-
vnode_getPropStartIndex as _vnode_getPropStartIndex,
21-
vnode_getProps as _vnode_getProps,
22-
vnode_isTextVNode as _vnode_isTextVNode,
23-
vnode_isVirtualVNode as _vnode_isVirtualVNode,
24-
vnode_getFirstChild as _vnode_getFirstChild,
25-
vnode_isMaterialized as _vnode_isMaterialized,
26-
vnode_getNextSibling as _vnode_getNextSibling,
27-
vnode_ensureElementInflated as _vnode_ensureElementInflated,
28-
vnode_getAttrKeys as _vnode_getAttrKeys,
29-
vnode_getAttr as _vnode_getAttr,
30-
} from './client/vnode';
3118
export {
3219
mapApp_findIndx as _mapApp_findIndx,
3320
mapArray_get as _mapArray_get,
3421
mapArray_set as _mapArray_set,
3522
} from './client/util-mapArray';
23+
export {
24+
vnode_ensureElementInflated as _vnode_ensureElementInflated,
25+
vnode_getAttr as _vnode_getAttr,
26+
vnode_getAttrKeys as _vnode_getAttrKeys,
27+
vnode_getFirstChild as _vnode_getFirstChild,
28+
vnode_getNextSibling as _vnode_getNextSibling,
29+
vnode_getProps as _vnode_getProps,
30+
vnode_getPropStartIndex as _vnode_getPropStartIndex,
31+
vnode_isMaterialized as _vnode_isMaterialized,
32+
vnode_isTextVNode as _vnode_isTextVNode,
33+
vnode_isVirtualVNode as _vnode_isVirtualVNode,
34+
vnode_toString as _vnode_toString,
35+
} from './client/vnode';
3636

37+
export { _hasStoreEffects, isStore as _isStore } from './reactive-primitives/impl/store';
3738
export { _wrapProp, _wrapSignal } from './reactive-primitives/internal-api';
3839
export { SubscriptionData as _SubscriptionData } from './reactive-primitives/subscription-data';
3940
export { _EFFECT_BACK_REF } from './reactive-primitives/types';
40-
export { _hasStoreEffects } from './reactive-primitives/impl/store';
4141
export {
4242
isStringifiable as _isStringifiable,
4343
type Stringifiable as _Stringifiable,
4444
} from './shared-types';
4545
export {
46+
_getConstProps,
47+
_getVarProps,
4648
isJSXNode as _isJSXNode,
4749
_jsxC,
4850
_jsxQ,
4951
_jsxS,
5052
_jsxSorted,
5153
_jsxSplit,
52-
_getVarProps,
53-
_getConstProps,
5454
} from './shared/jsx/jsx-runtime';
5555
export { _fnSignal } from './shared/qrl/inlined-fn';
56-
export { _SharedContainer } from './shared/shared-container';
5756
export {
5857
_deserialize,
5958
dumpState as _dumpState,
6059
preprocessState as _preprocessState,
6160
_serializationWeakRef,
6261
_serialize,
6362
} from './shared/serdes/index';
64-
export { _CONST_PROPS, _IMMUTABLE, _VAR_PROPS, _UNINITIALIZED } from './shared/utils/constants';
63+
export { _SharedContainer } from './shared/shared-container';
64+
export { _CONST_PROPS, _IMMUTABLE, _UNINITIALIZED, _VAR_PROPS } from './shared/utils/constants';
6565
export { EMPTY_ARRAY as _EMPTY_ARRAY } from './shared/utils/flyweight';
66+
export { retryOnPromise as _retryOnPromise } from './shared/utils/promises';
6667
export { _restProps } from './shared/utils/prop';
6768
export { verifySerializable as _verifySerializable } from './shared/utils/serialize-utils';
6869
export { _walkJSX } from './ssr/ssr-render-jsx';
70+
export { _resolveContextWithoutSequentialScope } from './use/use-context';
6971
export {
72+
_getContextContainer,
7073
_getContextElement,
7174
_getContextEvent,
72-
_getContextContainer,
7375
_jsxBranch,
7476
_waitUntilRendered,
7577
} from './use/use-core';
76-
export { scheduleTask as _task, isTask as _isTask } from './use/use-task';
77-
export { isStore as _isStore } from './reactive-primitives/impl/store';
78-
export { _resolveContextWithoutSequentialScope } from './use/use-context';
78+
export { isTask as _isTask, scheduleTask as _task } from './use/use-task';

packages/qwik/src/core/qwik.core.api.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,9 @@ export type ResourceReturn<T> = ResourcePending<T> | ResourceResolved<T> | Resou
902902
// @internal (undocumented)
903903
export const _restProps: (props: PropsProxy, omit?: string[], target?: Props) => Props;
904904

905+
// @internal
906+
export function _retryOnPromise<T>(fn: () => ValueOrPromise<T>, retryCount?: number): ValueOrPromise<T>;
907+
905908
// @internal
906909
export const _run: (...args: unknown[]) => ValueOrPromise<unknown>;
907910

packages/qwik/src/core/shared/utils/promises.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,11 @@ export const delay = (timeout: number) => {
9696
});
9797
};
9898

99-
/** Retries a function that throws a promise. */
99+
/**
100+
* Retries a function that throws a promise.
101+
*
102+
* @internal
103+
*/
100104
export function retryOnPromise<T>(
101105
fn: () => ValueOrPromise<T>,
102106
retryCount: number = 0

0 commit comments

Comments
 (0)