vike 0.4.196 → 0.4.197-commit-9db6c02
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/cjs/client/client-routing-runtime/prefetch/PrefetchSetting.js +2 -0
- package/dist/cjs/client/server-routing-runtime/onLoad.js +7 -0
- package/dist/cjs/client/server-routing-runtime/utils.js +34 -0
- package/dist/cjs/client/shared/getPageContextProxyForUser.js +79 -0
- package/dist/cjs/client/shared/preparePageContextForUserConsumptionClientSide.js +46 -0
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +17 -1
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +2 -2
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolvePointerImport.js +26 -23
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/{transformFileImports.js → transformPointerImports.js} +3 -4
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +44 -47
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +1 -1
- package/dist/cjs/node/prerender/runPrerender.js +5 -5
- package/dist/cjs/node/runtime/html/injectAssets/getHtmlTags.js +1 -1
- package/dist/cjs/node/runtime/html/injectAssets/injectAssets__public.js +1 -1
- package/dist/cjs/node/runtime/html/serializePageContextClientSide.js +2 -2
- package/dist/cjs/node/runtime/renderPage/createHttpResponse.js +3 -3
- package/dist/cjs/node/runtime/renderPage/debugPageFiles.js +1 -1
- package/dist/cjs/node/runtime/renderPage/handleErrorWithoutErrorPage.js +1 -1
- package/dist/cjs/node/runtime/renderPage/loadUserFilesServerSide.js +4 -4
- package/dist/cjs/node/runtime/renderPage/preparePageContextForUserConsumptionServerSide.js +2 -7
- package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +4 -4
- package/dist/cjs/node/runtime/renderPage.js +8 -8
- package/dist/cjs/shared/addIs404ToPageProps.js +1 -1
- package/dist/cjs/shared/assertPageContextProvidedByUser.js +1 -1
- package/dist/cjs/shared/page-configs/serialize/serializeConfigValues.js +2 -2
- package/dist/cjs/shared/preparePageContextForUserConsumption.js +34 -0
- package/dist/cjs/shared/route/executeGuardHook.js +1 -1
- package/dist/cjs/shared/route/executeOnBeforeRouteHook.js +6 -6
- package/dist/cjs/shared/route/index.js +3 -3
- package/dist/cjs/shared/route/resolveRouteString.js +10 -1
- package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
- package/dist/cjs/utils/isNpmPackage.js +4 -0
- package/dist/cjs/utils/isScriptFile.js +3 -3
- package/dist/esm/client/client-routing-runtime/entry.js +2 -2
- package/dist/esm/client/client-routing-runtime/getPageContextCurrent.d.ts +10 -0
- package/dist/esm/client/client-routing-runtime/getPageContextCurrent.js +25 -0
- package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.d.ts +28 -18
- package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +39 -32
- package/dist/esm/client/client-routing-runtime/history.js +1 -1
- package/dist/esm/client/client-routing-runtime/initClientRouter.d.ts +2 -0
- package/dist/esm/client/client-routing-runtime/{installClientRouter.js → initClientRouter.js} +11 -8
- package/dist/esm/client/client-routing-runtime/initOnLinkClick.d.ts +2 -0
- package/dist/esm/client/client-routing-runtime/{onLinkClick.js → initOnLinkClick.js} +2 -2
- package/dist/esm/client/client-routing-runtime/isClientSideRoutable.js +1 -0
- package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.js +1 -1
- package/dist/esm/client/client-routing-runtime/prefetch/PrefetchSetting.d.ts +7 -0
- package/dist/esm/client/client-routing-runtime/prefetch/PrefetchSetting.js +1 -0
- package/dist/esm/client/client-routing-runtime/prefetch/getPrefetchSettings.d.ts +8 -7
- package/dist/esm/client/client-routing-runtime/prefetch/getPrefetchSettings.js +74 -67
- package/dist/esm/client/client-routing-runtime/prefetch.d.ts +16 -5
- package/dist/esm/client/client-routing-runtime/prefetch.js +167 -64
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +115 -28
- package/dist/esm/client/server-routing-runtime/getPageContext.d.ts +1 -1
- package/dist/esm/client/server-routing-runtime/getPageContext.js +1 -1
- package/dist/esm/client/shared/executeOnRenderClientHook.d.ts +1 -1
- package/dist/esm/client/shared/getPageContextSerializedInHtml.d.ts +1 -1
- package/dist/esm/client/shared/getPageContextSerializedInHtml.js +1 -1
- package/dist/esm/client/shared/preparePageContextForUserConsumptionClientSide.d.ts +1 -1
- package/dist/esm/client/shared/preparePageContextForUserConsumptionClientSide.js +20 -29
- package/dist/esm/client/shared/removeFoucBuster.js +17 -11
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +17 -1
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +1 -1
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolvePointerImport.d.ts +1 -1
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolvePointerImport.js +25 -22
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/{transformFileImports.d.ts → transformPointerImports.d.ts} +2 -2
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/{transformFileImports.js → transformPointerImports.js} +3 -4
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +45 -48
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +1 -1
- package/dist/esm/node/prerender/runPrerender.js +5 -5
- package/dist/esm/node/runtime/html/injectAssets/getHtmlTags.js +1 -1
- package/dist/esm/node/runtime/html/injectAssets/injectAssets__public.js +1 -1
- package/dist/esm/node/runtime/html/injectAssets.d.ts +1 -1
- package/dist/esm/node/runtime/html/serializePageContextClientSide.d.ts +1 -1
- package/dist/esm/node/runtime/html/serializePageContextClientSide.js +2 -2
- package/dist/esm/node/runtime/renderPage/createHttpResponse.d.ts +1 -1
- package/dist/esm/node/runtime/renderPage/createHttpResponse.js +3 -3
- package/dist/esm/node/runtime/renderPage/debugPageFiles.d.ts +1 -1
- package/dist/esm/node/runtime/renderPage/debugPageFiles.js +1 -1
- package/dist/esm/node/runtime/renderPage/executeOnBeforeRenderAndDataHooks.d.ts +1 -1
- package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.d.ts +1 -1
- package/dist/esm/node/runtime/renderPage/handleErrorWithoutErrorPage.d.ts +1 -1
- package/dist/esm/node/runtime/renderPage/handleErrorWithoutErrorPage.js +1 -1
- package/dist/esm/node/runtime/renderPage/loadUserFilesServerSide.d.ts +1 -1
- package/dist/esm/node/runtime/renderPage/loadUserFilesServerSide.js +4 -4
- package/dist/esm/node/runtime/renderPage/preparePageContextForUserConsumptionServerSide.d.ts +1 -1
- package/dist/esm/node/runtime/renderPage/preparePageContextForUserConsumptionServerSide.js +3 -8
- package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +6 -6
- package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +4 -4
- package/dist/esm/node/runtime/renderPage.js +8 -8
- package/dist/esm/shared/addIs404ToPageProps.d.ts +1 -1
- package/dist/esm/shared/addIs404ToPageProps.js +1 -1
- package/dist/esm/shared/assertPageContextProvidedByUser.js +1 -1
- package/dist/esm/shared/page-configs/Config.d.ts +21 -1
- package/dist/esm/shared/page-configs/serialize/serializeConfigValues.js +1 -1
- package/dist/esm/shared/preparePageContextForUserConsumption.d.ts +5 -0
- package/dist/esm/shared/preparePageContextForUserConsumption.js +32 -0
- package/dist/esm/shared/route/executeGuardHook.d.ts +1 -1
- package/dist/esm/shared/route/executeGuardHook.js +1 -1
- package/dist/esm/shared/route/executeOnBeforeRouteHook.js +6 -6
- package/dist/esm/shared/route/index.d.ts +1 -1
- package/dist/esm/shared/route/index.js +3 -3
- package/dist/esm/shared/route/resolveRouteString.d.ts +2 -15
- package/dist/esm/shared/route/resolveRouteString.js +10 -1
- package/dist/esm/shared/types.d.ts +6 -2
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
- package/dist/esm/utils/PROJECT_VERSION.js +1 -1
- package/dist/esm/utils/isNpmPackage.d.ts +2 -0
- package/dist/esm/utils/isNpmPackage.js +4 -0
- package/dist/esm/utils/isScriptFile.d.ts +2 -2
- package/dist/esm/utils/isScriptFile.js +3 -3
- package/dist/esm/utils/projectInfo.d.ts +1 -1
- package/package.json +1 -1
- package/dist/cjs/shared/sortPageContext.js +0 -12
- package/dist/esm/client/client-routing-runtime/installClientRouter.d.ts +0 -2
- package/dist/esm/client/client-routing-runtime/onLinkClick.d.ts +0 -2
- package/dist/esm/client/client-routing-runtime/prefetch/alreadyPrefetched.d.ts +0 -4
- package/dist/esm/client/client-routing-runtime/prefetch/alreadyPrefetched.js +0 -16
- package/dist/esm/shared/sortPageContext.d.ts +0 -2
- package/dist/esm/shared/sortPageContext.js +0 -10
- /package/{readme.md → README.md} +0 -0
|
@@ -1,21 +1,43 @@
|
|
|
1
1
|
export { prefetch };
|
|
2
|
+
export { getPageContextPrefetched };
|
|
3
|
+
export { initLinkPrefetchHandlers };
|
|
2
4
|
export { addLinkPrefetchHandlers };
|
|
3
|
-
|
|
5
|
+
export { addLinkPrefetchHandlers_watch };
|
|
6
|
+
export { addLinkPrefetchHandlers_unwatch };
|
|
7
|
+
import { assert, assertClientRouting, assertUsage, assertUsageUrlPathname, assertWarning, checkIfClientRouting, getGlobalObject, hasProp, objectAssign } from './utils.js';
|
|
4
8
|
import { isErrorFetchingStaticAssets, loadUserFilesClientSide } from '../shared/loadUserFilesClientSide.js';
|
|
5
9
|
import { skipLink } from './skipLink.js';
|
|
6
|
-
import { getPrefetchSettings } from './prefetch/getPrefetchSettings.js';
|
|
7
|
-
import { isAlreadyPrefetched, markAsAlreadyPrefetched } from './prefetch/alreadyPrefetched.js';
|
|
8
10
|
import { disableClientRouting } from './renderPageClientSide.js';
|
|
9
11
|
import { isClientSideRoutable } from './isClientSideRoutable.js';
|
|
10
12
|
import { createPageContext } from './createPageContext.js';
|
|
11
13
|
import { route } from '../../shared/route/index.js';
|
|
12
14
|
import { noRouteMatch } from '../../shared/route/noRouteMatch.js';
|
|
15
|
+
import { getPageContextFromServerHooks } from './getPageContextFromHooks.js';
|
|
16
|
+
import { getPageContextCurrent } from './getPageContextCurrent.js';
|
|
17
|
+
import { PAGE_CONTEXT_MAX_AGE_DEFAULT, getPrefetchSettings } from './prefetch/getPrefetchSettings.js';
|
|
13
18
|
import pc from '@brillout/picocolors';
|
|
14
19
|
assertClientRouting();
|
|
15
|
-
const globalObject = getGlobalObject('prefetch.ts', {
|
|
16
|
-
|
|
20
|
+
const globalObject = getGlobalObject('prefetch.ts', {
|
|
21
|
+
linkPrefetchHandlerAdded: new WeakSet(),
|
|
22
|
+
addLinkPrefetchHandlers_debounce: null,
|
|
23
|
+
mutationObserver: new MutationObserver(addLinkPrefetchHandlers),
|
|
24
|
+
// `linkTags` [is automatically updated](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection#:~:text=An%20HTMLCollection%20in%20the%20HTML%20DOM%20is%20live%3B%20it%20is%20automatically%20updated%20when%20the%20underlying%20document%20is%20changed.)
|
|
25
|
+
linkTags: document.getElementsByTagName('A'),
|
|
26
|
+
prefetchedPageContexts: {}
|
|
27
|
+
});
|
|
28
|
+
function getPageContextPrefetched(pageContext) {
|
|
29
|
+
const url = pageContext.urlOriginal;
|
|
30
|
+
const found = globalObject.prefetchedPageContexts[url];
|
|
31
|
+
if (!found || found.result.is404ServerSideRouted || isExpired(found))
|
|
32
|
+
return null;
|
|
33
|
+
const pageContextPrefetched = found.result.pageContextFromServerHooks;
|
|
34
|
+
// We discard the prefetched pageContext whenever we use it, so that the user always sees fresh data upon naivgating.
|
|
35
|
+
delete globalObject.prefetchedPageContexts[url];
|
|
36
|
+
return pageContextPrefetched;
|
|
37
|
+
}
|
|
38
|
+
async function prefetchAssets(pageContextLink) {
|
|
17
39
|
try {
|
|
18
|
-
await loadUserFilesClientSide(pageId,
|
|
40
|
+
await loadUserFilesClientSide(pageContextLink.pageId, pageContextLink._pageFilesAll, pageContextLink._pageConfigs);
|
|
19
41
|
}
|
|
20
42
|
catch (err) {
|
|
21
43
|
if (isErrorFetchingStaticAssets(err)) {
|
|
@@ -26,6 +48,15 @@ async function prefetchAssets(pageId, pageContext) {
|
|
|
26
48
|
}
|
|
27
49
|
}
|
|
28
50
|
}
|
|
51
|
+
async function prefetchPageContextFromServerHooks(pageContextLink, resultMaxAge) {
|
|
52
|
+
const result = await getPageContextFromServerHooks(pageContextLink, false);
|
|
53
|
+
const urlOfLink = pageContextLink.urlOriginal;
|
|
54
|
+
globalObject.prefetchedPageContexts[urlOfLink] = {
|
|
55
|
+
resultFetchedAt: Date.now(),
|
|
56
|
+
resultMaxAge,
|
|
57
|
+
result
|
|
58
|
+
};
|
|
59
|
+
}
|
|
29
60
|
/**
|
|
30
61
|
* Programmatically prefetch client assets.
|
|
31
62
|
*
|
|
@@ -33,85 +64,157 @@ async function prefetchAssets(pageId, pageContext) {
|
|
|
33
64
|
*
|
|
34
65
|
* @param url - The URL of the page you want to prefetch.
|
|
35
66
|
*/
|
|
36
|
-
async function prefetch(url) {
|
|
67
|
+
async function prefetch(url, options) {
|
|
37
68
|
assertUsage(checkIfClientRouting(), 'prefetch() only works with Client Routing, see https://vike.dev/prefetch', {
|
|
38
69
|
showStackTrace: true
|
|
39
70
|
});
|
|
40
71
|
const errPrefix = '[prefetch(url)] url';
|
|
41
72
|
assertUsageUrlPathname(url, errPrefix);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
markAsAlreadyPrefetched(url);
|
|
45
|
-
const pageContext = await createPageContext(url);
|
|
46
|
-
let pageContextFromRoute;
|
|
47
|
-
try {
|
|
48
|
-
pageContextFromRoute = await route(pageContext);
|
|
49
|
-
}
|
|
50
|
-
catch {
|
|
51
|
-
// If a route() hook has a bug or `throw render()` / `throw redirect()`
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const pageId = pageContextFromRoute._pageId;
|
|
55
|
-
if (!pageId) {
|
|
73
|
+
const pageContextLink = await getPageContextLink(url);
|
|
74
|
+
if (!pageContextLink?.pageId) {
|
|
56
75
|
assertWarning(false, `${errPrefix} ${pc.string(url)} ${noRouteMatch}`, {
|
|
57
76
|
showStackTrace: true,
|
|
58
77
|
onlyOnce: false
|
|
59
78
|
});
|
|
60
79
|
return;
|
|
61
80
|
}
|
|
62
|
-
|
|
81
|
+
assert(hasProp(pageContextLink, 'pageId', 'string')); // help TypeScript
|
|
82
|
+
await Promise.all([
|
|
83
|
+
(async () => {
|
|
84
|
+
if (options?.staticAssets !== false) {
|
|
85
|
+
await prefetchAssets(pageContextLink);
|
|
86
|
+
}
|
|
87
|
+
})(),
|
|
88
|
+
(async () => {
|
|
89
|
+
if (options?.pageContext !== false) {
|
|
90
|
+
const resultMaxAge = getResultMaxAge();
|
|
91
|
+
await prefetchPageContextFromServerHooks(pageContextLink, resultMaxAge);
|
|
92
|
+
}
|
|
93
|
+
})()
|
|
94
|
+
]);
|
|
95
|
+
return;
|
|
96
|
+
function getResultMaxAge() {
|
|
97
|
+
if (typeof options?.pageContext === 'number') {
|
|
98
|
+
return options.pageContext;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
// If user calls prefetch() before hydration finished => await the pageContext to be set
|
|
102
|
+
const pageContextCurrent = getPageContextCurrent();
|
|
103
|
+
// TODO/pageContext-prefetch: remove this dirty hack for @brillout/docpress and, instead, use Vike's default if pageContextCurrent isn't defined yet.
|
|
104
|
+
if (!pageContextCurrent)
|
|
105
|
+
return Infinity;
|
|
106
|
+
const prefetchSettings = getPrefetchSettings(pageContextCurrent, null);
|
|
107
|
+
const resultMaxAge = typeof prefetchSettings.pageContext === 'number' ? prefetchSettings.pageContext : PAGE_CONTEXT_MAX_AGE_DEFAULT;
|
|
108
|
+
return resultMaxAge;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Lazy execution logic copied from: https://github.com/withastro/astro/blob/2594eb088d53a98181ac820243bcb1a765856ecf/packages/astro/src/runtime/client/dev-toolbar/apps/audit/index.ts#L53-L72
|
|
113
|
+
function addLinkPrefetchHandlers() {
|
|
114
|
+
if (globalObject.addLinkPrefetchHandlers_debounce)
|
|
115
|
+
clearTimeout(globalObject.addLinkPrefetchHandlers_debounce);
|
|
116
|
+
globalObject.addLinkPrefetchHandlers_debounce = setTimeout(() => {
|
|
117
|
+
// Wait for the next idle period, as it is less likely to interfere with any other work the browser is doing post-mutation.
|
|
118
|
+
if ('requestIdleCallback' in window) {
|
|
119
|
+
requestIdleCallback(addLinkPrefetchHandlers_apply, { timeout: 300 });
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
// Fallback for old versions of Safari, we'll assume that things are less likely to be busy after 150ms.
|
|
123
|
+
setTimeout(addLinkPrefetchHandlers_apply, 150);
|
|
124
|
+
}
|
|
125
|
+
}, 250);
|
|
126
|
+
}
|
|
127
|
+
function initLinkPrefetchHandlers() {
|
|
128
|
+
addLinkPrefetchHandlers();
|
|
129
|
+
}
|
|
130
|
+
function addLinkPrefetchHandlers_watch() {
|
|
131
|
+
// Notes about performance:
|
|
132
|
+
// - https://stackoverflow.com/questions/31659567/performance-of-mutationobserver-to-detect-nodes-in-entire-dom/39332340#39332340
|
|
133
|
+
// - https://news.ycombinator.com/item?id=15274211
|
|
134
|
+
// - https://github.com/kubetail-org/sentineljs
|
|
135
|
+
// - https://stackoverflow.com/questions/55046093/listening-for-changes-in-htmlcollection-or-achieving-a-similar-effect
|
|
136
|
+
globalObject.mutationObserver.observe(document.body, {
|
|
137
|
+
childList: true,
|
|
138
|
+
subtree: true
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function addLinkPrefetchHandlers_unwatch() {
|
|
142
|
+
globalObject.mutationObserver.disconnect();
|
|
63
143
|
}
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
markAsAlreadyPrefetched(pageContext.urlPathname);
|
|
67
|
-
const linkTags = [...document.getElementsByTagName('A')];
|
|
68
|
-
linkTags.forEach((linkTag) => {
|
|
144
|
+
function addLinkPrefetchHandlers_apply() {
|
|
145
|
+
for (let linkTag of globalObject.linkTags) {
|
|
69
146
|
if (globalObject.linkPrefetchHandlerAdded.has(linkTag))
|
|
70
|
-
|
|
71
|
-
globalObject.linkPrefetchHandlerAdded.
|
|
72
|
-
const url = linkTag.getAttribute('href');
|
|
147
|
+
continue;
|
|
148
|
+
globalObject.linkPrefetchHandlerAdded.add(linkTag);
|
|
73
149
|
if (skipLink(linkTag))
|
|
74
150
|
return;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
151
|
+
linkTag.addEventListener('mouseover', () => {
|
|
152
|
+
prefetchOnEvent(linkTag, 'hover');
|
|
153
|
+
}, { passive: true });
|
|
154
|
+
linkTag.addEventListener('touchstart', () => {
|
|
155
|
+
prefetchOnEvent(linkTag, 'hover');
|
|
156
|
+
}, { passive: true });
|
|
157
|
+
const observer = new IntersectionObserver((entries) => {
|
|
158
|
+
entries.forEach((entry) => {
|
|
159
|
+
if (entry.isIntersecting) {
|
|
160
|
+
prefetchOnEvent(linkTag, 'viewport');
|
|
161
|
+
observer.disconnect();
|
|
162
|
+
}
|
|
84
163
|
});
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
164
|
+
});
|
|
165
|
+
observer.observe(linkTag);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async function prefetchOnEvent(linkTag, event) {
|
|
169
|
+
let prefetchSettings;
|
|
170
|
+
const pageContextCurrent = getPageContextCurrent();
|
|
171
|
+
if (pageContextCurrent) {
|
|
172
|
+
prefetchSettings = getPrefetchSettings(pageContextCurrent, linkTag);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
// TODO/pageContext-prefetch: remove this dirty hack for @brillout/docpress and, instead, use Vike's default if pageContextCurrent isn't defined yet.
|
|
176
|
+
prefetchSettings = { staticAssets: 'hover', pageContext: Infinity };
|
|
177
|
+
}
|
|
178
|
+
const urlOfLink = linkTag.getAttribute('href');
|
|
179
|
+
assert(urlOfLink);
|
|
180
|
+
const pageContextLink = await getPageContextLink(urlOfLink);
|
|
181
|
+
if (!pageContextLink?.pageId)
|
|
182
|
+
return;
|
|
183
|
+
assert(hasProp(pageContextLink, 'pageId', 'string')); // help TypeScript
|
|
184
|
+
if (!(await isClientSideRoutable(pageContextLink.pageId, pageContextLink)))
|
|
185
|
+
return;
|
|
186
|
+
await Promise.all([
|
|
187
|
+
(async () => {
|
|
188
|
+
if (prefetchSettings.staticAssets === event) {
|
|
189
|
+
await prefetchAssets(pageContextLink);
|
|
190
|
+
}
|
|
191
|
+
})(),
|
|
192
|
+
(async () => {
|
|
193
|
+
if (event !== 'viewport' && prefetchSettings.pageContext) {
|
|
194
|
+
const found = globalObject.prefetchedPageContexts[urlOfLink];
|
|
195
|
+
if (!found || isExpired(found)) {
|
|
196
|
+
// TODO/pageContext-prefetch: move this logic in getPrefetchSettings()
|
|
197
|
+
const resultMaxAge = prefetchSettings.pageContext;
|
|
198
|
+
await prefetchPageContextFromServerHooks(pageContextLink, resultMaxAge);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
})()
|
|
202
|
+
]);
|
|
203
|
+
}
|
|
204
|
+
function isExpired(found) {
|
|
205
|
+
return Date.now() - found.resultFetchedAt > found.resultMaxAge;
|
|
101
206
|
}
|
|
102
|
-
|
|
103
|
-
|
|
207
|
+
// TODO/next-major-release: make it sync
|
|
208
|
+
async function getPageContextLink(urlOfLink) {
|
|
209
|
+
const pageContextLink = await createPageContext(urlOfLink);
|
|
104
210
|
let pageContextFromRoute;
|
|
105
211
|
try {
|
|
106
|
-
pageContextFromRoute = await route(
|
|
212
|
+
pageContextFromRoute = await route(pageContextLink);
|
|
107
213
|
}
|
|
108
214
|
catch {
|
|
109
215
|
// If a route() hook has a bug or `throw render()` / `throw redirect()`
|
|
110
|
-
return;
|
|
216
|
+
return null;
|
|
111
217
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!(await isClientSideRoutable(pageContextFromRoute._pageId, pageContext)))
|
|
115
|
-
return;
|
|
116
|
-
await prefetchAssets(pageContextFromRoute._pageId, pageContext);
|
|
218
|
+
objectAssign(pageContextLink, pageContextFromRoute);
|
|
219
|
+
return pageContextLink;
|
|
117
220
|
}
|
|
@@ -2,10 +2,10 @@ export { renderPageClientSide };
|
|
|
2
2
|
export { getRenderCount };
|
|
3
3
|
export { disableClientRouting };
|
|
4
4
|
export { firstRenderStartPromise };
|
|
5
|
-
import { assert, getCurrentUrl, isSameErrorMessage, objectAssign, redirectHard, getGlobalObject, executeHook, hasProp, augmentType, genPromise } from './utils.js';
|
|
6
|
-
import {
|
|
5
|
+
import { assert, getCurrentUrl, isSameErrorMessage, objectAssign, redirectHard, getGlobalObject, executeHook, hasProp, augmentType, genPromise, isCallable } from './utils.js';
|
|
6
|
+
import { getPageContextFromClientHooks, getPageContextFromServerHooks, getPageContextFromHooks_isHydration, getPageContextFromHooks_serialized, setPageContextInitIsPassedToClient } from './getPageContextFromHooks.js';
|
|
7
7
|
import { createPageContext } from './createPageContext.js';
|
|
8
|
-
import { addLinkPrefetchHandlers } from './prefetch.js';
|
|
8
|
+
import { addLinkPrefetchHandlers, addLinkPrefetchHandlers_unwatch, addLinkPrefetchHandlers_watch, getPageContextPrefetched } from './prefetch.js';
|
|
9
9
|
import { assertInfo, assertWarning, isReact } from './utils.js';
|
|
10
10
|
import { executeOnRenderClientHook } from '../shared/executeOnRenderClientHook.js';
|
|
11
11
|
import { assertHook, getHook } from '../../shared/hooks/getHook.js';
|
|
@@ -18,6 +18,8 @@ import { setScrollPosition } from './setScrollPosition.js';
|
|
|
18
18
|
import { updateState } from './onBrowserHistoryNavigation.js';
|
|
19
19
|
import { browserNativeScrollRestoration_disable, setInitialRenderIsDone } from './scrollRestoration.js';
|
|
20
20
|
import { getErrorPageId } from '../../shared/error-page.js';
|
|
21
|
+
import { setPageContextCurrent } from './getPageContextCurrent.js';
|
|
22
|
+
import { getRouteStringParameterList } from '../../shared/route/resolveRouteString.js';
|
|
21
23
|
const globalObject = getGlobalObject('renderPageClientSide.ts', (() => {
|
|
22
24
|
const { promise: firstRenderStartPromise, resolve: firstRenderStartPromiseResolve } = genPromise();
|
|
23
25
|
return {
|
|
@@ -28,8 +30,10 @@ const globalObject = getGlobalObject('renderPageClientSide.ts', (() => {
|
|
|
28
30
|
})());
|
|
29
31
|
const { firstRenderStartPromise } = globalObject;
|
|
30
32
|
async function renderPageClientSide(renderArgs) {
|
|
31
|
-
const {
|
|
33
|
+
const { urlOriginal = getCurrentUrl(), overwriteLastHistoryEntry = false, isBackwardNavigation, pageContextsFromRewrite = [], redirectCount = 0, isUserLandPushStateNavigation, isClientSideNavigation = true } = renderArgs;
|
|
34
|
+
let { scrollTarget } = renderArgs;
|
|
32
35
|
const { previousPageContext } = globalObject;
|
|
36
|
+
addLinkPrefetchHandlers_unwatch();
|
|
33
37
|
const { isRenderOutdated, setHydrationCanBeAborted, isFirstRender } = getIsRenderOutdated();
|
|
34
38
|
// Note that pageContext.isHydration isn't equivalent to isFirstRender
|
|
35
39
|
// - Thus pageContext.isHydration isn't equivalent to !pageContext.isClientSideNavigation
|
|
@@ -93,7 +97,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
93
97
|
}
|
|
94
98
|
if (isRenderOutdated())
|
|
95
99
|
return;
|
|
96
|
-
if (!pageContextFromRoute.
|
|
100
|
+
if (!pageContextFromRoute.pageId) {
|
|
97
101
|
/*
|
|
98
102
|
// We don't use the client router to render the 404 page:
|
|
99
103
|
// - So that the +redirects setting (https://vike.dev/redirects) can be applied.
|
|
@@ -106,17 +110,17 @@ async function renderPageClientSide(renderArgs) {
|
|
|
106
110
|
redirectHard(urlOriginal);
|
|
107
111
|
return;
|
|
108
112
|
}
|
|
109
|
-
assert(hasProp(pageContextFromRoute, '
|
|
110
|
-
const isClientRoutable = await isClientSideRoutable(pageContextFromRoute.
|
|
113
|
+
assert(hasProp(pageContextFromRoute, 'pageId', 'string')); // Help TS
|
|
114
|
+
const isClientRoutable = await isClientSideRoutable(pageContextFromRoute.pageId, pageContext);
|
|
111
115
|
if (isRenderOutdated())
|
|
112
116
|
return;
|
|
113
117
|
if (!isClientRoutable) {
|
|
114
118
|
redirectHard(urlOriginal);
|
|
115
119
|
return;
|
|
116
120
|
}
|
|
117
|
-
const isSamePage = pageContextFromRoute.
|
|
118
|
-
previousPageContext?.
|
|
119
|
-
pageContextFromRoute.
|
|
121
|
+
const isSamePage = pageContextFromRoute.pageId &&
|
|
122
|
+
previousPageContext?.pageId &&
|
|
123
|
+
pageContextFromRoute.pageId === previousPageContext.pageId;
|
|
120
124
|
if (isUserLandPushStateNavigation && isSamePage) {
|
|
121
125
|
// Skip's Vike's rendering; let the user handle the navigation
|
|
122
126
|
return;
|
|
@@ -126,7 +130,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
126
130
|
assert(!('urlOriginal' in pageContextRouted));
|
|
127
131
|
objectAssign(pageContext, pageContextRouted);
|
|
128
132
|
try {
|
|
129
|
-
objectAssign(pageContext, await loadUserFilesClientSide(pageContext.
|
|
133
|
+
objectAssign(pageContext, await loadUserFilesClientSide(pageContext.pageId, pageContext._pageFilesAll, pageContext._pageConfigs));
|
|
130
134
|
}
|
|
131
135
|
catch (err) {
|
|
132
136
|
if (handleErrorFetchingStaticAssets(err, pageContext, isFirstRender)) {
|
|
@@ -147,7 +151,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
147
151
|
else {
|
|
148
152
|
assertWarning(!isReact(), 'You seem to be using React; we recommend setting hydrationCanBeAborted to true, see https://vike.dev/hydrationCanBeAborted', { onlyOnce: true });
|
|
149
153
|
}
|
|
150
|
-
// There wasn't any `await` but
|
|
154
|
+
// There wasn't any `await` but the isRenderOutdated() return value may have changed because we called setHydrationCanBeAborted()
|
|
151
155
|
if (isRenderOutdated())
|
|
152
156
|
return;
|
|
153
157
|
// Get pageContext from hooks (fetched from server, and/or directly called on the client-side)
|
|
@@ -168,9 +172,33 @@ async function renderPageClientSide(renderArgs) {
|
|
|
168
172
|
await renderPageView(pageContext);
|
|
169
173
|
}
|
|
170
174
|
else {
|
|
171
|
-
|
|
175
|
+
// Fetch pageContext from server-side hooks
|
|
176
|
+
let pageContextFromServerHooks;
|
|
177
|
+
const pageContextPrefetched = getPageContextPrefetched(pageContext);
|
|
178
|
+
if (pageContextPrefetched) {
|
|
179
|
+
pageContextFromServerHooks = pageContextPrefetched;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
try {
|
|
183
|
+
const result = await getPageContextFromServerHooks(pageContext, false);
|
|
184
|
+
if (result.is404ServerSideRouted)
|
|
185
|
+
return;
|
|
186
|
+
pageContextFromServerHooks = result.pageContextFromServerHooks;
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
await onError(err);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (isRenderOutdated())
|
|
194
|
+
return;
|
|
195
|
+
// TODO/eventually: create helper assertPageContextFromHook()
|
|
196
|
+
assert(!('urlOriginal' in pageContextFromServerHooks));
|
|
197
|
+
objectAssign(pageContext, pageContextFromServerHooks);
|
|
198
|
+
// Get pageContext from client-side hooks
|
|
199
|
+
let pageContextFromClientHooks;
|
|
172
200
|
try {
|
|
173
|
-
|
|
201
|
+
pageContextFromClientHooks = await getPageContextFromClientHooks(pageContext, false);
|
|
174
202
|
}
|
|
175
203
|
catch (err) {
|
|
176
204
|
await onError(err);
|
|
@@ -178,10 +206,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
178
206
|
}
|
|
179
207
|
if (isRenderOutdated())
|
|
180
208
|
return;
|
|
181
|
-
|
|
182
|
-
return;
|
|
183
|
-
augmentType(pageContext, res.pageContextAugmented);
|
|
184
|
-
// Render page view
|
|
209
|
+
augmentType(pageContext, pageContextFromClientHooks);
|
|
185
210
|
await renderPageView(pageContext);
|
|
186
211
|
}
|
|
187
212
|
}
|
|
@@ -284,9 +309,9 @@ async function renderPageClientSide(renderArgs) {
|
|
|
284
309
|
if (!errorPageId)
|
|
285
310
|
throw new Error('No error page defined.');
|
|
286
311
|
objectAssign(pageContext, {
|
|
287
|
-
|
|
312
|
+
pageId: errorPageId
|
|
288
313
|
});
|
|
289
|
-
const isClientRoutable = await isClientSideRoutable(pageContext.
|
|
314
|
+
const isClientRoutable = await isClientSideRoutable(pageContext.pageId, pageContext);
|
|
290
315
|
if (isRenderOutdated())
|
|
291
316
|
return;
|
|
292
317
|
if (!isClientRoutable) {
|
|
@@ -294,7 +319,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
294
319
|
return;
|
|
295
320
|
}
|
|
296
321
|
try {
|
|
297
|
-
objectAssign(pageContext, await loadUserFilesClientSide(pageContext.
|
|
322
|
+
objectAssign(pageContext, await loadUserFilesClientSide(pageContext.pageId, pageContext._pageFilesAll, pageContext._pageConfigs));
|
|
298
323
|
}
|
|
299
324
|
catch (err) {
|
|
300
325
|
if (handleErrorFetchingStaticAssets(err, pageContext, isFirstRender)) {
|
|
@@ -308,21 +333,34 @@ async function renderPageClientSide(renderArgs) {
|
|
|
308
333
|
}
|
|
309
334
|
if (isRenderOutdated())
|
|
310
335
|
return;
|
|
311
|
-
let
|
|
336
|
+
let pageContextFromServerHooks;
|
|
312
337
|
try {
|
|
313
|
-
|
|
338
|
+
const result = await getPageContextFromServerHooks(pageContext, true);
|
|
339
|
+
if (result.is404ServerSideRouted)
|
|
340
|
+
return;
|
|
341
|
+
pageContextFromServerHooks = result.pageContextFromServerHooks;
|
|
314
342
|
}
|
|
315
343
|
catch (err) {
|
|
316
|
-
// - When user hasn't defined a `_error.page.js` file
|
|
317
|
-
// - Some Vike unpexected internal error
|
|
318
344
|
onError(err);
|
|
319
345
|
return;
|
|
320
346
|
}
|
|
321
347
|
if (isRenderOutdated())
|
|
322
348
|
return;
|
|
323
|
-
|
|
349
|
+
// TODO/eventually: create helper assertPageContextFromHook()
|
|
350
|
+
assert(!('urlOriginal' in pageContextFromServerHooks));
|
|
351
|
+
objectAssign(pageContext, pageContextFromServerHooks);
|
|
352
|
+
let pageContextFromClientHooks;
|
|
353
|
+
try {
|
|
354
|
+
pageContextFromClientHooks = await getPageContextFromClientHooks(pageContext, true);
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
onError(err);
|
|
324
358
|
return;
|
|
325
|
-
|
|
359
|
+
}
|
|
360
|
+
if (isRenderOutdated())
|
|
361
|
+
return;
|
|
362
|
+
augmentType(pageContext, pageContextFromClientHooks);
|
|
363
|
+
objectAssign(pageContext, { routeParams: {} });
|
|
326
364
|
await renderPageView(pageContext, args);
|
|
327
365
|
}
|
|
328
366
|
async function renderPageView(pageContext, isErrorPage) {
|
|
@@ -369,7 +407,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
369
407
|
/* We don't abort in order to ensure that onHydrationEnd() is called: we abort only after onHydrationEnd() is called.
|
|
370
408
|
if (isRenderOutdated(true)) return
|
|
371
409
|
*/
|
|
372
|
-
|
|
410
|
+
setPageContextCurrent(pageContext);
|
|
373
411
|
// onHydrationEnd()
|
|
374
412
|
if (isFirstRender && !onRenderClientError) {
|
|
375
413
|
assertHook(pageContext, 'onHydrationEnd');
|
|
@@ -411,10 +449,24 @@ async function renderPageClientSide(renderArgs) {
|
|
|
411
449
|
return;
|
|
412
450
|
}
|
|
413
451
|
}
|
|
452
|
+
if (!scrollTarget && previousPageContext) {
|
|
453
|
+
const keepScrollPositionPrev = getKeepScrollPositionSetting(previousPageContext);
|
|
454
|
+
const keepScrollPositionNext = getKeepScrollPositionSetting(pageContext);
|
|
455
|
+
if (keepScrollPositionNext !== false &&
|
|
456
|
+
keepScrollPositionPrev !== false &&
|
|
457
|
+
areKeysEqual(keepScrollPositionNext, keepScrollPositionPrev)) {
|
|
458
|
+
scrollTarget = { preserveScroll: true };
|
|
459
|
+
}
|
|
460
|
+
}
|
|
414
461
|
// Page scrolling
|
|
415
462
|
setScrollPosition(scrollTarget);
|
|
416
463
|
browserNativeScrollRestoration_disable();
|
|
417
464
|
setInitialRenderIsDone();
|
|
465
|
+
if (pageContext._hasPageContextFromServer)
|
|
466
|
+
setPageContextInitIsPassedToClient(pageContext);
|
|
467
|
+
// Add link prefetch handlers
|
|
468
|
+
addLinkPrefetchHandlers_watch();
|
|
469
|
+
addLinkPrefetchHandlers();
|
|
418
470
|
}
|
|
419
471
|
}
|
|
420
472
|
function changeUrl(url, overwriteLastHistoryEntry) {
|
|
@@ -486,3 +538,38 @@ function getIsRenderOutdated() {
|
|
|
486
538
|
function getRenderCount() {
|
|
487
539
|
return globalObject.renderCounter;
|
|
488
540
|
}
|
|
541
|
+
function getKeepScrollPositionSetting(pageContext) {
|
|
542
|
+
const c = pageContext.from.configsStandard.keepScrollPosition;
|
|
543
|
+
if (!c)
|
|
544
|
+
return false;
|
|
545
|
+
let val = c.value;
|
|
546
|
+
const configDefinedAt = c.definedAt;
|
|
547
|
+
assert(configDefinedAt);
|
|
548
|
+
const routeParameterList = getRouteStringParameterList(configDefinedAt);
|
|
549
|
+
if (isCallable(val))
|
|
550
|
+
val = val(pageContext, {
|
|
551
|
+
configDefinedAt: c.definedAt
|
|
552
|
+
/* We don't pass routeParameterList because it's useless: the user knows the parameter list.
|
|
553
|
+
routeParameterList
|
|
554
|
+
*/
|
|
555
|
+
});
|
|
556
|
+
if (val === true) {
|
|
557
|
+
return [
|
|
558
|
+
configDefinedAt,
|
|
559
|
+
...routeParameterList.map((param) => {
|
|
560
|
+
const val = pageContext.routeParams[param];
|
|
561
|
+
assert(val);
|
|
562
|
+
return val;
|
|
563
|
+
})
|
|
564
|
+
];
|
|
565
|
+
}
|
|
566
|
+
// We skip validation and type-cast instead of assertUsage() in order to save client-side KBs
|
|
567
|
+
return val;
|
|
568
|
+
}
|
|
569
|
+
function areKeysEqual(key1, key2) {
|
|
570
|
+
if (key1 === key2)
|
|
571
|
+
return true;
|
|
572
|
+
if (!Array.isArray(key1) || !Array.isArray(key2))
|
|
573
|
+
return false;
|
|
574
|
+
return key1.length === key2.length && key1.every((_, i) => key1[i] === key2[i]);
|
|
575
|
+
}
|
|
@@ -12,7 +12,7 @@ async function getPageContext() {
|
|
|
12
12
|
_hasPageContextFromServer: true,
|
|
13
13
|
_hasPageContextFromClient: false
|
|
14
14
|
});
|
|
15
|
-
objectAssign(pageContext, await loadPageUserFiles(pageContext.
|
|
15
|
+
objectAssign(pageContext, await loadPageUserFiles(pageContext.pageId));
|
|
16
16
|
assertPristineUrl();
|
|
17
17
|
return pageContext;
|
|
18
18
|
}
|
|
@@ -7,7 +7,7 @@ type PageContextBeforeRenderClient = {
|
|
|
7
7
|
_pageFilesLoaded: PageFile[];
|
|
8
8
|
urlOriginal?: string;
|
|
9
9
|
urlPathname?: string;
|
|
10
|
-
|
|
10
|
+
pageId: string;
|
|
11
11
|
_pageConfigs: PageConfigRuntime[];
|
|
12
12
|
} & PageContextExports & PageContextForUserConsumptionClientSide;
|
|
13
13
|
declare function executeOnRenderClientHook<PC extends PageContextBeforeRenderClient>(pageContext: PC, isClientRouting: boolean): Promise<void>;
|
|
@@ -14,7 +14,7 @@ function getPageContextSerializedInHtml() {
|
|
|
14
14
|
const pageContextJson = elem.textContent;
|
|
15
15
|
assert(pageContextJson);
|
|
16
16
|
const pageContextSerializedInHtml = parse(pageContextJson);
|
|
17
|
-
assert(hasProp(pageContextSerializedInHtml, '
|
|
17
|
+
assert(hasProp(pageContextSerializedInHtml, 'pageId', 'string'));
|
|
18
18
|
assert(hasProp(pageContextSerializedInHtml, 'routeParams', 'string{}'));
|
|
19
19
|
return pageContextSerializedInHtml;
|
|
20
20
|
}
|
|
@@ -4,7 +4,7 @@ import type { PageContextExports } from '../../shared/getPageFiles.js';
|
|
|
4
4
|
import type { PageConfigRuntime } from '../../shared/page-configs/PageConfig.js';
|
|
5
5
|
import { PageContextForPassToClientWarning } from './getPageContextProxyForUser.js';
|
|
6
6
|
type PageContextForUserConsumptionClientSide = PageContextExports & PageContextForPassToClientWarning & {
|
|
7
|
-
|
|
7
|
+
pageId: string;
|
|
8
8
|
_pageConfigs: PageConfigRuntime[];
|
|
9
9
|
};
|
|
10
10
|
declare function preparePageContextForUserConsumptionClientSide<T extends PageContextForUserConsumptionClientSide>(pageContext: T, isClientRouting: boolean): T & {
|