vike 0.4.171-commit-ea3808a → 0.4.171-commit-e429162

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 (30) hide show
  1. package/dist/cjs/node/prerender/runPrerender.js +2 -2
  2. package/dist/cjs/node/runtime/renderPage/executeOnBeforeRenderAndDataHooks.js +2 -2
  3. package/dist/cjs/node/runtime/renderPage/executeOnRenderHtmlHook.js +1 -1
  4. package/dist/cjs/shared/getPageContext.js +5 -0
  5. package/dist/cjs/shared/hooks/executeHook.js +18 -3
  6. package/dist/cjs/shared/route/executeGuardHook.js +1 -1
  7. package/dist/cjs/shared/route/executeOnBeforeRouteHook.js +1 -1
  8. package/dist/cjs/utils/getPropAccessNotation.js +1 -4
  9. package/dist/cjs/utils/projectInfo.js +1 -1
  10. package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +1 -1
  11. package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +3 -3
  12. package/dist/esm/client/server-routing-runtime/utils.d.ts +1 -0
  13. package/dist/esm/client/server-routing-runtime/utils.js +1 -0
  14. package/dist/esm/client/shared/executeOnRenderClientHook.js +1 -1
  15. package/dist/esm/client/shared/getPageContextProxyForUser.d.ts +3 -2
  16. package/dist/esm/client/shared/getPageContextProxyForUser.js +35 -48
  17. package/dist/esm/node/prerender/runPrerender.js +2 -2
  18. package/dist/esm/node/runtime/renderPage/executeOnBeforeRenderAndDataHooks.js +2 -2
  19. package/dist/esm/node/runtime/renderPage/executeOnRenderHtmlHook.js +1 -1
  20. package/dist/esm/shared/getPageContext.d.ts +1 -0
  21. package/dist/esm/shared/getPageContext.js +1 -0
  22. package/dist/esm/shared/hooks/executeHook.d.ts +5 -1
  23. package/dist/esm/shared/hooks/executeHook.js +17 -2
  24. package/dist/esm/shared/route/executeGuardHook.js +1 -1
  25. package/dist/esm/shared/route/executeOnBeforeRouteHook.js +1 -1
  26. package/dist/esm/utils/getPropAccessNotation.d.ts +1 -2
  27. package/dist/esm/utils/getPropAccessNotation.js +2 -6
  28. package/dist/esm/utils/projectInfo.d.ts +2 -2
  29. package/dist/esm/utils/projectInfo.js +1 -1
  30. package/package.json +10 -1
@@ -245,7 +245,7 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
245
245
  if (doNotPrerenderList.find((p) => p.pageId === pageId)) {
246
246
  return;
247
247
  }
248
- const prerenderResult = await (0, executeHook_js_1.executeHook)(() => hookFn(), { hookName, hookFilePath, hookTimeout });
248
+ const prerenderResult = await (0, executeHook_js_1.executeHook)(() => hookFn(), { hookName, hookFilePath, hookTimeout }, null);
249
249
  const result = normalizeOnPrerenderHookResult(prerenderResult, hookFilePath, hookName);
250
250
  result.forEach(({ url, pageContext }) => {
251
251
  {
@@ -420,7 +420,7 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
420
420
  });
421
421
  return prerenderContext.pageContexts;
422
422
  }
423
- }), onPrerenderStartHook);
423
+ }), onPrerenderStartHook, null);
424
424
  if (result === null || result === undefined) {
425
425
  return;
426
426
  }
@@ -16,7 +16,7 @@ async function executeOnBeforeRenderAndDataHooks(pageContext) {
16
16
  }
17
17
  (0, preparePageContextForUserConsumptionServerSide_js_1.preparePageContextForUserConsumptionServerSide)(pageContext);
