vike 0.4.152 → 0.4.153-commit-01ab602
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/node/cli/bin.js +2 -2
- package/dist/cjs/node/plugin/index.js +2 -2
- package/dist/cjs/node/plugin/plugins/autoFullBuild.js +2 -2
- package/dist/cjs/node/plugin/plugins/envVars.js +1 -1
- package/dist/cjs/node/plugin/plugins/{assertFileEnv.js → fileEnv.js} +4 -4
- package/dist/cjs/node/plugin/plugins/importBuild/index.js +1 -1
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +1 -9
- package/dist/cjs/node/prerender/index.js +1 -1
- package/dist/cjs/node/prerender/runPrerender.js +21 -13
- package/dist/cjs/node/runtime/html/serializePageContextClientSide.js +5 -3
- package/dist/cjs/node/runtime/html/stream.js +2 -1
- package/dist/cjs/node/runtime/renderPage/getPageAssets/retrieveAssetsDev.js +2 -1
- package/dist/cjs/node/runtime/renderPage/isNewError.js +1 -1
- package/dist/cjs/node/runtime/renderPage/{loadPageFilesServerSide.js → loadUserFilesServerSide.js} +5 -5
- package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +5 -4
- package/dist/cjs/node/runtime/renderPage.js +2 -2
- package/dist/cjs/node/runtime/utils.js +1 -2
- package/dist/cjs/shared/hooks/getHook.js +14 -8
- package/dist/cjs/shared/misc/isRenderFailure.js +4 -0
- package/dist/cjs/shared/misc/pageContextInitIsPassedToClient.js +4 -0
- package/dist/cjs/shared/route/abort.js +15 -4
- package/dist/cjs/shared/route/loadPageRoutes.js +1 -9
- package/dist/cjs/utils/isSameErrorMessage.js +10 -0
- package/dist/cjs/utils/projectInfo.js +1 -1
- package/dist/esm/client/client-routing-runtime/createPageContext.d.ts +0 -1
- package/dist/esm/client/client-routing-runtime/createPageContext.js +0 -3
- package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.d.ts +28 -33
- package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +42 -58
- package/dist/esm/client/client-routing-runtime/installClientRouter.d.ts +1 -1
- package/dist/esm/client/client-routing-runtime/installClientRouter.js +8 -2
- package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.js +2 -2
- package/dist/esm/client/client-routing-runtime/onLinkClick.js +2 -2
- package/dist/esm/client/client-routing-runtime/prefetch/getPrefetchSettings.d.ts +1 -3
- package/dist/esm/client/client-routing-runtime/prefetch/getPrefetchSettings.js +1 -1
- package/dist/esm/client/client-routing-runtime/prefetch.d.ts +0 -1
- package/dist/esm/client/client-routing-runtime/prefetch.js +2 -2
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.d.ts +1 -1
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +298 -204
- package/dist/esm/client/client-routing-runtime/utils.d.ts +1 -1
- package/dist/esm/client/client-routing-runtime/utils.js +1 -1
- package/dist/esm/client/server-routing-runtime/getPageContext.d.ts +2 -2
- package/dist/esm/client/server-routing-runtime/getPageContext.js +5 -4
- package/dist/esm/client/shared/executeOnRenderClientHook.d.ts +4 -2
- package/dist/esm/client/shared/getPageContextSerializedInHtml.d.ts +0 -1
- package/dist/esm/client/shared/getPageContextSerializedInHtml.js +1 -4
- package/dist/esm/client/shared/{loadPageFilesClientSide.d.ts → loadUserFilesClientSide.d.ts} +7 -6
- package/dist/esm/client/shared/{loadPageFilesClientSide.js → loadUserFilesClientSide.js} +4 -4
- package/dist/esm/node/cli/bin.js +3 -3
- package/dist/esm/node/plugin/index.js +2 -2
- package/dist/esm/node/plugin/plugins/autoFullBuild.js +3 -3
- package/dist/esm/node/plugin/plugins/envVars.js +1 -1
- package/dist/esm/node/plugin/plugins/fileEnv.d.ts +3 -0
- package/dist/esm/node/plugin/plugins/{assertFileEnv.js → fileEnv.js} +3 -3
- package/dist/esm/node/plugin/plugins/importBuild/index.js +1 -1
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +1 -9
- package/dist/esm/node/prerender/index.d.ts +1 -1
- package/dist/esm/node/prerender/index.js +1 -1
- package/dist/esm/node/prerender/runPrerender.d.ts +8 -8
- package/dist/esm/node/prerender/runPrerender.js +22 -14
- package/dist/esm/node/runtime/html/serializePageContextClientSide.d.ts +0 -1
- package/dist/esm/node/runtime/html/serializePageContextClientSide.js +5 -3
- package/dist/esm/node/runtime/html/stream.js +3 -2
- package/dist/esm/node/runtime/renderPage/getPageAssets/retrieveAssetsDev.js +2 -1
- package/dist/esm/node/runtime/renderPage/isNewError.js +2 -2
- package/dist/esm/node/runtime/renderPage/{loadPageFilesServerSide.d.ts → loadUserFilesServerSide.d.ts} +6 -6
- package/dist/esm/node/runtime/renderPage/{loadPageFilesServerSide.js → loadUserFilesServerSide.js} +4 -4
- package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +2 -2
- package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +5 -4
- package/dist/esm/node/runtime/renderPage.js +2 -2
- package/dist/esm/node/runtime/utils.d.ts +1 -2
- package/dist/esm/node/runtime/utils.js +1 -2
- package/dist/esm/shared/hooks/getHook.d.ts +2 -0
- package/dist/esm/shared/hooks/getHook.js +13 -7
- package/dist/esm/shared/misc/isRenderFailure.d.ts +1 -0
- package/dist/esm/shared/misc/isRenderFailure.js +1 -0
- package/dist/esm/shared/misc/pageContextInitIsPassedToClient.d.ts +1 -0
- package/dist/esm/shared/misc/pageContextInitIsPassedToClient.js +1 -0
- package/dist/esm/shared/page-configs/Config.d.ts +1 -1
- package/dist/esm/shared/route/abort.d.ts +1 -1
- package/dist/esm/shared/route/abort.js +16 -5
- package/dist/esm/shared/route/loadPageRoutes.js +1 -9
- package/dist/esm/utils/isSameErrorMessage.d.ts +2 -0
- package/dist/esm/utils/isSameErrorMessage.js +7 -0
- package/dist/esm/utils/projectInfo.d.ts +2 -2
- package/dist/esm/utils/projectInfo.js +1 -1
- package/package.json +2 -2
- package/dist/cjs/utils/dynamicImport.js +0 -8
- package/dist/cjs/utils/isEquivalentError.js +0 -18
- package/dist/esm/node/plugin/plugins/assertFileEnv.d.ts +0 -3
- package/dist/esm/utils/dynamicImport.d.ts +0 -2
- package/dist/esm/utils/dynamicImport.js +0 -4
- package/dist/esm/utils/isEquivalentError.d.ts +0 -2
- package/dist/esm/utils/isEquivalentError.js +0 -15
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export { renderPageClientSide };
|
|
2
2
|
export { getRenderCount };
|
|
3
3
|
export { disableClientRouting };
|
|
4
|
-
import { assert, getCurrentUrl,
|
|
5
|
-
import {
|
|
4
|
+
import { assert, getCurrentUrl, isSameErrorMessage, objectAssign, serverSideRouteTo, getGlobalObject, executeHook, hasProp } from './utils.js';
|
|
5
|
+
import { getPageContextFromHooks_isHydration, getPageContextFromHooks_isNotHydration, getPageContextFromHooks_serialized, isServerSideRouted } from './getPageContextFromHooks.js';
|
|
6
6
|
import { createPageContext } from './createPageContext.js';
|
|
7
7
|
import { addLinkPrefetchHandlers } from './prefetch.js';
|
|
8
8
|
import { assertInfo, assertWarning, isReact } from './utils.js';
|
|
9
9
|
import { executeOnRenderClientHook } from '../shared/executeOnRenderClientHook.js';
|
|
10
10
|
import { assertHook, getHook } from '../../shared/hooks/getHook.js';
|
|
11
|
-
import { isErrorFetchingStaticAssets } from '../shared/
|
|
11
|
+
import { isErrorFetchingStaticAssets, loadUserFilesClientSide } from '../shared/loadUserFilesClientSide.js';
|
|
12
12
|
import { pushHistory } from './history.js';
|
|
13
13
|
import { assertNoInfiniteAbortLoop, getPageContextFromAllRewrites, isAbortError, logAbortErrorHandled } from '../../shared/route/abort.js';
|
|
14
14
|
import { route } from '../../shared/route/index.js';
|
|
@@ -16,62 +16,56 @@ import { isClientSideRoutable } from './isClientSideRoutable.js';
|
|
|
16
16
|
import { setScrollPosition } from './setScrollPosition.js';
|
|
17
17
|
import { updateState } from './onBrowserHistoryNavigation.js';
|
|
18
18
|
import { browserNativeScrollRestoration_disable, setInitialRenderIsDone } from './scrollRestoration.js';
|
|
19
|
+
import { getErrorPageId } from '../../shared/error-page.js';
|
|
20
|
+
import { isRenderFailure } from '../../shared/misc/isRenderFailure.js';
|
|
19
21
|
const globalObject = getGlobalObject('renderPageClientSide.ts', { renderCounter: 0 });
|
|
20
22
|
async function renderPageClientSide(renderArgs) {
|
|
21
23
|
const { scrollTarget, urlOriginal = getCurrentUrl(), overwriteLastHistoryEntry = false, isBackwardNavigation, pageContextsFromRewrite = [], redirectCount = 0, isUserLandPushStateNavigation, isClientSideNavigation = true } = renderArgs;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
// isHydrationRender <=> the first render attempt
|
|
25
|
+
const { isRenderOutdated, setHydrationCanBeAborted, isHydrationRender } = getIsRenderOutdated();
|
|
26
|
+
assert(isClientSideNavigation === !isHydrationRender);
|
|
24
27
|
assertNoInfiniteAbortLoop(pageContextsFromRewrite.length, redirectCount);
|
|
25
28
|
if (globalObject.clientRoutingIsDisabled) {
|
|
26
29
|
serverSideRouteTo(urlOriginal);
|
|
27
30
|
return;
|
|
28
31
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
36
|
-
{
|
|
37
|
-
const pageContextFromAllRewrites = getPageContextFromAllRewrites(pageContextsFromRewrite);
|
|
38
|
-
objectAssign(pageContext, pageContextFromAllRewrites);
|
|
39
|
-
}
|
|
40
|
-
let renderState = {};
|
|
41
|
-
const onError = (err) => {
|
|
42
|
-
assert(err);
|
|
43
|
-
assert(!('err' in renderState));
|
|
44
|
-
assert(!('errorWhileRendering' in pageContext));
|
|
45
|
-
renderState.err = err;
|
|
46
|
-
pageContext.errorWhileRendering = err;
|
|
47
|
-
};
|
|
48
|
-
if (!isFirstRender) {
|
|
32
|
+
await renderPageNominal();
|
|
33
|
+
return;
|
|
34
|
+
async function renderPageNominal() {
|
|
35
|
+
const pageContext = await getPageContextBegin();
|
|
36
|
+
if (isRenderOutdated())
|
|
37
|
+
return;
|
|
49
38
|
// Route
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
onError(err);
|
|
39
|
+
let pageContextRouted;
|
|
40
|
+
if (isHydrationRender) {
|
|
41
|
+
const pageContextSerialized = getPageContextFromHooks_serialized();
|
|
42
|
+
pageContextRouted = pageContextSerialized;
|
|
55
43
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
else {
|
|
45
|
+
let pageContextFromRoute;
|
|
46
|
+
try {
|
|
47
|
+
pageContextFromRoute = await route(pageContext);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
await renderErrorPage({ err });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (isRenderOutdated())
|
|
54
|
+
return;
|
|
62
55
|
let isClientRoutable;
|
|
63
56
|
if (!pageContextFromRoute._pageId) {
|
|
64
57
|
isClientRoutable = false;
|
|
65
58
|
}
|
|
66
59
|
else {
|
|
67
60
|
isClientRoutable = await isClientSideRoutable(pageContextFromRoute._pageId, pageContext);
|
|
68
|
-
if (
|
|
61
|
+
if (isRenderOutdated())
|
|
69
62
|
return;
|
|
70
63
|
}
|
|
71
64
|
if (!isClientRoutable) {
|
|
72
65
|
serverSideRouteTo(urlOriginal);
|
|
73
66
|
return;
|
|
74
67
|
}
|
|
68
|
+
assert(hasProp(pageContextFromRoute, '_pageId', 'string')); // Help TS
|
|
75
69
|
const isSamePage = pageContextFromRoute._pageId &&
|
|
76
70
|
globalObject.previousPageContext?._pageId &&
|
|
77
71
|
pageContextFromRoute._pageId === globalObject.previousPageContext._pageId;
|
|
@@ -79,201 +73,303 @@ async function renderPageClientSide(renderArgs) {
|
|
|
79
73
|
// Skip's Vike's rendering; let the user handle the navigation
|
|
80
74
|
return;
|
|
81
75
|
}
|
|
76
|
+
pageContextRouted = pageContextFromRoute;
|
|
82
77
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const callTransitionHooks = !isFirstRender;
|
|
86
|
-
if (callTransitionHooks) {
|
|
87
|
-
if (!globalObject.isTransitioning) {
|
|
88
|
-
if (globalObject.onPageTransitionStart) {
|
|
89
|
-
const hook = globalObject.onPageTransitionStart;
|
|
90
|
-
const { hookFn } = hook;
|
|
91
|
-
await executeHook(() => hookFn(pageContext), hook);
|
|
92
|
-
}
|
|
93
|
-
globalObject.isTransitioning = true;
|
|
94
|
-
if (abortRender())
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (isFirstRender) {
|
|
99
|
-
assert(!renderState.pageContextFromRoute);
|
|
100
|
-
assert(!renderState.err);
|
|
78
|
+
assert(!('urlOriginal' in pageContextRouted));
|
|
79
|
+
objectAssign(pageContext, pageContextRouted);
|
|
101
80
|
try {
|
|
102
|
-
|
|
81
|
+
objectAssign(pageContext, await loadUserFilesClientSide(pageContext._pageId, pageContext._pageFilesAll, pageContext._pageConfigs));
|
|
103
82
|
}
|
|
104
83
|
catch (err) {
|
|
105
|
-
|
|
84
|
+
if (handleErrorFetchingStaticAssets(err, pageContext, isHydrationRender)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
106
90
|
}
|
|
107
|
-
if (
|
|
91
|
+
if (isRenderOutdated())
|
|
108
92
|
return;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
93
|
+
// Set global hydrationCanBeAborted
|
|
94
|
+
if (pageContext.exports.hydrationCanBeAborted) {
|
|
95
|
+
setHydrationCanBeAborted();
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
assertWarning(!isReact(), 'You seem to be using React; we recommend setting hydrationCanBeAborted to true, see https://vike.dev/hydrationCanBeAborted', { onlyOnce: true });
|
|
99
|
+
}
|
|
100
|
+
// There wasn't any `await` but result may change because we just called setHydrationCanBeAborted()
|
|
101
|
+
if (isRenderOutdated())
|
|
102
|
+
return;
|
|
103
|
+
// onPageTransitionStart()
|
|
104
|
+
if (!isHydrationRender) {
|
|
105
|
+
assertHook(pageContext, 'onPageTransitionStart');
|
|
106
|
+
if (!globalObject.isTransitioning) {
|
|
107
|
+
globalObject.isTransitioning = true;
|
|
108
|
+
const onPageTransitionStartHook = getHook(pageContext, 'onPageTransitionStart');
|
|
109
|
+
if (onPageTransitionStartHook) {
|
|
110
|
+
const hook = onPageTransitionStartHook;
|
|
111
|
+
const { hookFn } = hook;
|
|
112
|
+
try {
|
|
113
|
+
await executeHook(() => hookFn(pageContext), hook);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
await renderErrorPage({ err });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (isRenderOutdated())
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Get pageContext from hooks (fetched from server, and/or directly called on the client-side)
|
|
125
|
+
if (isHydrationRender) {
|
|
126
|
+
assert(hasProp(pageContext, '_hasPageContextFromServer', 'true'));
|
|
127
|
+
let pageContextFromHooks;
|
|
117
128
|
try {
|
|
118
|
-
|
|
129
|
+
pageContextFromHooks = await getPageContextFromHooks_isHydration(pageContext);
|
|
119
130
|
}
|
|
120
131
|
catch (err) {
|
|
121
|
-
|
|
132
|
+
await renderErrorPage({ err });
|
|
133
|
+
return;
|
|
122
134
|
}
|
|
123
|
-
if (
|
|
135
|
+
if (isRenderOutdated())
|
|
124
136
|
return;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (!isAbortError(err)) {
|
|
130
|
-
// We don't swallow 404 errors:
|
|
131
|
-
// - On the server-side, Vike swallows / doesn't show any 404 error log because it's expected that a user may go to some random non-existent URL. (We don't want to flood the app's error tracking with 404 logs.)
|
|
132
|
-
// - On the client-side, if the user navigates to a 404 then it means that the UI has a broken link. (It isn't expected that users can go to some random URL using the client-side router, as it would require, for example, the user to manually change the URL of a link by manually manipulating the DOM which highly unlikely.)
|
|
133
|
-
console.error(err);
|
|
137
|
+
assert(!('urlOriginal' in pageContextFromHooks));
|
|
138
|
+
objectAssign(pageContext, pageContextFromHooks);
|
|
139
|
+
// Render page view
|
|
140
|
+
await renderPageView(pageContext);
|
|
134
141
|
}
|
|
135
142
|
else {
|
|
136
|
-
|
|
137
|
-
|
|
143
|
+
let pageContextFromHooks;
|
|
144
|
+
try {
|
|
145
|
+
pageContextFromHooks = await getPageContextFromHooks_isNotHydration(pageContext, false);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
await renderErrorPage({ err });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (isRenderOutdated())
|
|
152
|
+
return;
|
|
153
|
+
if (isRenderFailure in pageContextFromHooks) {
|
|
154
|
+
await renderErrorPage({ pageContextError: pageContextFromHooks });
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
assert(!('urlOriginal' in pageContextFromHooks));
|
|
158
|
+
objectAssign(pageContext, pageContextFromHooks);
|
|
159
|
+
// Render page view
|
|
160
|
+
await renderPageView(pageContext);
|
|
138
161
|
}
|
|
139
|
-
|
|
162
|
+
}
|
|
163
|
+
async function getPageContextBegin() {
|
|
164
|
+
const pageContext = await createPageContext(urlOriginal);
|
|
165
|
+
objectAssign(pageContext, {
|
|
166
|
+
isBackwardNavigation,
|
|
167
|
+
isClientSideNavigation
|
|
168
|
+
});
|
|
169
|
+
{
|
|
170
|
+
const pageContextFromAllRewrites = getPageContextFromAllRewrites(pageContextsFromRewrite);
|
|
171
|
+
assert(!('urlOriginal' in pageContextFromAllRewrites));
|
|
172
|
+
objectAssign(pageContext, pageContextFromAllRewrites);
|
|
173
|
+
}
|
|
174
|
+
return pageContext;
|
|
175
|
+
}
|
|
176
|
+
async function renderErrorPage(args) {
|
|
177
|
+
const pageContext = await getPageContextBegin();
|
|
178
|
+
if (isRenderOutdated())
|
|
140
179
|
return;
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
pageContextsFromRewrite: [...pageContextsFromRewrite, pageContextAbort]
|
|
151
|
-
});
|
|
180
|
+
if (args.pageContextError) {
|
|
181
|
+
objectAssign(pageContext, args.pageContextError);
|
|
182
|
+
}
|
|
183
|
+
if ('err' in args) {
|
|
184
|
+
const { err } = args;
|
|
185
|
+
assert(err);
|
|
186
|
+
assert(!('errorWhileRendering' in pageContext));
|
|
187
|
+
pageContext.errorWhileRendering = err;
|
|
188
|
+
if (shouldSwallowAndInterrupt(err))
|
|
152
189
|
return;
|
|
190
|
+
if (!isAbortError(err)) {
|
|
191
|
+
// We don't swallow 404 errors:
|
|
192
|
+
// - On the server-side, Vike swallows / doesn't show any 404 error log because it's expected that a user may go to some random non-existent URL. (We don't want to flood the app's error tracking with 404 logs.)
|
|
193
|
+
// - On the client-side, if the user navigates to a 404 then it means that the UI has a broken link. (It isn't expected that users can go to some random URL using the client-side router, as it would require, for example, the user to manually change the URL of a link by manually manipulating the DOM which highly unlikely.)
|
|
194
|
+
console.error(err);
|
|
153
195
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
196
|
+
else {
|
|
197
|
+
// We swallow throw redirect()/render() called by client-side hooks onBeforeRender()/data()/guard()
|
|
198
|
+
// We handle the abort error down below.
|
|
199
|
+
}
|
|
200
|
+
if (isAbortError(err)) {
|
|
201
|
+
const errAbort = err;
|
|
202
|
+
logAbortErrorHandled(err, !import.meta.env.DEV, pageContext);
|
|
203
|
+
const pageContextAbort = errAbort._pageContextAbort;
|
|
204
|
+
// throw render('/some-url')
|
|
205
|
+
if (pageContextAbort._urlRewrite) {
|
|
163
206
|
await renderPageClientSide({
|
|
164
207
|
...renderArgs,
|
|
165
208
|
scrollTarget: 'scroll-to-top-or-hash',
|
|
166
|
-
|
|
167
|
-
overwriteLastHistoryEntry: false,
|
|
168
|
-
isBackwardNavigation: false,
|
|
169
|
-
redirectCount: redirectCount + 1
|
|
209
|
+
pageContextsFromRewrite: [...pageContextsFromRewrite, pageContextAbort]
|
|
170
210
|
});
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
// throw redirect('/some-url')
|
|
214
|
+
if (pageContextAbort._urlRedirect) {
|
|
215
|
+
const urlRedirect = pageContextAbort._urlRedirect.url;
|
|
216
|
+
if (urlRedirect.startsWith('http')) {
|
|
217
|
+
// External redirection
|
|
218
|
+
window.location.href = urlRedirect;
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
await renderPageClientSide({
|
|
223
|
+
...renderArgs,
|
|
224
|
+
scrollTarget: 'scroll-to-top-or-hash',
|
|
225
|
+
urlOriginal: urlRedirect,
|
|
226
|
+
overwriteLastHistoryEntry: false,
|
|
227
|
+
isBackwardNavigation: false,
|
|
228
|
+
redirectCount: redirectCount + 1
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
// throw render(statusCode)
|
|
234
|
+
assert(pageContextAbort.abortStatusCode);
|
|
235
|
+
assert(!('urlOriginal' in pageContextAbort));
|
|
236
|
+
objectAssign(pageContext, pageContextAbort);
|
|
237
|
+
if (pageContextAbort.abortStatusCode === 404) {
|
|
238
|
+
objectAssign(pageContext, { is404: true });
|
|
171
239
|
}
|
|
172
|
-
return;
|
|
173
240
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
objectAssign(pageContext, pageContextAbort);
|
|
177
|
-
if (pageContextAbort.abortStatusCode === 404) {
|
|
178
|
-
objectAssign(pageContext, { is404: true });
|
|
241
|
+
else {
|
|
242
|
+
objectAssign(pageContext, { is404: false });
|
|
179
243
|
}
|
|
180
244
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
245
|
+
const errorPageId = getErrorPageId(pageContext._pageFilesAll, pageContext._pageConfigs);
|
|
246
|
+
if (!errorPageId)
|
|
247
|
+
throw new Error('No error page defined.');
|
|
248
|
+
objectAssign(pageContext, {
|
|
249
|
+
_pageId: errorPageId
|
|
250
|
+
});
|
|
184
251
|
try {
|
|
185
|
-
|
|
252
|
+
objectAssign(pageContext, await loadUserFilesClientSide(pageContext._pageId, pageContext._pageFilesAll, pageContext._pageConfigs));
|
|
186
253
|
}
|
|
187
|
-
catch (
|
|
188
|
-
|
|
189
|
-
// - Some unpexected vike internal error
|
|
190
|
-
if (shouldSwallowAndInterrupt(err2, pageContext, isFirstRender))
|
|
254
|
+
catch (err) {
|
|
255
|
+
if (handleErrorFetchingStaticAssets(err, pageContext, isHydrationRender)) {
|
|
191
256
|
return;
|
|
192
|
-
if (!isFirstRender) {
|
|
193
|
-
setTimeout(() => {
|
|
194
|
-
// We let the server show the 404 page
|
|
195
|
-
window.location.pathname = urlOriginal;
|
|
196
|
-
}, 0);
|
|
197
|
-
}
|
|
198
|
-
if (!isEquivalentError(err, err2)) {
|
|
199
|
-
throw err2;
|
|
200
257
|
}
|
|
201
258
|
else {
|
|
202
|
-
|
|
259
|
+
throw err;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (isRenderOutdated())
|
|
263
|
+
return;
|
|
264
|
+
let pageContextFromHooks;
|
|
265
|
+
try {
|
|
266
|
+
pageContextFromHooks = await getPageContextFromHooks_isNotHydration(pageContext, true);
|
|
267
|
+
}
|
|
268
|
+
catch (errErrorPage) {
|
|
269
|
+
// - When user hasn't defined a `_error.page.js` file
|
|
270
|
+
// - Some Vike unpexected internal error
|
|
271
|
+
if (shouldSwallowAndInterrupt(errErrorPage))
|
|
203
272
|
return;
|
|
273
|
+
if (!isSameErrorMessage(args.err, errErrorPage)) {
|
|
274
|
+
/* When we can't render the error page, we prefer showing a blank page over letting the server-side try because otherwise:
|
|
275
|
+
- We risk running into an infinite loop of reloads which would overload the server.
|
|
276
|
+
- An infinite reloading page is a even worse UX than a blank page.
|
|
277
|
+
serverSideRouteTo(urlOriginal)
|
|
278
|
+
*/
|
|
279
|
+
console.error(errErrorPage);
|
|
204
280
|
}
|
|
281
|
+
return;
|
|
205
282
|
}
|
|
206
|
-
if (
|
|
283
|
+
if (isRenderOutdated())
|
|
207
284
|
return;
|
|
285
|
+
assert(pageContextFromHooks);
|
|
286
|
+
assert(!('urlOriginal' in pageContextFromHooks));
|
|
287
|
+
objectAssign(pageContext, pageContextFromHooks);
|
|
288
|
+
await renderPageView(pageContext, true);
|
|
208
289
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
290
|
+
async function renderPageView(pageContext, isErrorPage) {
|
|
291
|
+
// We use globalObject.renderPromise in order to ensure that there is never two concurrent onRenderClient() calls
|
|
292
|
+
if (globalObject.renderPromise) {
|
|
293
|
+
// Make sure that the previous render has finished
|
|
294
|
+
await globalObject.renderPromise;
|
|
295
|
+
assert(globalObject.renderPromise === undefined);
|
|
296
|
+
if (isRenderOutdated())
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
changeUrl(urlOriginal, overwriteLastHistoryEntry);
|
|
300
|
+
globalObject.previousPageContext = pageContext;
|
|
301
|
+
assert(globalObject.renderPromise === undefined);
|
|
302
|
+
globalObject.renderPromise = (async () => {
|
|
303
|
+
try {
|
|
304
|
+
await executeOnRenderClientHook(pageContext, true);
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
if (!isErrorPage) {
|
|
308
|
+
renderErrorPage({ err });
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
throw err;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
addLinkPrefetchHandlers(pageContext);
|
|
315
|
+
globalObject.renderPromise = undefined;
|
|
316
|
+
})();
|
|
229
317
|
await globalObject.renderPromise;
|
|
230
318
|
assert(globalObject.renderPromise === undefined);
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
if (abortRender(true))
|
|
255
|
-
return;
|
|
319
|
+
/* We don't abort in order to ensure that onHydrationEnd() is called: we abort only after onHydrationEnd() is called.
|
|
320
|
+
if (isRenderOutdated(true)) return
|
|
321
|
+
*/
|
|
322
|
+
// onHydrationEnd()
|
|
323
|
+
if (isHydrationRender) {
|
|
324
|
+
assertHook(pageContext, 'onHydrationEnd');
|
|
325
|
+
const hook = getHook(pageContext, 'onHydrationEnd');
|
|
326
|
+
if (hook) {
|
|
327
|
+
const { hookFn } = hook;
|
|
328
|
+
try {
|
|
329
|
+
await executeHook(() => hookFn(pageContext), hook);
|
|
330
|
+
}
|
|
331
|
+
catch (err) {
|
|
332
|
+
if (!isErrorPage) {
|
|
333
|
+
renderErrorPage({ err });
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
throw err;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if (isRenderOutdated(true))
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
256
342
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
343
|
+
// We abort *after* onHydrationEnd() is called
|
|
344
|
+
if (isRenderOutdated(true))
|
|
345
|
+
return;
|
|
346
|
+
// onPageTransitionEnd()
|
|
347
|
+
if (globalObject.isTransitioning) {
|
|
348
|
+
globalObject.isTransitioning = undefined;
|
|
349
|
+
assertHook(pageContext, 'onPageTransitionEnd');
|
|
350
|
+
const hook = getHook(pageContext, 'onPageTransitionEnd');
|
|
351
|
+
if (hook) {
|
|
352
|
+
const { hookFn } = hook;
|
|
353
|
+
try {
|
|
354
|
+
await executeHook(() => hookFn(pageContext), hook);
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
if (!isErrorPage) {
|
|
358
|
+
renderErrorPage({ err });
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
throw err;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (isRenderOutdated(true))
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
270
367
|
}
|
|
271
|
-
|
|
368
|
+
// Page scrolling
|
|
369
|
+
setScrollPosition(scrollTarget);
|
|
370
|
+
browserNativeScrollRestoration_disable();
|
|
371
|
+
setInitialRenderIsDone();
|
|
272
372
|
}
|
|
273
|
-
// Page scrolling
|
|
274
|
-
setScrollPosition(scrollTarget);
|
|
275
|
-
browserNativeScrollRestoration_disable();
|
|
276
|
-
setInitialRenderIsDone();
|
|
277
373
|
}
|
|
278
374
|
function changeUrl(url, overwriteLastHistoryEntry) {
|
|
279
375
|
if (getCurrentUrl() === url)
|
|
@@ -282,18 +378,16 @@ function changeUrl(url, overwriteLastHistoryEntry) {
|
|
|
282
378
|
pushHistory(url, overwriteLastHistoryEntry);
|
|
283
379
|
updateState();
|
|
284
380
|
}
|
|
285
|
-
function shouldSwallowAndInterrupt(err
|
|
286
|
-
if (
|
|
287
|
-
return true;
|
|
288
|
-
if (handleErrorFetchingStaticAssets(err, pageContext, isFirstRender))
|
|
381
|
+
function shouldSwallowAndInterrupt(err) {
|
|
382
|
+
if (isServerSideRouted(err))
|
|
289
383
|
return true;
|
|
290
384
|
return false;
|
|
291
385
|
}
|
|
292
|
-
function handleErrorFetchingStaticAssets(err, pageContext,
|
|
386
|
+
function handleErrorFetchingStaticAssets(err, pageContext, isHydrationRender) {
|
|
293
387
|
if (!isErrorFetchingStaticAssets(err)) {
|
|
294
388
|
return false;
|
|
295
389
|
}
|
|
296
|
-
if (
|
|
390
|
+
if (isHydrationRender) {
|
|
297
391
|
disableClientRouting(err, false);
|
|
298
392
|
// This may happen if the frontend was newly deployed during hydration.
|
|
299
393
|
// Ideally: re-try a couple of times by reloading the page (not entirely trivial to implement since `localStorage` is needed.)
|
|
@@ -323,7 +417,7 @@ function disableClientRouting(err, log) {
|
|
|
323
417
|
.filter(Boolean)
|
|
324
418
|
.join(' '), { onlyOnce: true });
|
|
325
419
|
}
|
|
326
|
-
function
|
|
420
|
+
function getIsRenderOutdated() {
|
|
327
421
|
const renderNumber = ++globalObject.renderCounter;
|
|
328
422
|
assert(renderNumber >= 1);
|
|
329
423
|
let hydrationCanBeAborted = false;
|
|
@@ -331,11 +425,11 @@ function getAbortRender() {
|
|
|
331
425
|
hydrationCanBeAborted = true;
|
|
332
426
|
};
|
|
333
427
|
/** Whether the rendering should be aborted because a new rendering has started. We should call this after each `await`. */
|
|
334
|
-
const
|
|
428
|
+
const isRenderOutdated = (isRenderCleanup) => {
|
|
335
429
|
// Never abort hydration if `hydrationCanBeAborted` isn't `true`
|
|
336
|
-
|
|
430
|
+
{
|
|
337
431
|
const isHydration = renderNumber === 1;
|
|
338
|
-
if (isHydration && !hydrationCanBeAborted) {
|
|
432
|
+
if (isHydration && !hydrationCanBeAborted && !isRenderCleanup) {
|
|
339
433
|
return false;
|
|
340
434
|
}
|
|
341
435
|
}
|
|
@@ -343,9 +437,9 @@ function getAbortRender() {
|
|
|
343
437
|
return renderNumber !== globalObject.renderCounter;
|
|
344
438
|
};
|
|
345
439
|
return {
|
|
346
|
-
|
|
440
|
+
isRenderOutdated,
|
|
347
441
|
setHydrationCanBeAborted,
|
|
348
|
-
|
|
442
|
+
isHydrationRender: renderNumber === 1
|
|
349
443
|
};
|
|
350
444
|
}
|
|
351
445
|
function getRenderCount() {
|
|
@@ -10,7 +10,7 @@ export * from '../../utils/isCallable.js';
|
|
|
10
10
|
export * from '../../utils/isObject.js';
|
|
11
11
|
export * from '../../utils/isPlainObject.js';
|
|
12
12
|
export * from '../../utils/isReact.js';
|
|
13
|
-
export * from '../../utils/
|
|
13
|
+
export * from '../../utils/isSameErrorMessage.js';
|
|
14
14
|
export * from '../../utils/objectAssign.js';
|
|
15
15
|
export * from '../../utils/parseUrl.js';
|
|
16
16
|
export * from '../../utils/projectInfo.js';
|
|
@@ -16,7 +16,7 @@ export * from '../../utils/isCallable.js';
|
|
|
16
16
|
export * from '../../utils/isObject.js';
|
|
17
17
|
export * from '../../utils/isPlainObject.js';
|
|
18
18
|
export * from '../../utils/isReact.js';
|
|
19
|
-
export * from '../../utils/
|
|
19
|
+
export * from '../../utils/isSameErrorMessage.js';
|
|
20
20
|
export * from '../../utils/objectAssign.js';
|
|
21
21
|
export * from '../../utils/parseUrl.js';
|
|
22
22
|
export * from '../../utils/projectInfo.js';
|