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.
Files changed (93) hide show
  1. package/dist/cjs/node/cli/bin.js +2 -2
  2. package/dist/cjs/node/plugin/index.js +2 -2
  3. package/dist/cjs/node/plugin/plugins/autoFullBuild.js +2 -2
  4. package/dist/cjs/node/plugin/plugins/envVars.js +1 -1
  5. package/dist/cjs/node/plugin/plugins/{assertFileEnv.js → fileEnv.js} +4 -4
  6. package/dist/cjs/node/plugin/plugins/importBuild/index.js +1 -1
  7. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +1 -9
  8. package/dist/cjs/node/prerender/index.js +1 -1
  9. package/dist/cjs/node/prerender/runPrerender.js +21 -13
  10. package/dist/cjs/node/runtime/html/serializePageContextClientSide.js +5 -3
  11. package/dist/cjs/node/runtime/html/stream.js +2 -1
  12. package/dist/cjs/node/runtime/renderPage/getPageAssets/retrieveAssetsDev.js +2 -1
  13. package/dist/cjs/node/runtime/renderPage/isNewError.js +1 -1
  14. package/dist/cjs/node/runtime/renderPage/{loadPageFilesServerSide.js → loadUserFilesServerSide.js} +5 -5
  15. package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +5 -4
  16. package/dist/cjs/node/runtime/renderPage.js +2 -2
  17. package/dist/cjs/node/runtime/utils.js +1 -2
  18. package/dist/cjs/shared/hooks/getHook.js +14 -8
  19. package/dist/cjs/shared/misc/isRenderFailure.js +4 -0
  20. package/dist/cjs/shared/misc/pageContextInitIsPassedToClient.js +4 -0
  21. package/dist/cjs/shared/route/abort.js +15 -4
  22. package/dist/cjs/shared/route/loadPageRoutes.js +1 -9
  23. package/dist/cjs/utils/isSameErrorMessage.js +10 -0
  24. package/dist/cjs/utils/projectInfo.js +1 -1
  25. package/dist/esm/client/client-routing-runtime/createPageContext.d.ts +0 -1
  26. package/dist/esm/client/client-routing-runtime/createPageContext.js +0 -3
  27. package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.d.ts +28 -33
  28. package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +42 -58
  29. package/dist/esm/client/client-routing-runtime/installClientRouter.d.ts +1 -1
  30. package/dist/esm/client/client-routing-runtime/installClientRouter.js +8 -2
  31. package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.js +2 -2
  32. package/dist/esm/client/client-routing-runtime/onLinkClick.js +2 -2
  33. package/dist/esm/client/client-routing-runtime/prefetch/getPrefetchSettings.d.ts +1 -3
  34. package/dist/esm/client/client-routing-runtime/prefetch/getPrefetchSettings.js +1 -1
  35. package/dist/esm/client/client-routing-runtime/prefetch.d.ts +0 -1
  36. package/dist/esm/client/client-routing-runtime/prefetch.js +2 -2
  37. package/dist/esm/client/client-routing-runtime/renderPageClientSide.d.ts +1 -1
  38. package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +298 -204
  39. package/dist/esm/client/client-routing-runtime/utils.d.ts +1 -1
  40. package/dist/esm/client/client-routing-runtime/utils.js +1 -1
  41. package/dist/esm/client/server-routing-runtime/getPageContext.d.ts +2 -2
  42. package/dist/esm/client/server-routing-runtime/getPageContext.js +5 -4
  43. package/dist/esm/client/shared/executeOnRenderClientHook.d.ts +4 -2
  44. package/dist/esm/client/shared/getPageContextSerializedInHtml.d.ts +0 -1
  45. package/dist/esm/client/shared/getPageContextSerializedInHtml.js +1 -4
  46. package/dist/esm/client/shared/{loadPageFilesClientSide.d.ts → loadUserFilesClientSide.d.ts} +7 -6
  47. package/dist/esm/client/shared/{loadPageFilesClientSide.js → loadUserFilesClientSide.js} +4 -4
  48. package/dist/esm/node/cli/bin.js +3 -3
  49. package/dist/esm/node/plugin/index.js +2 -2
  50. package/dist/esm/node/plugin/plugins/autoFullBuild.js +3 -3
  51. package/dist/esm/node/plugin/plugins/envVars.js +1 -1
  52. package/dist/esm/node/plugin/plugins/fileEnv.d.ts +3 -0
  53. package/dist/esm/node/plugin/plugins/{assertFileEnv.js → fileEnv.js} +3 -3
  54. package/dist/esm/node/plugin/plugins/importBuild/index.js +1 -1
  55. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +1 -9
  56. package/dist/esm/node/prerender/index.d.ts +1 -1
  57. package/dist/esm/node/prerender/index.js +1 -1
  58. package/dist/esm/node/prerender/runPrerender.d.ts +8 -8
  59. package/dist/esm/node/prerender/runPrerender.js +22 -14
  60. package/dist/esm/node/runtime/html/serializePageContextClientSide.d.ts +0 -1
  61. package/dist/esm/node/runtime/html/serializePageContextClientSide.js +5 -3
  62. package/dist/esm/node/runtime/html/stream.js +3 -2
  63. package/dist/esm/node/runtime/renderPage/getPageAssets/retrieveAssetsDev.js +2 -1
  64. package/dist/esm/node/runtime/renderPage/isNewError.js +2 -2
  65. package/dist/esm/node/runtime/renderPage/{loadPageFilesServerSide.d.ts → loadUserFilesServerSide.d.ts} +6 -6
  66. package/dist/esm/node/runtime/renderPage/{loadPageFilesServerSide.js → loadUserFilesServerSide.js} +4 -4
  67. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +2 -2
  68. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +5 -4
  69. package/dist/esm/node/runtime/renderPage.js +2 -2
  70. package/dist/esm/node/runtime/utils.d.ts +1 -2
  71. package/dist/esm/node/runtime/utils.js +1 -2
  72. package/dist/esm/shared/hooks/getHook.d.ts +2 -0
  73. package/dist/esm/shared/hooks/getHook.js +13 -7
  74. package/dist/esm/shared/misc/isRenderFailure.d.ts +1 -0
  75. package/dist/esm/shared/misc/isRenderFailure.js +1 -0
  76. package/dist/esm/shared/misc/pageContextInitIsPassedToClient.d.ts +1 -0
  77. package/dist/esm/shared/misc/pageContextInitIsPassedToClient.js +1 -0
  78. package/dist/esm/shared/page-configs/Config.d.ts +1 -1
  79. package/dist/esm/shared/route/abort.d.ts +1 -1
  80. package/dist/esm/shared/route/abort.js +16 -5
  81. package/dist/esm/shared/route/loadPageRoutes.js +1 -9
  82. package/dist/esm/utils/isSameErrorMessage.d.ts +2 -0
  83. package/dist/esm/utils/isSameErrorMessage.js +7 -0
  84. package/dist/esm/utils/projectInfo.d.ts +2 -2
  85. package/dist/esm/utils/projectInfo.js +1 -1
  86. package/package.json +2 -2
  87. package/dist/cjs/utils/dynamicImport.js +0 -8
  88. package/dist/cjs/utils/isEquivalentError.js +0 -18
  89. package/dist/esm/node/plugin/plugins/assertFileEnv.d.ts +0 -3
  90. package/dist/esm/utils/dynamicImport.d.ts +0 -2
  91. package/dist/esm/utils/dynamicImport.js +0 -4
  92. package/dist/esm/utils/isEquivalentError.d.ts +0 -2
  93. 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, isEquivalentError, objectAssign, serverSideRouteTo, getGlobalObject, executeHook, hasProp } from './utils.js';