18
18
  if (dataHook) {
19
- const hookResult = await (0, executeHook_js_1.executeHook)(() => dataHook.hookFn(pageContext), dataHook);
19
+ const hookResult = await (0, executeHook_js_1.executeHook)(() => dataHook.hookFn(pageContext), dataHook, pageContext);
20
20
  // Note: hookResult can be anything (e.g. an object) and is to be assigned to pageContext.data
21
21
  const pageContextFromHook = {
22
22
  data: hookResult
@@ -24,7 +24,7 @@ async function executeOnBeforeRenderAndDataHooks(pageContext) {
24
24
  Object.assign(pageContext, pageContextFromHook);
25
25
  }
26
26
  if (onBeforeRenderHook) {
27
- const hookResult = await (0, executeHook_js_1.executeHook)(() => onBeforeRenderHook.hookFn(pageContext), onBeforeRenderHook);
27
+ const hookResult = await (0, executeHook_js_1.executeHook)(() => onBeforeRenderHook.hookFn(pageContext), onBeforeRenderHook, pageContext);
28
28
  (0, assertOnBeforeRenderHookReturn_js_1.assertOnBeforeRenderHookReturn)(hookResult, onBeforeRenderHook.hookFilePath);
29
29
  const pageContextFromHook = hookResult?.pageContext;
30
30
  Object.assign(pageContext, pageContextFromHook);
@@ -18,7 +18,7 @@ async function executeOnRenderHtmlHook(pageContext) {
18
18
  const { renderHook, hookFn } = getRenderHook(pageContext);
19
19
  (0, utils_js_1.objectAssign)(pageContext, { _renderHook: renderHook });
20
20
  (0, preparePageContextForUserConsumptionServerSide_js_1.preparePageContextForUserConsumptionServerSide)(pageContext);
21
- const hookReturnValue = await (0, executeHook_js_1.executeHook)(() => hookFn(pageContext), renderHook);
21
+ const hookReturnValue = await (0, executeHook_js_1.executeHook)(() => hookFn(pageContext), renderHook, pageContext);
22
22
  const { documentHtml, pageContextProvidedByRenderHook, pageContextPromise, injectFilter } = processHookReturnValue(hookReturnValue, renderHook);
23
23
  Object.assign(pageContext, pageContextProvidedByRenderHook);
24
24
  (0, utils_js_1.objectAssign)(pageContext, { _pageContextPromise: pageContextPromise });
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPageContext = void 0;
4
+ var executeHook_js_1 = require("./hooks/executeHook.js");
5
+ Object.defineProperty(exports, "getPageContext", { enumerable: true, get: function () { return executeHook_js_1.getPageContext; } });
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUserHookError = exports.executeHook = void 0;
3
+ exports.isUserHookError = exports.getPageContext = exports.executeHook = void 0;
4
4
  const assert_js_1 = require("../../utils/assert.js");
5
5
  const getGlobalObject_js_1 = require("../../utils/getGlobalObject.js");
6
6
  const humanizeTime_js_1 = require("../../utils/humanizeTime.js");
7
7
  const isObject_js_1 = require("../../utils/isObject.js");
8
+ const utils_js_1 = require("../utils.js");
8
9
  const globalObject = (0, getGlobalObject_js_1.getGlobalObject)('utils/executeHook.ts', {
9
- userHookErrors: new WeakMap()
10
+ userHookErrors: new WeakMap(),
11
+ pageContext: null
10
12
  });
11
13
  function isUserHookError(err) {
12
14
  if (!(0, isObject_js_1.isObject)(err))
@@ -14,7 +16,7 @@ function isUserHookError(err) {
14
16
  return globalObject.userHookErrors.get(err) ?? false;
15
17
  }
16
18
  exports.isUserHookError = isUserHookError;
17
- function executeHook(hookFnCaller, hook) {
19
+ function executeHook(hookFnCaller, hook, pageContext) {
18
20
  const { hookName, hookFilePath, hookTimeout: { error: timeoutErr, warning: timeoutWarn } } = hook;
19
21
  let resolve;
20
22
  let reject;
@@ -45,6 +47,7 @@ function executeHook(hookFnCaller, hook) {
45
47
  }, timeoutErr);
46
48
  (async () => {
47
49
  try {
50
+ providePageContext(pageContext);
48
51
  const ret = await hookFnCaller();
49
52
  resolve(ret);
50
53
  }
@@ -61,3 +64,15 @@ exports.executeHook = executeHook;
61
64
  function isNotDisabled(timeout) {
62
65
  return !!timeout && timeout !== Infinity;
63
66
  }
67
+ function getPageContext() {
68
+ return globalObject.pageContext;
69
+ }
70
+ exports.getPageContext = getPageContext;
71
+ function providePageContext(pageContext) {
72
+ globalObject.pageContext = pageContext;
73
+ if (!(0, utils_js_1.isBrowser)()) {
74
+ process.nextTick(() => {
75
+ globalObject.pageContext = null;
76
+ });
77
+ }
78
+ }
@@ -23,7 +23,7 @@ async function executeGuardHook(pageContext, prepareForUserConsumption) {
23
23
  const res = prepareForUserConsumption(pageContext);
24
24
  if (res)
25
25
  pageContextForUserConsumption = res;
26
- const hookResult = await (0, executeHook_js_1.executeHook)(() => guard(pageContextForUserConsumption), hook);
26
+ const hookResult = await (0, executeHook_js_1.executeHook)(() => guard(pageContextForUserConsumption), hook, pageContext);
27
27
  (0, utils_js_1.assertUsage)(hookResult === undefined, `${errIntro} ${hook.hookFilePath} returns a value, but guard() shouldn't return any value`);
28
28
  }
29
29
  exports.executeGuardHook = executeGuardHook;
@@ -42,7 +42,7 @@ async function getPageContextFromHook(onBeforeRouteHook, pageContext) {
42
42
  let hookReturn = onBeforeRouteHook.hookFn(pageContext);
43
43
  (0, resolveRouteFunction_js_1.assertSyncRouting)(hookReturn, `The onBeforeRoute() hook ${onBeforeRouteHook.hookFilePath}`);
44
44
  // TODO/v1-release: make executeOnBeforeRouteHook() and route() sync
45
- hookReturn = await (0, executeHook_js_1.executeHook)(() => hookReturn, onBeforeRouteHook);
45
+ hookReturn = await (0, executeHook_js_1.executeHook)(() => hookReturn, onBeforeRouteHook, pageContext);
46
46
  const errPrefix = `The onBeforeRoute() hook defined by ${onBeforeRouteHook.hookFilePath}`;
47
47
  (0, utils_js_1.assertUsage)(hookReturn === null ||
48
48
  hookReturn === undefined ||
@@ -2,9 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getPropAccessNotation = void 0;
4
4
  function getPropAccessNotation(key) {
5
- return isKeyDotNotationCompatible(key) ? `.${key}` : `[${JSON.stringify(key)}]`;
5
+ return typeof key === 'string' && /^[a-z0-9\$_]+$/i.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`;
6
6
  }
7
7
  exports.getPropAccessNotation = getPropAccessNotation;
8
- function isKeyDotNotationCompatible(key) {
9
- return /^[a-z0-9\$_]+$/i.test(key);
10
- }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROJECT_VERSION = exports.projectInfo = void 0;
4
- const PROJECT_VERSION = '0.4.171-commit-ea3808a';
4
+ const PROJECT_VERSION = '0.4.171-commit-e429162';
5
5
  exports.PROJECT_VERSION = PROJECT_VERSION;
6
6
  const projectInfo = {
7
7
  projectName: 'Vike',
@@ -108,7 +108,7 @@ async function executeHookClientSide(hookName, pageContext) {
108
108
  return null;
109
109
  }
110
110
  const pageContextForUserConsumption = preparePageContextForUserConsumptionClientSide(pageContext, true);
111
- const hookResult = await executeHook(() => hook.hookFn(pageContextForUserConsumption), hook);
111
+ const hookResult = await executeHook(() => hook.hookFn(pageContextForUserConsumption), hook, pageContext);
112
112
  const pageContextFromHook = {};
113
113
  if (hookName === 'onBeforeRender') {
114
114
  assertOnBeforeRenderHookReturn(hookResult, hook.hookFilePath);
@@ -51,7 +51,7 @@ async function renderPageClientSide(renderArgs) {
51
51
  const hook = onPageTransitionStartHook;
52
52
  const { hookFn } = hook;
53
53
  try {
54
- await executeHook(() => hookFn(pageContext), hook);
54
+ await executeHook(() => hookFn(pageContext), hook, pageContext);
55
55
  }
56
56
  catch (err) {
57
57
  await onError(err);
@@ -353,7 +353,7 @@ async function renderPageClientSide(renderArgs) {
353
353
  if (hook) {
354
354
  const { hookFn } = hook;
355
355
  try {
356
- await executeHook(() => hookFn(pageContext), hook);
356
+ await executeHook(() => hookFn(pageContext), hook, pageContext);
357
357
  }
358
358
  catch (err) {
359
359
  await onError(err);
@@ -377,7 +377,7 @@ async function renderPageClientSide(renderArgs) {
377
377
  if (hook) {
378
378
  const { hookFn } = hook;
379
379
  try {
380
- await executeHook(() => hookFn(pageContext), hook);
380
+ await executeHook(() => hookFn(pageContext), hook, pageContext);
381
381
  }
382
382
  catch (err) {
383
383
  await onError(err);
@@ -12,3 +12,4 @@ export * from '../../utils/parseUrl.js';
12
12
  export * from '../../utils/projectInfo.js';
13
13
  export * from '../../utils/slice.js';
14
14
  export * from '../../utils/unique.js';
15
+ export * from '../../utils/getPropAccessNotation.js';
@@ -16,3 +16,4 @@ export * from '../../utils/parseUrl.js';
16
16
  export * from '../../utils/projectInfo.js';
17
17
  export * from '../../utils/slice.js';
18
18
  export * from '../../utils/unique.js'; // Only used by Server Routing (not needed for Client Routing)
19
+ export * from '../../utils/getPropAccessNotation.js';
@@ -45,7 +45,7 @@ async function executeOnRenderClientHook(pageContext, isClientRouting) {
45
45
  const renderHook = hook.hookFn;
46
46
  assert(hookName);
47
47
  // We don't use a try-catch wrapper because rendering errors are usually handled by the UI framework. (E.g. React's Error Boundaries.)
48
- const hookResult = await executeHook(() => renderHook(pageContextForUserConsumption), hook);
48
+ const hookResult = await executeHook(() => renderHook(pageContextForUserConsumption), hook, pageContext);
49
49
  assertUsage(hookResult === undefined, `The ${hookName}() hook defined by ${hook.hookFilePath} isn't allowed to return a value`);
50
50
  }
51
51
  function getUrlToShowToUser(pageContext) {
@@ -5,7 +5,8 @@ type PageContextForPassToClientWarning = {
5
5
  _hasPageContextFromClient: boolean;
6
6
  };
7
7
  /**
8
- * - Throw error when pageContext value isn't serializable
9
- * - Throw error when pageContext prop is missing in passToClient
8
+ * Throw error when pageContext value isn't:
9
+ * - serializable, or
10
+ * - defined.
10
11
  */
11
12
  declare function getPageContextProxyForUser<PageContext extends Record<string, unknown> & PageContextForPassToClientWarning>(pageContext: PageContext): PageContext;
@@ -1,10 +1,11 @@
1
1
  export { getPageContextProxyForUser };
2
- import { assert, assertUsage, assertWarning, getGlobalObject } from '../server-routing-runtime/utils.js';
2
+ import { assert, assertUsage, assertWarning, getGlobalObject, getPropAccessNotation } from '../server-routing-runtime/utils.js';
3
3
  import { notSerializable } from '../../shared/notSerializable.js';
4
4
  const globalObject = getGlobalObject('getPageContextProxyForUser.ts', {});
5
5
  /**
6
- * - Throw error when pageContext value isn't serializable
7
- * - Throw error when pageContext prop is missing in passToClient
6
+ * Throw error when pageContext value isn't:
7
+ * - serializable, or
8
+ * - defined.
8
9
  */
9
10
  function getPageContextProxyForUser(pageContext) {
10
11
  assert([true, false].includes(pageContext._hasPageContextFromServer));
@@ -12,66 +13,45 @@ function getPageContextProxyForUser(pageContext) {
12
13
  return new Proxy(pageContext, {
13
14
  get(_, prop) {
14
15
  const val = pageContext[prop];
15
- const propName = JSON.stringify(prop);
16
- assertUsage(val !== notSerializable, `pageContext[${propName}] couldn't be serialized and, therefore, is missing on the client-side. Check the server logs for more information.`);
17
- assertIsDefined(pageContext, prop);
16
+ const propName = getPropAccessNotation(prop);
17
+ assertUsage(val !== notSerializable, `pageContext${propName} couldn't be serialized and, therefore, is missing on the client-side. Check the server logs for more information.`);
18
+ passToClientHint(pageContext, prop, propName);
18
19
  return val;
19
20
  }
20
21
  });
21
22
  }
22
- function assertIsDefined(pageContext, prop) {
23
- // We disable assertIsDefined() for the next attempt to read `prop`, because of how Vue's reactivity work. When changing a reactive object:
24
- // - Vue tries to read its old value first. This triggers a `assertIsDefined()` failure if e.g. `pageContextOldReactive.routeParams = pageContextNew.routeParams` and `pageContextOldReactive` has no `routeParams`.
25
- // - Vue seems to read __v_raw before reading the property
26
- if (globalObject.prev === prop || globalObject.prev === '__v_raw')
23
+ function passToClientHint(pageContext, prop, propName) {
24
+ if (handleVueReactivity(prop))
27
25
  return;
28
- ignoreNextRead(prop);
26
+ // `prop in pageContext` is the trick we use to know the passToClient value on the client-side, as we set a value to all passToClient props, even `undefined` ones:
27
+ // ```html
28
+ // <script id="vike_pageContext" type="application/json">{"pageProps":"!undefined"}</script>
29
+ // ```
29
30
  if (prop in pageContext)
30
31
  return;
31
- if (isExpected(prop))
32
+ if (isWhitelisted(prop))
32
33
  return;
33
- // - If no pageContext was fetchd from the server, then adding props to passToClient is useless.
34
- // - Showing a warning, even though no pageContext was fetched from the server, is actually erroneous as the client runtime cannot deduce the passToClient list.
34
+ // The trick described above (`prop in pageContext`) doesn't work if Vike doesn't fetch any pageContext from the server.
35
+ // - There would still be some value to show a warning, but it isn't worth it because of the confusion that the first recommendation (adding `prop` to `passToClient`) wouldn't actually remove the warning, and only the second recommendation (using `prop in pageContext` instead of `pageContext[prop]`) would work.
35
36
  if (!pageContext._hasPageContextFromServer)
36
37
  return;
37
- const propName = JSON.stringify(prop);
38
- /* This handling would be the clearest but, unfortunately, it's fundamentally problematic:
39
- * - It would force the pageContext value consumer to be synchronized with the pageContext value provider. For example, if vike-react wants to conditionally do something dependening on wehther some optional pageContext value was provided by some optional vike-react-* integration package.
40
- * - If a pageContext value is set by an optional hook, then it's expected that the value is undefined if the hook doesn't exist.
41
- const errMsg = `pageContext[${propName}] is \`undefined\` on the client-side. If it's defined on the server-side then add ${propName} to passToClient (https://vike.dev/passToClient), otherwise make sure your client-side hooks always define it (e.g. set it to \`null\` instead of \`undefined\`).`
42
- assertUsage(false, errMsg)
43
- */
44
- if (!pageContext._hasPageContextFromClient) {
45
- // We can safely assume that the property is missing in passToClient, because the server-side defines all passToClient properties even if they have an undefined value:
46
- // ```
47
- // <script id="vike_pageContext" type="application/json">{"_pageId":"/pages/admin","user":"!undefined","pageProps":"!undefined","title":"!undefined","abortReason":"!undefined","_urlRewrite":null}</script>
48
- // ```
49
- // Note how properties have "!undefined" values => we can tell whether an undefined pageContext value exists in passToClient.
50
- assertUsage(false, `pageContext[${propName}] isn't available on the client-side because ${propName} is missing in passToClient, see https://vike.dev/passToClient`);
38
+ const errMsg = `pageContext${propName} isn't defined on the client-side, see https://vike.dev/passToClient#error`;
39
+ if (
40
+ // TODO/next-major-release always make it an error.
41
+ // - Remove pageContext._hasPageContextFromClient logic (IIRC this is its only use case).
42
+ pageContext._hasPageContextFromClient) {
43
+ assertWarning(false, errMsg, { onlyOnce: false, showStackTrace: true });
51
44
  }
52
45
  else {
53
- // Do nothing, not even a warning, because we don't know whether the user expects that the pageContext value can be undefined. (E.g. a pageContext value that is defined by an optional hook.)
54
- // TODO/next-major-release make it an assertUsage()
55
- assertWarning(false, [
56
- `pageContext[${propName}] isn't defined on the client-side:`,
57
- `1. if it's defined by the server-side then add ${propName} to passToClient (https://vike.dev/passToClient), or`,
58
- `2. if it's expected that it may not be defined:`,
59
- ' ```js',
60
- ' // ❌ Replace code like this:',
61
- ` const val = pageContext[${propName}] ?? someDefaultValue`,
62
- ' // ✅ With that:',
63
- ` const val = ${propName} in pageContext ? pageContext[${propName}] : someDefaultValue`,
64
- ' ```',
65
- `See stack track below to find where pageContext[${propName}] is being accessed.`
66
- ].join('\n'), { showStackTrace: true, onlyOnce: false });
46
+ assertUsage(false, errMsg);
67
47
  }
68
48
  }
69
- const IGNORE_LIST = [
49
+ const WHITELIST = [
70
50
  'then',
71
- 'toJSON' // Vue tries to get `toJSON`
51
+ 'toJSON' // Vue triggers `toJSON`
72
52
  ];
73
- function isExpected(prop) {
74
- if (IGNORE_LIST.includes(prop))
53
+ function isWhitelisted(prop) {
54
+ if (WHITELIST.includes(prop))
75
55
  return true;
76
56
  if (typeof prop === 'symbol')
77
57
  return true; // Vue tries to access some symbols
@@ -81,9 +61,16 @@ function isExpected(prop) {
81
61
  return true; // Vue internals upon `reactive(pageContext)`
82
62
  return false;
83
63
  }
84
- function ignoreNextRead(prop) {
64
+ // Handle Vue's reactivity.
65
+ // When changing a reactive object:
66
+ // - Vue tries to read its old value first. This triggers a `assertIsDefined()` failure if e.g. `pageContextReactive.routeParams = pageContextNew.routeParams` and `pageContextReactive` has no `routeParams`.
67
+ // - Vue seems to read __v_raw before reading the property.
68
+ function handleVueReactivity(prop) {
69
+ if (globalObject.prev === prop || globalObject.prev === '__v_raw')
70
+ return true;
85
71
  globalObject.prev = prop;
86
72
  window.setTimeout(() => {
87
73
  globalObject.prev = undefined;
88
74
  }, 0);
75
+ return false;
89
76
  }
@@ -217,7 +217,7 @@ async function callOnBeforePrerenderStartHooks(prerenderContext, renderContext,
217
217
  if (doNotPrerenderList.find((p) => p.pageId === pageId)) {
218
218
  return;
219
219
  }
220
- const prerenderResult = await executeHook(() => hookFn(), { hookName, hookFilePath, hookTimeout });
220
+ const prerenderResult = await executeHook(() => hookFn(), { hookName, hookFilePath, hookTimeout }, null);
221
221
  const result = normalizeOnPrerenderHookResult(prerenderResult, hookFilePath, hookName);
222
222
  result.forEach(({ url, pageContext }) => {
223
223
  {
@@ -392,7 +392,7 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
392
392
  });
393
393
  return prerenderContext.pageContexts;
394
394
  }
395
- }), onPrerenderStartHook);
395
+ }), onPrerenderStartHook, null);
396
396
  if (result === null || result === undefined) {
397
397
  return;
398
398
  }
@@ -14,7 +14,7 @@ async function executeOnBeforeRenderAndDataHooks(pageContext) {
14
14
  }
15
15
  preparePageContextForUserConsumptionServerSide(pageContext);
16
16
  if (dataHook) {
17
- const hookResult = await executeHook(() => dataHook.hookFn(pageContext), dataHook);
17
+ const hookResult = await executeHook(() => dataHook.hookFn(pageContext), dataHook, pageContext);
18
18
  // Note: hookResult can be anything (e.g. an object) and is to be assigned to pageContext.data
19
19
  const pageContextFromHook = {
20
20
  data: hookResult
@@ -22,7 +22,7 @@ async function executeOnBeforeRenderAndDataHooks(pageContext) {
22
22
  Object.assign(pageContext, pageContextFromHook);
23
23
  }
24
24
  if (onBeforeRenderHook) {
25
- const hookResult = await executeHook(() => onBeforeRenderHook.hookFn(pageContext), onBeforeRenderHook);
25
+ const hookResult = await executeHook(() => onBeforeRenderHook.hookFn(pageContext), onBeforeRenderHook, pageContext);
26
26
  assertOnBeforeRenderHookReturn(hookResult, onBeforeRenderHook.hookFilePath);
27
27
  const pageContextFromHook = hookResult?.pageContext;
28
28
  Object.assign(pageContext, pageContextFromHook);
@@ -13,7 +13,7 @@ async function executeOnRenderHtmlHook(pageContext) {
13
13
  const { renderHook, hookFn } = getRenderHook(pageContext);
14
14
  objectAssign(pageContext, { _renderHook: renderHook });
15
15
  preparePageContextForUserConsumptionServerSide(pageContext);
16
- const hookReturnValue = await executeHook(() => hookFn(pageContext), renderHook);
16
+ const hookReturnValue = await executeHook(() => hookFn(pageContext), renderHook, pageContext);
17
17
  const { documentHtml, pageContextProvidedByRenderHook, pageContextPromise, injectFilter } = processHookReturnValue(hookReturnValue, renderHook);
18
18
  Object.assign(pageContext, pageContextProvidedByRenderHook);
19
19
  objectAssign(pageContext, { _pageContextPromise: pageContextPromise });
@@ -0,0 +1 @@
1
+ export { getPageContext } from './hooks/executeHook.js';
@@ -0,0 +1 @@
1
+ export { getPageContext } from './hooks/executeHook.js';
@@ -1,5 +1,9 @@
1
1
  export { executeHook };
2
+ export { getPageContext };
2
3
  export { isUserHookError };
4
+ import type { PageContextClient, PageContextServer } from '../types.js';
3
5
  import type { Hook, HookLoc } from './getHook.js';
6
+ type PageContextUnknown = null | Record<string, unknown>;
4
7
  declare function isUserHookError(err: unknown): false | HookLoc;
5
- declare function executeHook<T = unknown>(hookFnCaller: () => T, hook: Omit<Hook, 'hookFn'>): Promise<T>;
8
+ declare function executeHook<T = unknown>(hookFnCaller: () => T, hook: Omit<Hook, 'hookFn'>, pageContext: PageContextUnknown): Promise<T>;
9
+ declare function getPageContext<PageContext = PageContextClient | PageContextServer>(): PageContext;
@@ -1,18 +1,21 @@
1
1
  export { executeHook };
2
+ export { getPageContext };
2
3
  export { isUserHookError };
3
4
  import { getProjectError, assertWarning } from '../../utils/assert.js';
4
5
  import { getGlobalObject } from '../../utils/getGlobalObject.js';
5
6
  import { humanizeTime } from '../../utils/humanizeTime.js';
6
7
  import { isObject } from '../../utils/isObject.js';
8
+ import { isBrowser } from '../utils.js';
7
9
  const globalObject = getGlobalObject('utils/executeHook.ts', {
8
- userHookErrors: new WeakMap()
10
+ userHookErrors: new WeakMap(),
11
+ pageContext: null
9
12
  });
10
13
  function isUserHookError(err) {
11
14
  if (!isObject(err))
12
15
  return false;
13
16
  return globalObject.userHookErrors.get(err) ?? false;
14
17
  }
15
- function executeHook(hookFnCaller, hook) {
18
+ function executeHook(hookFnCaller, hook, pageContext) {
16
19
  const { hookName, hookFilePath, hookTimeout: { error: timeoutErr, warning: timeoutWarn } } = hook;
17
20
  let resolve;
18
21
  let reject;
@@ -43,6 +46,7 @@ function executeHook(hookFnCaller, hook) {
43
46
  }, timeoutErr);
44
47
  (async () => {
45
48
  try {
49
+ providePageContext(pageContext);
46
50
  const ret = await hookFnCaller();
47
51
  resolve(ret);
48
52
  }
@@ -58,3 +62,14 @@ function executeHook(hookFnCaller, hook) {
58
62
  function isNotDisabled(timeout) {
59
63
  return !!timeout && timeout !== Infinity;
60
64
  }
65
+ function getPageContext() {
66
+ return globalObject.pageContext;
67
+ }
68
+ function providePageContext(pageContext) {
69
+ globalObject.pageContext = pageContext;
70
+ if (!isBrowser()) {
71
+ process.nextTick(() => {
72
+ globalObject.pageContext = null;
73
+ });
74
+ }
75
+ }
@@ -21,7 +21,7 @@ async function executeGuardHook(pageContext, prepareForUserConsumption) {
21
21
  const res = prepareForUserConsumption(pageContext);
22
22
  if (res)
23
23
  pageContextForUserConsumption = res;
24
- const hookResult = await executeHook(() => guard(pageContextForUserConsumption), hook);
24
+ const hookResult = await executeHook(() => guard(pageContextForUserConsumption), hook, pageContext);
25
25
  assertUsage(hookResult === undefined, `${errIntro} ${hook.hookFilePath} returns a value, but guard() shouldn't return any value`);
26
26
  }
27
27
  function findPageGuard(pageId, pageFilesAll) {
@@ -36,7 +36,7 @@ async function getPageContextFromHook(onBeforeRouteHook, pageContext) {
36
36
  let hookReturn = onBeforeRouteHook.hookFn(pageContext);
37
37
  assertSyncRouting(hookReturn, `The onBeforeRoute() hook ${onBeforeRouteHook.hookFilePath}`);
38
38
  // TODO/v1-release: make executeOnBeforeRouteHook() and route() sync
39
- hookReturn = await executeHook(() => hookReturn, onBeforeRouteHook);
39
+ hookReturn = await executeHook(() => hookReturn, onBeforeRouteHook, pageContext);
40
40
  const errPrefix = `The onBeforeRoute() hook defined by ${onBeforeRouteHook.hookFilePath}`;
41
41
  assertUsage(hookReturn === null ||
42
42
  hookReturn === undefined ||
@@ -1,2 +1 @@
1
- export { getPropAccessNotation };
2
- declare function getPropAccessNotation(key: string): `.${string}` | `[${string}]`;
1
+ export declare function getPropAccessNotation(key: unknown): `.${string}` | `[${string}]`;
@@ -1,7 +1,3 @@
1
- export { getPropAccessNotation };
2
- function getPropAccessNotation(key) {
3
- return isKeyDotNotationCompatible(key) ? `.${key}` : `[${JSON.stringify(key)}]`;
4
- }
5
- function isKeyDotNotationCompatible(key) {
6
- return /^[a-z0-9\$_]+$/i.test(key);
1
+ export function getPropAccessNotation(key) {
2
+ return typeof key === 'string' && /^[a-z0-9\$_]+$/i.test(key) ? `.${key}` : `[${JSON.stringify(key)}]`;
7
3
  }
@@ -1,7 +1,7 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
- declare const PROJECT_VERSION: "0.4.171-commit-ea3808a";
3
+ declare const PROJECT_VERSION: "0.4.171-commit-e429162";
4
4
  declare const projectInfo: {
5
5
  projectName: "Vike";
6
- projectVersion: "0.4.171-commit-ea3808a";
6
+ projectVersion: "0.4.171-commit-e429162";
7
7
  };
@@ -1,6 +1,6 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
- const PROJECT_VERSION = '0.4.171-commit-ea3808a';
3
+ const PROJECT_VERSION = '0.4.171-commit-e429162';
4
4
  const projectInfo = {
5
5
  projectName: 'Vike',
6
6
  projectVersion: PROJECT_VERSION
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike",
3
- "version": "0.4.171-commit-ea3808a",
3
+ "version": "0.4.171-commit-e429162",
4
4
  "scripts": {
5
5
  "dev": "tsc --watch",
6
6
  "build": "rimraf dist/ && pnpm run build:esm && pnpm run build:cjs",
@@ -106,6 +106,15 @@
106
106
  "types": "./dist/esm/shared/abort.d.ts",
107
107
  "default": "./dist/esm/shared/abort.js"
108
108
  },
109
+ "./getPageContext": {
110
+ "worker": "./dist/esm/shared/getPageContext.js",
111
+ "edge-light": "./dist/esm/shared/getPageContext.js",
112
+ "require": "./dist/cjs/shared/getPageContext.js",
113
+ "node": "./dist/esm/shared/getPageContext.js",
114
+ "browser": "./dist/esm/shared/getPageContext.js",
115
+ "types": "./dist/esm/shared/getPageContext.d.ts",
116
+ "default": "./dist/esm/shared/getPageContext.js"
117
+ },
109
118
  "./__internal": {
110
119
  "require": "./dist/cjs/__internal/index.js",
111
120
  "node": "./dist/esm/__internal/index.js",