|
| 1 | +import { isServer } from '@qwik.dev/core/build'; |
| 2 | +// @ts-expect-error we don't have types for the preloader |
| 3 | +import { p as preload } from '@qwik.dev/core/preloader'; |
1 | 4 | import type { DeserializeContainer } from '../types'; |
2 | 5 | import { TypeIds } from './constants'; |
3 | 6 |
|
@@ -95,14 +98,49 @@ export function preprocessState(data: unknown[], container: DeserializeContainer |
95 | 98 | data[index + 1] = object; |
96 | 99 | }; |
97 | 100 |
|
| 101 | + const toPreload: number[] | undefined = isServer ? undefined : []; |
98 | 102 | for (let i = 0; i < data.length; i += 2) { |
99 | 103 | if (isRootDeepRef(data[i] as TypeIds, data[i + 1])) { |
100 | 104 | processRootRef(i); |
101 | 105 | } else if (isForwardRefsMap(data[i] as TypeIds)) { |
102 | 106 | container.$forwardRefs$ = data[i + 1] as number[]; |
103 | | - } else if (isPreloadQrlType(data[i] as TypeIds)) { |
| 107 | + } else if (!isServer && isPreloadQrlType(data[i] as TypeIds)) { |
| 108 | + // preload QRLs are always serialized as strings with chunk and symbol ids |
104 | 109 | const qrl = data[i + 1] as string; |
105 | | - (container.$initialQRLs$ ||= []).push(qrl); |
| 110 | + const chunkIdx = Number(qrl.split(' ')[0]); |
| 111 | + toPreload!.push(chunkIdx); |
| 112 | + } |
| 113 | + } |
| 114 | + |
| 115 | + /** |
| 116 | + * Preloads QRLs that are defined in the state data as `PreloadQRL`. |
| 117 | + * |
| 118 | + * This is done because when computed and custom serializer QRLs are called they need QRL to work. |
| 119 | + * If the QRL is not resolved at this point, it will be resolved by throwing a promise and |
| 120 | + * rerunning the whole wrapping function again. We want to avoid that, because it means that the |
| 121 | + * function can execute twice. |
| 122 | + * |
| 123 | + * ```ts |
| 124 | + * useVisibleTask$(() => { |
| 125 | + * runHeavyLogic(); // This will be called again if the QRL of `computedOrCustomSerializer` is not resolved. |
| 126 | + * console.log(computedOrCustomSerializer.value); // Throw a promise if QRL not resolved and execute visible task again. |
| 127 | + * }); |
| 128 | + * ``` |
| 129 | + */ |
| 130 | + if (!isServer) { |
| 131 | + for (const idx of toPreload!) { |
| 132 | + // we preload the chunk instead of the symbol so it also works in dev |
| 133 | + const chunkType = data[idx * 2] as TypeIds; |
| 134 | + let chunk: string; |
| 135 | + if (chunkType === TypeIds.Plain) { |
| 136 | + chunk = data[idx * 2 + 1] as string; |
| 137 | + } else if (chunkType === TypeIds.RootRef) { |
| 138 | + const refIdx = data[idx * 2 + 1] as number; |
| 139 | + chunk = data[refIdx * 2 + 1] as string; |
| 140 | + } else { |
| 141 | + continue; |
| 142 | + } |
| 143 | + preload(chunk, 0.3); |
106 | 144 | } |
107 | 145 | } |
108 | 146 | } |
0 commit comments