5
- import { getPageContextFromHooks_errorPage, getPageContextFromHooks_firstRender, getPageContextFromHooks_uponNavigation, isAlreadyServerSideRouted } from './getPageContextFromHooks.js';
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/loadPageFilesClientSide.js';
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
- const { abortRender, setHydrationCanBeAborted, isFirstRender } = getAbortRender();
23
- assert(isClientSideNavigation === !isFirstRender);
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
- const pageContext = await createPageContext(urlOriginal);
30
- if (abortRender())
31
- return;
32
- objectAssign(pageContext, {
33
- isBackwardNavigation,
34
- isClientSideNavigation
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
- try {
51
- renderState = { pageContextFromRoute: await route(pageContext) };
52
- }
53
- catch (err) {
54
- onError(err);
39
+ let pageContextRouted;
40
+ if (isHydrationRender) {
41
+ const pageContextSerialized = getPageContextFromHooks_serialized();
42
+ pageContextRouted = pageContextSerialized;
55
43
  }
56
- if (abortRender())
57
- return;
58
- // Check whether rendering should be skipped
59
- if (renderState.pageContextFromRoute) {
60
- const { pageContextFromRoute } = renderState;
61
- objectAssign(pageContext, pageContextFromRoute);
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 (abortRender())
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
- // onPageTransitionStart()
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
- renderState.pageContextFromHooks = await getPageContextFromHooks_firstRender(pageContext);
81
+ objectAssign(pageContext, await loadUserFilesClientSide(pageContext._pageId, pageContext._pageFilesAll, pageContext._pageConfigs));
103
82
  }
104
83
  catch (err) {
105
- onError(err);
84
+ if (handleErrorFetchingStaticAssets(err, pageContext, isHydrationRender)) {
85
+ return;
86
+ }
87
+ else {
88
+ throw err;
89
+ }
106
90
  }
107
- if (abortRender())
91
+ if (isRenderOutdated())
108
92
  return;
109
- }
110
- else {
111
- if (!renderState.err) {
112
- const { pageContextFromRoute } = renderState;
113
- assert(pageContextFromRoute);
114
- assert(pageContextFromRoute._pageId);
115
- assert(hasProp(pageContextFromRoute, '_pageId', 'string')); // Help TS
116
- objectAssign(pageContext, pageContextFromRoute);
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
- renderState.pageContextFromHooks = await getPageContextFromHooks_uponNavigation(pageContext);
129
+ pageContextFromHooks = await getPageContextFromHooks_isHydration(pageContext);
119
130
  }
120
131
  catch (err) {
121
- onError(err);
132
+ await renderErrorPage({ err });
133
+ return;
122
134
  }
123
- if (abortRender())
135
+ if (isRenderOutdated())
124
136
  return;
125
- }
126
- }
127
- if ('err' in renderState) {
128
- const { err } = renderState;
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
- // We swallow throw redirect()/render() called by client-side hooks onBeforeRender(), data() and guard()
137
- // We handle the abort error down below.
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
- if (shouldSwallowAndInterrupt(err, pageContext, isFirstRender))
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 (isAbortError(err)) {
142
- const errAbort = err;
143
- logAbortErrorHandled(err, pageContext._isProduction, pageContext);
144
- const pageContextAbort = errAbort._pageContextAbort;
145
- // throw render('/some-url')
146
- if (pageContextAbort._urlRewrite) {
147
- await renderPageClientSide({
148
- ...renderArgs,
149
- scrollTarget: 'scroll-to-top-or-hash',
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
- // throw redirect('/some-url')
155
- if (pageContextAbort._urlRedirect) {
156
- const urlRedirect = pageContextAbort._urlRedirect.url;
157
- if (urlRedirect.startsWith('http')) {
158
- // External redirection
159
- window.location.href = urlRedirect;
160
- return;
161
- }
162
- else {
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
- urlOriginal: urlRedirect,
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
- // throw render(statusCode)
175
- assert(pageContextAbort.abortStatusCode);
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
- else {
182
- objectAssign(pageContext, { is404: false });
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
- renderState.pageContextFromHooks = await getPageContextFromHooks_errorPage(pageContext);
252
+ objectAssign(pageContext, await loadUserFilesClientSide(pageContext._pageId, pageContext._pageFilesAll, pageContext._pageConfigs));
186
253
  }
187
- catch (err2) {
188
- // - When user hasn't defined a `_error.page.js` file
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
- // Abort
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 (abortRender())
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
- const { pageContextFromHooks } = renderState;
210
- assert(pageContextFromHooks);
211
- objectAssign(pageContext, pageContextFromHooks);
212
- // Set global onPageTransitionStart()
213
- assertHook(pageContext, 'onPageTransitionStart');
214
- const onPageTransitionStartHook = getHook(pageContext, 'onPageTransitionStart');
215
- globalObject.onPageTransitionStart = onPageTransitionStartHook;
216
- // Set global hydrationCanBeAborted
217
- if (pageContext.exports.hydrationCanBeAborted) {
218
- setHydrationCanBeAborted();
219
- }
220
- else {
221
- assertWarning(!isReact(), 'You seem to be using React; we recommend setting hydrationCanBeAborted to true, see https://vike.dev/hydrationCanBeAborted', { onlyOnce: true });
222
- }
223
- // There wasn't any `await` but result may change because we just called setHydrationCanBeAborted()
224
- if (abortRender())
225
- return;
226
- // We use globalObject.renderPromise in order to ensure that there is never two concurrent onRenderClient() calls
227
- if (globalObject.renderPromise) {
228
- // Make sure that the previous render has finished
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
- if (abortRender())
232
- return;
233
- }
234
- changeUrl(urlOriginal, overwriteLastHistoryEntry);
235
- globalObject.previousPageContext = pageContext;
236
- assert(globalObject.renderPromise === undefined);
237
- globalObject.renderPromise = (async () => {
238
- await executeOnRenderClientHook(pageContext, true);
239
- addLinkPrefetchHandlers(pageContext);
240
- globalObject.renderPromise = undefined;
241
- })();
242
- await globalObject.renderPromise;
243
- assert(globalObject.renderPromise === undefined);
244
- /* We don't abort in order to ensure that onHydrationEnd() is called: we abort only after onHydrationEnd() is called.
245
- if (abortRender(true)) return
246
- */
247
- // onHydrationEnd()
248
- if (isFirstRender) {
249
- assertHook(pageContext, 'onHydrationEnd');
250
- const hook = getHook(pageContext, 'onHydrationEnd');
251
- if (hook) {
252
- const { hookFn } = hook;
253
- await executeHook(() => hookFn(pageContext), hook);
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
- // We abort only after onHydrationEnd() is called
259
- if (abortRender(true))
260
- return;
261
- // onPageTransitionEnd()
262
- if (callTransitionHooks) {
263
- assertHook(pageContext, 'onPageTransitionEnd');
264
- const hook = getHook(pageContext, 'onPageTransitionEnd');
265
- if (hook) {
266
- const { hookFn } = hook;
267
- await executeHook(() => hookFn(pageContext), hook);
268
- if (abortRender(true))
269
- return;
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
- globalObject.isTransitioning = undefined;
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, pageContext, isFirstRender) {
286
- if (isAlreadyServerSideRouted(err))
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, isFirstRender) {
386
+ function handleErrorFetchingStaticAssets(err, pageContext, isHydrationRender) {
293
387
  if (!isErrorFetchingStaticAssets(err)) {
294
388
  return false;
295
389
  }
296
- if (isFirstRender) {
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 getAbortRender() {
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 abortRender = (isRenderCleanup) => {
428
+ const isRenderOutdated = (isRenderCleanup) => {
335
429
  // Never abort hydration if `hydrationCanBeAborted` isn't `true`
336
- if (!isRenderCleanup) {
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
- abortRender,
440
+ isRenderOutdated,
347
441
  setHydrationCanBeAborted,
348
- isFirstRender: renderNumber === 1
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/isEquivalentError.js';
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/isEquivalentError.js';
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';