vike 0.4.235-commit-8f42b16 → 0.4.235-commit-d2ac38a

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 (40) hide show
  1. package/dist/cjs/node/runtime/globalContext.js +21 -6
  2. package/dist/cjs/node/runtime/html/serializeContext.js +58 -13
  3. package/dist/cjs/node/runtime/renderPage/createHttpResponse/getCacheControl.js +7 -7
  4. package/dist/cjs/node/runtime/renderPage/createHttpResponse.js +8 -5
  5. package/dist/cjs/node/runtime/renderPage/loadPageConfigsLazyServerSide.js +28 -2
  6. package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +1 -0
  7. package/dist/cjs/node/runtime/renderPage.js +1 -0
  8. package/dist/cjs/node/vite/shared/resolveVikeConfigInternal/configDefinitionsBuiltIn.js +4 -0
  9. package/dist/cjs/node/vite/shared/resolveVikeConfigInternal/filesystemRouting.js +4 -6
  10. package/dist/cjs/shared/createGlobalContextShared.js +20 -7
  11. package/dist/cjs/shared/route/loadPageRoutes.js +7 -1
  12. package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
  13. package/dist/esm/client/runtime-client-routing/getPageContextFromHooks.d.ts +8 -0
  14. package/dist/esm/client/runtime-client-routing/renderPageClientSide.d.ts +2 -0
  15. package/dist/esm/client/shared/createGetGlobalContextClient.d.ts +2 -2
  16. package/dist/esm/node/prerender/runPrerender.d.ts +2 -1
  17. package/dist/esm/node/runtime/globalContext.d.ts +14 -12
  18. package/dist/esm/node/runtime/globalContext.js +23 -8
  19. package/dist/esm/node/runtime/html/serializeContext.d.ts +7 -1
  20. package/dist/esm/node/runtime/html/serializeContext.js +58 -13
  21. package/dist/esm/node/runtime/renderPage/createHttpResponse/getCacheControl.d.ts +3 -3
  22. package/dist/esm/node/runtime/renderPage/createHttpResponse/getCacheControl.js +7 -7
  23. package/dist/esm/node/runtime/renderPage/createHttpResponse.d.ts +1 -0
  24. package/dist/esm/node/runtime/renderPage/createHttpResponse.js +8 -5
  25. package/dist/esm/node/runtime/renderPage/loadPageConfigsLazyServerSide.d.ts +8 -4
  26. package/dist/esm/node/runtime/renderPage/loadPageConfigsLazyServerSide.js +29 -3
  27. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +4 -2
  28. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +1 -0
  29. package/dist/esm/node/runtime/renderPage.js +1 -0
  30. package/dist/esm/node/vite/shared/resolveVikeConfigInternal/configDefinitionsBuiltIn.js +4 -0
  31. package/dist/esm/node/vite/shared/resolveVikeConfigInternal/filesystemRouting.js +4 -6
  32. package/dist/esm/shared/createGlobalContextShared.d.ts +3 -3
  33. package/dist/esm/shared/createGlobalContextShared.js +20 -7
  34. package/dist/esm/shared/route/loadPageRoutes.d.ts +5 -0
  35. package/dist/esm/shared/route/loadPageRoutes.js +7 -1
  36. package/dist/esm/types/Config.d.ts +9 -1
  37. package/dist/esm/types/PageContext.d.ts +8 -2
  38. package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
  39. package/dist/esm/utils/PROJECT_VERSION.js +1 -1
  40. package/package.json +1 -1
@@ -13,7 +13,7 @@ export { setGlobalContext_viteDevServer };
13
13
  export { setGlobalContext_viteConfig };
14
14
  export { setGlobalContext_isPrerendering };
15
15
  export { setGlobalContext_isProduction };
16
- export { setGlobalContext_buildEntry };
16
+ export { setGlobalContext_buildEntry }; // production entry
17
17
  export { clearGlobalContext };
18
18
  export { assertBuildInfo };
19
19
  export { updateUserFiles };
@@ -30,7 +30,7 @@ import { assert, onSetupRuntime, assertUsage, assertWarning, isPlainObject, obje
30
30
  import { importServerProductionEntry } from '@brillout/vite-plugin-server-entry/runtime';
31
31
  import { virtualFileIdEntryServer } from '../shared/virtualFiles/virtualFileEntry.js';
32
32
  import pc from '@brillout/picocolors';
33
- import { loadPageRoutes } from '../../shared/route/loadPageRoutes.js';
33
+ import { loadPageRoutes, loadPageRoutesSync } from '../../shared/route/loadPageRoutes.js';
34
34
  import { assertV1Design } from '../shared/assertV1Design.js';
35
35
  import { resolveBase } from '../shared/resolveBase.js';
36
36
  import { createGlobalContextShared, getGlobalContextSyncErrMsg, } from '../../shared/createGlobalContextShared.js';
@@ -39,7 +39,7 @@ import { logRuntimeError, logRuntimeInfo } from './loggerRuntime.js';
39
39
  import { getVikeConfigErrorBuild, setVikeConfigError } from '../shared/getVikeConfigError.js';
40
40
  import { hasAlreadyLogged } from './renderPage/isNewError.js';
41
41
  const debug = createDebugger('vike:globalContext');
42
- const globalObject = getGlobalObject('runtime/globalContext.ts', getInitialGlobalContext());
42
+ const globalObject = getGlobalObject('runtime/globalContext.ts', getInitialGlobalObject());
43
43
  // Trick to break down TypeScript circular dependency
44
44
  // https://chat.deepseek.com/a/chat/s/d7e9f90a-c7f3-4108-9cd5-4ad6caed3539
45
45
  const globalObjectTyped = globalObject;
@@ -232,6 +232,7 @@ function assertViteManifest(manifest) {
232
232
  async function loadBuildEntry(outDir) {
233
233
  debug('loadBuildEntry()');
234
234
  if (globalObject.globalContext) {
235
+ debug('loadBuildEntry() - already done');
235
236
  return;
236
237
  }
237
238
  if (!globalObject.buildEntry) {
@@ -257,6 +258,8 @@ async function loadBuildEntry(outDir) {
257
258
  globalObject.buildInfo = buildEntry.buildInfo;
258
259
  await setGlobalContext(buildEntry.virtualFileExports);
259
260
  }
261
+ // This is the production entry, see:
262
+ // https://github.com/vikejs/vike/blob/798e5465dc3e3e6723b38b601a50350c0a006fb8/packages/vike/node/vite/plugins/pluginBuild/pluginBuildEntry.ts#L47
260
263
  async function setGlobalContext_buildEntry(buildEntry) {
261
264
  debug('setGlobalContext_buildEntry()');
262
265
  setIsProduction(true);
@@ -266,6 +269,7 @@ async function setGlobalContext_buildEntry(buildEntry) {
266
269
  assert(globalObject.buildEntry); // ensure no infinite loop
267
270
  await loadBuildEntry();
268
271
  assertGlobalContextIsDefined();
272
+ debug('setGlobalContext_buildEntry() - done');
269
273
  }
270
274
  function assertBuildEntry(buildEntry) {
271
275
  assert(isObject(buildEntry));
@@ -362,18 +366,29 @@ async function updateUserFiles() {
362
366
  return onSuccess();
363
367
  }
364
368
  async function setGlobalContext(virtualFileExports) {
369
+ debug('setGlobalContext()');
365
370
  assert(!getVikeConfigErrorBuild());
366
- const globalContext = await createGlobalContextShared(virtualFileExports, globalObject, addGlobalContext);
371
+ const globalContext = await createGlobalContextShared(virtualFileExports, globalObject, addGlobalContextAsync, addGlobalContextSync);
367
372
  assertV1Design(
368
373
  // pageConfigs is PageConfigRuntime[] but assertV1Design() requires PageConfigBuildTime[]
369
374
  globalContext._pageConfigs.length > 0, globalContext._pageFilesAll);
370
375
  assertGlobalContextIsDefined();
371
376
  onSetupRuntime();
377
+ debug('setGlobalContext() - done');
372
378
  // Never actually used, only used for TypeScript `ReturnType<typeof setGlobalContext>`
373
379
  return globalContext;
374
380
  }
375
- async function addGlobalContext(globalContext) {
381
+ async function addGlobalContextAsync(globalContext) {
382
+ debug('addGlobalContextAsync()');
376
383
  const { pageRoutes, onBeforeRouteHook } = await loadPageRoutes(globalContext._pageFilesAll, globalContext._pageConfigs, globalContext._pageConfigGlobal, globalContext._allPageIds);
384
+ return addGlobalContextCommon(globalContext, pageRoutes, onBeforeRouteHook);
385
+ }
386
+ function addGlobalContextSync(globalContext) {
387
+ debug('addGlobalContextSync()');
388
+ const { pageRoutes, onBeforeRouteHook } = loadPageRoutesSync(globalContext._pageFilesAll, globalContext._pageConfigs, globalContext._pageConfigGlobal, globalContext._allPageIds);
389
+ return addGlobalContextCommon(globalContext, pageRoutes, onBeforeRouteHook);
390
+ }
391
+ function addGlobalContextCommon(globalContext, pageRoutes, onBeforeRouteHook) {
377
392
  const globalContextBase = {
378
393
  isClientSide: false,
379
394
  _pageRoutes: pageRoutes,
@@ -432,10 +447,10 @@ async function addGlobalContext(globalContext) {
432
447
  }
433
448
  function clearGlobalContext() {
434
449
  debug('clearGlobalContext()');
435
- objectReplace(globalObject, getInitialGlobalContext(), ['buildEntryPrevious']);
450
+ objectReplace(globalObject, getInitialGlobalObject(), ['buildEntryPrevious']);
436
451
  }
437
- function getInitialGlobalContext() {
438
- debug('getInitialGlobalContext()');
452
+ function getInitialGlobalObject() {
453
+ debug('getInitialGlobalObject()');
439
454
  const { promise: viteDevServerPromise, resolve: viteDevServerPromiseResolve } = genPromise();
440
455
  return {
441
456
  viteDevServerPromise,
@@ -2,19 +2,25 @@ export { getPageContextClientSerialized };
2
2
  export { getPageContextClientSerializedAbort };
3
3
  export { getGlobalContextClientSerialized };
4
4
  export type { PageContextSerialization };
5
+ export type { PassToClient };
5
6
  import type { UrlRedirect } from '../../../shared/route/abort.js';
6
7
  import type { GlobalContextServerInternal } from '../globalContext.js';
7
8
  type PageContextSerialization = {
8
9
  pageId: string;
9
10
  routeParams: Record<string, string>;
10
- _passToClient: string[];
11
+ _passToClient: PassToClient;
11
12
  is404: null | boolean;
12
13
  pageProps?: Record<string, unknown>;
13
14
  _pageContextInit: Record<string, unknown>;
14
15
  _globalContext: GlobalContextServerInternal;
16
+ isClientSideNavigation: boolean;
15
17
  };
16
18
  declare function getPageContextClientSerialized(pageContext: PageContextSerialization): string;
17
19
  declare function getGlobalContextClientSerialized(pageContext: PageContextSerialization): string;
20
+ type PassToClient = (string | {
21
+ prop: string;
22
+ once?: boolean;
23
+ })[];
18
24
  declare function getPageContextClientSerializedAbort(pageContext: Record<string, unknown> & ({
19
25
  _urlRedirect: UrlRedirect;
20
26
  } | {
@@ -27,20 +27,41 @@ const passToClientBuiltInPageContext = [
27
27
  const pageToClientBuiltInPageContextError = ['pageProps', 'is404', isServerSideError];
28
28
  function getPageContextClientSerialized(pageContext) {
29
29
  const passToClientPageContext = getPassToClientPageContext(pageContext);
30
- const pageContextClient = applyPassToClient(passToClientPageContext, pageContext);
31
- if (passToClientPageContext.some((prop) => getPropVal(pageContext._pageContextInit, prop))) {
30
+ const getObj = (passToClientEntry) => {
31
+ if (passToClientEntry.once)
32
+ return undefined; // pass it to client-side globalContext
33
+ return { obj: pageContext, objName: 'pageContext' };
34
+ };
35
+ const res = applyPassToClient(passToClientPageContext, getObj);
36
+ const pageContextClient = res.objClient;
37
+ const pageContextClientProps = res.objClientProps;
38
+ if (pageContextClientProps.some((prop) => getPropVal(pageContext._pageContextInit, prop))) {
32
39
  pageContextClient[pageContextInitIsPassedToClient] = true;
33
40
  }
34
- const pageContextClientSerialized = serializeObject(pageContextClient, 'pageContext', passToClientPageContext);
41
+ const pageContextClientSerialized = serializeObject(pageContextClient, passToClientPageContext, getObj);
35
42
  return pageContextClientSerialized;
36
43
  }
37
44
  function getGlobalContextClientSerialized(pageContext) {
38
45
  const passToClient = pageContext._passToClient;
39
- const globalContextClient = applyPassToClient(passToClient, pageContext._globalContext);
40
- const globalContextClientSerialized = serializeObject(globalContextClient, 'globalContext', passToClient);
46
+ const globalContext = pageContext._globalContext;
47
+ const getObj = ({ prop, once }) => {
48
+ if (once && getPropVal(pageContext, prop)) {
49
+ assert(typeof pageContext.isClientSideNavigation === 'boolean');
50
+ if (!pageContext.isClientSideNavigation) {
51
+ return { obj: pageContext, objName: 'pageContext' }; // pass it to client-side globalContext
52
+ }
53
+ else {
54
+ return undefined; // already passed to client-side
55
+ }
56
+ }
57
+ return { obj: globalContext, objName: 'globalContext' };
58
+ };
59
+ const res = applyPassToClient(passToClient, getObj);
60
+ const globalContextClient = res.objClient;
61
+ const globalContextClientSerialized = serializeObject(globalContextClient, passToClient, getObj);
41
62
  return globalContextClientSerialized;
42
63
  }
43
- function serializeObject(obj, objName, passToClient) {
64
+ function serializeObject(obj, passToClient, getObj) {
44
65
  let serialized;
45
66
  try {
46
67
  serialized = serializeValue(obj);
@@ -49,11 +70,15 @@ function serializeObject(obj, objName, passToClient) {
49
70
  const h = (s) => pc.cyan(s);
50
71
  let hasWarned = false;
51
72
  const propsNonSerializable = [];
52
- passToClient.forEach((prop) => {
73
+ passToClient.forEach((entry) => {
74
+ const entryNormalized = normalizePassToClientEntry(entry);
75
+ const { prop } = entryNormalized;
53
76
  const res = getPropVal(obj, prop);
54
77
  if (!res)
55
78
  return;
56
79
  const { value } = res;
80
+ const { objName } = getObj(entryNormalized) ?? {};
81
+ assert(objName);
57
82
  const varName = `${objName}${getPropKeys(prop).map(getPropAccessNotation).join('')}`;
58
83
  try {
59
84
  serializeValue(value, varName);
@@ -163,16 +188,36 @@ function getPageContextClientSerializedAbort(pageContext) {
163
188
  }
164
189
  return serializeValue(pageContext);
165
190
  }
166
- function applyPassToClient(passToClient, pageContext) {
167
- const pageContextClient = {};
168
- passToClient.forEach((prop) => {
191
+ function applyPassToClient(passToClient, getObj) {
192
+ const objClient = {};
193
+ const objClientProps = [];
194
+ passToClient.forEach((entry) => {
195
+ const entryNormalized = normalizePassToClientEntry(entry);
196
+ const { prop } = entryNormalized;
197
+ const { obj } = getObj(entryNormalized) ?? {};
198
+ if (!obj)
199
+ return;
169
200
  // Get value from pageContext
170
- const res = getPropVal(pageContext, prop);
201
+ const res = getPropVal(obj, prop);
171
202
  if (!res)
172
203
  return;
173
204
  const { value } = res;
174
205
  // Set value to pageContextClient
175
- setPropVal(pageContextClient, prop, value);
206
+ setPropVal(objClient, prop, value);
207
+ objClientProps.push(prop);
176
208
  });
177
- return pageContextClient;
209
+ return { objClient, objClientProps };
210
+ }
211
+ function normalizePassToClientEntry(entry) {
212
+ let once;
213
+ let prop;
214
+ if (typeof entry === 'string') {
215
+ prop = entry;
216
+ once = false;
217
+ }
218
+ else {
219
+ prop = entry.prop;
220
+ once = entry.once ?? false;
221
+ }
222
+ return { prop, once };
178
223
  }
@@ -1,5 +1,5 @@
1
1
  export { getCacheControl };
2
+ export { cacheControlDisable };
2
3
  import type { PageConfigRuntime } from '../../../../types/PageConfig.js';
3
- import type { HttpResponse } from '../createHttpResponse.js';
4
- type StatusCode = HttpResponse['statusCode'];
5
- declare function getCacheControl(pageId: string | null, pageConfigs: PageConfigRuntime[], statusCode: StatusCode): string;
4
+ declare const cacheControlDisable = "no-store, max-age=0";
5
+ declare function getCacheControl(pageId: string | null, pageConfigs: PageConfigRuntime[]): string;
@@ -1,13 +1,13 @@
1
+ // TODO/now: move
1
2
  export { getCacheControl };
3
+ export { cacheControlDisable };
2
4
  import { getPageConfig } from '../../../../shared/page-configs/helpers.js';
3
5
  import { getConfigValueRuntime } from '../../../../shared/page-configs/getConfigValueRuntime.js';
4
- const defaultValue = 'no-store, max-age=0';
5
- function getCacheControl(pageId, pageConfigs, statusCode) {
6
- // TO-DO/next-major-release: remove
6
+ const cacheControlDisable = 'no-store, max-age=0';
7
+ function getCacheControl(pageId, pageConfigs) {
8
+ // TO-DO/next-major-release: remove this line
7
9
  if (pageConfigs.length === 0)
8
- return defaultValue;
9
- if (statusCode > 499)
10
- return defaultValue;
10
+ return cacheControlDisable;
11
11
  if (pageId) {
12
12
  const pageConfig = getPageConfig(pageId, pageConfigs);
13
13
  const configValue = getConfigValueRuntime(pageConfig, 'cacheControl', 'string');
@@ -18,5 +18,5 @@ function getCacheControl(pageId, pageConfigs, statusCode) {
18
18
  // - Disabling caching by default is the safest strategy, because caching is problematic with authentication as described in https://github.com/vikejs/vike/issues/1275#issuecomment-1824366875
19
19
  // - Are there use cases when we don't need to disable caching?
20
20
  // - When there isn't any <script id="vike_pageContext" type="application/json"> then we can safely have caching. (We don't implement this exception because we're lazy and it's quite a rare situation.)
21
- return defaultValue;
21
+ return cacheControlDisable;
22
22
  }
@@ -28,6 +28,7 @@ declare function createHttpResponsePage(htmlRender: HtmlRender, renderHook: null
28
28
  __getPageAssets: GetPageAssets;
29
29
  _globalContext: GlobalContextServerInternal;
30
30
  abortStatusCode?: AbortStatusCode;
31
+ headersResponse?: Headers;
31
32
  }): Promise<HttpResponse>;
32
33
  declare function createHttpResponse404(errMsg404: string): HttpResponse;
33
34
  declare function createHttpResponseBaseIsMissing(urlOriginal: string, baseServer: string): HttpResponse;
@@ -9,8 +9,8 @@ import { assert, assertWarning, escapeHtml } from '../utils.js';
9
9
  import { getErrorPageId, isErrorPage } from '../../../shared/error-page.js';
10
10
  import { getHttpResponseBody, getHttpResponseBodyStreamHandlers } from './getHttpResponseBody.js';
11
11
  import { getEarlyHints } from './getEarlyHints.js';
12
- import { getCacheControl } from './createHttpResponse/getCacheControl.js';
13
12
  import { assertNoInfiniteHttpRedirect } from './createHttpResponse/assertNoInfiniteHttpRedirect.js';
13
+ import { cacheControlDisable } from './createHttpResponse/getCacheControl.js';
14
14
  async function createHttpResponsePage(htmlRender, renderHook, pageContext) {
15
15
  let statusCode = pageContext.abortStatusCode;
16
16
  if (!statusCode) {
@@ -29,10 +29,13 @@ async function createHttpResponsePage(htmlRender, renderHook, pageContext) {
29
29
  }
30
30
  const earlyHints = getEarlyHints(await pageContext.__getPageAssets());
31
31
  const headers = [];
32
- const cacheControl = getCacheControl(pageContext.pageId, pageContext._globalContext._pageConfigs, statusCode);
33
- if (cacheControl) {
34
- headers.push(['Cache-Control', cacheControl]);
35
- }
32
+ const headersResponse = pageContext.headersResponse || new Headers();
33
+ headersResponse.forEach((value, key) => {
34
+ headers.push([key, value]);
35
+ });
36
+ // An 5xx error page shouldn't be cached (it should be temporary)
37
+ if (statusCode >= 500)
38
+ headersResponse.set('Cache-Control', cacheControlDisable);
36
39
  return createHttpResponse(statusCode, 'text/html;charset=utf-8', headers, htmlRender, earlyHints, renderHook);
37
40
  }
38
41
  function createHttpResponse404(errMsg404) {
@@ -1,11 +1,13 @@
1
1
  export { loadPageConfigsLazyServerSideAndExecHook };
2
2
  export type { PageContext_loadPageConfigsLazyServerSide };
3
3
  export type { PageConfigsLazy };
4
+ import { type VikeConfigPublicPageLazy } from '../../../shared/getPageFiles.js';
4
5
  import { PromiseType } from '../utils.js';
5
6
  import { PageContextGetPageAssets, type PageAsset } from './getPageAssets.js';
6
7
  import { type PageContextDebugRouteMatches } from './debugPageFiles.js';
7
8
  import type { GlobalContextServerInternal } from '../globalContext.js';
8
9
  import { type PageContextExecHookServer } from './execHookServer.js';
10
+ import type { PassToClient } from '../html/serializeContext.js';
9
11
  type PageContextExecuteHook = Omit<PageContextExecHookServer, keyof Awaited<ReturnType<typeof loadPageConfigsLazyServerSide>>>;
10
12
  type PageContext_loadPageConfigsLazyServerSide = PageContextGetPageAssets & PageContextDebugRouteMatches & {
11
13
  pageId: string;
@@ -13,19 +15,21 @@ type PageContext_loadPageConfigsLazyServerSide = PageContextGetPageAssets & Page
13
15
  _globalContext: GlobalContextServerInternal;
14
16
  };
15
17
  type PageConfigsLazy = PromiseType<ReturnType<typeof loadPageConfigsLazyServerSide>>;
16
- declare function loadPageConfigsLazyServerSideAndExecHook<PageContext extends PageContext_loadPageConfigsLazyServerSide & PageContextExecuteHook>(pageContext: PageContext): Promise<PageContext & import("../../../shared/getPageFiles.js").VikeConfigPublicPageLazy & {
18
+ declare function loadPageConfigsLazyServerSideAndExecHook<PageContext extends PageContext_loadPageConfigsLazyServerSide & PageContextExecuteHook>(pageContext: PageContext): Promise<PageContext & VikeConfigPublicPageLazy & {
17
19
  Page: unknown;
18
20
  _isHtmlOnly: boolean;
19
- _passToClient: string[];
21
+ _passToClient: PassToClient;
20
22
  _pageFilePathsLoaded: string[];
23
+ headersResponse: Headers;
21
24
  } & {
22
25
  __getPageAssets: () => Promise<PageAsset[]>;
23
26
  }>;
24
- declare function loadPageConfigsLazyServerSide(pageContext: PageContext_loadPageConfigsLazyServerSide): Promise<import("../../../shared/getPageFiles.js").VikeConfigPublicPageLazy & {
27
+ declare function loadPageConfigsLazyServerSide(pageContext: PageContext_loadPageConfigsLazyServerSide): Promise<VikeConfigPublicPageLazy & {
25
28
  Page: unknown;
26
29
  _isHtmlOnly: boolean;
27
- _passToClient: string[];
30
+ _passToClient: PassToClient;
28
31
  _pageFilePathsLoaded: string[];
32
+ headersResponse: Headers;
29
33
  } & {
30
34
  __getPageAssets: () => Promise<PageAsset[]>;
31
35
  }>;
@@ -2,19 +2,22 @@ export { loadPageConfigsLazyServerSideAndExecHook };
2
2
  import { getPageFilesServerSide } from '../../../shared/getPageFiles.js';
3
3
  import { resolveVikeConfigPublicPageLazy } from '../../../shared/page-configs/resolveVikeConfigPublic.js';
4
4
  import { analyzePageClientSideInit } from '../../../shared/getPageFiles/analyzePageClientSide.js';
5
- import { assertUsage, assertWarning, hasProp, objectAssign, isArrayOfStrings } from '../utils.js';
5
+ import { assertUsage, assertWarning, hasProp, objectAssign } from '../utils.js';
6
6
  import { getPageAssets } from './getPageAssets.js';
7
7
  import { debugPageFiles } from './debugPageFiles.js';
8
8
  import { findPageConfig } from '../../../shared/page-configs/findPageConfig.js';
9
9
  import { analyzePage } from './analyzePage.js';
10
10
  import { loadConfigValues } from '../../../shared/page-configs/loadConfigValues.js';
11
11
  import { execHookServer } from './execHookServer.js';
12
+ import { getCacheControl } from './createHttpResponse/getCacheControl.js';
13
+ // TODO/now: rename?
12
14
  async function loadPageConfigsLazyServerSideAndExecHook(pageContext) {
13
15
  const pageContextAddendum = await loadPageConfigsLazyServerSide(pageContext);
14
16
  objectAssign(pageContext, pageContextAddendum);
15
17
  await execHookServer('onCreatePageContext', pageContext);
16
18
  return pageContext;
17
19
  }
20
+ // TODO/now: rename?
18
21
  async function loadPageConfigsLazyServerSide(pageContext) {
19
22
  const pageConfig = findPageConfig(pageContext._globalContext._pageConfigs, pageContext.pageId); // Make pageConfig globally available as pageContext._pageConfig ?
20
23
  const globalContext = pageContext._globalContext;
@@ -36,8 +39,9 @@ async function loadPageConfigsLazyServerSide(pageContext) {
36
39
  }
37
40
  else {
38
41
  configPublicPageLazy.from.configsCumulative.passToClient?.values.forEach((v) => {
39
- const { value, definedAt } = v;
40
- assertUsage(isArrayOfStrings(value), `+passToClient value defined at ${definedAt}${errMsg}`);
42
+ const { value } = v;
43
+ // const { definedAt } = v
44
+ // assertUsage(isArrayOfStrings(value), `+passToClient value defined at ${definedAt}${errMsg}`)
41
45
  passToClient.push(...value);
42
46
  });
43
47
  }
@@ -48,6 +52,7 @@ async function loadPageConfigsLazyServerSide(pageContext) {
48
52
  _isHtmlOnly: isHtmlOnly,
49
53
  _passToClient: passToClient,
50
54
  _pageFilePathsLoaded: pageFilesLoaded.map((p) => p.filePath),
55
+ headersResponse: resolveHeadersResponse(pageContext, pageContextAddendum),
51
56
  });
52
57
  objectAssign(pageContextAddendum, {
53
58
  __getPageAssets: async () => {
@@ -100,6 +105,7 @@ async function loadPageConfigsLazyServerSide(pageContext) {
100
105
  });
101
106
  return pageContextAddendum;
102
107
  }
108
+ // TODO/now: rename?
103
109
  async function loadPageUserFiles(pageFilesAll, pageConfig, pageConfigGlobal, pageId, isDev) {
104
110
  const pageFilesServerSide = getPageFilesServerSide(pageFilesAll, pageId);
105
111
  const pageConfigLoaded = !pageConfig ? null : await loadConfigValues(pageConfig, isDev);
@@ -110,3 +116,23 @@ async function loadPageUserFiles(pageFilesAll, pageConfig, pageConfigGlobal, pag
110
116
  pageFilesLoaded: pageFilesServerSide,
111
117
  };
112
118
  }
119
+ function resolveHeadersResponse(
120
+ // TODO/now: merge pageContextAddendum with pageContext
121
+ pageContext, pageContextAddendum) {
122
+ const headersResponse = mergeHeaders(pageContextAddendum.config.headersResponse);
123
+ if (!headersResponse.get('Cache-Control')) {
124
+ const cacheControl = getCacheControl(pageContext.pageId, pageContext._globalContext._pageConfigs);
125
+ if (cacheControl)
126
+ headersResponse.set('Cache-Control', cacheControl);
127
+ }
128
+ return headersResponse;
129
+ }
130
+ function mergeHeaders(headersList = []) {
131
+ const headersMerged = new Headers();
132
+ headersList.forEach((headers) => {
133
+ new Headers(headers).forEach((value, key) => {
134
+ headersMerged.append(key, value);
135
+ });
136
+ });
137
+ return headersMerged;
138
+ }
@@ -143,8 +143,9 @@ declare function prerenderPage(pageContext: PageContextCreated & PageConfigsLazy
143
143
  } & import("../../../shared/getPageFiles.js").VikeConfigPublicPageLazy & {
144
144
  Page: unknown;
145
145
  _isHtmlOnly: boolean;
146
- _passToClient: string[];
146
+ _passToClient: import("../html/serializeContext.js").PassToClient;
147
147
  _pageFilePathsLoaded: string[];
148
+ headersResponse: Headers;
148
149
  } & {
149
150
  __getPageAssets: () => Promise<import("./getPageAssets.js").PageAsset[]>;
150
151
  } & {
@@ -277,8 +278,9 @@ declare function prerenderPage(pageContext: PageContextCreated & PageConfigsLazy
277
278
  } & import("../../../shared/getPageFiles.js").VikeConfigPublicPageLazy & {
278
279
  Page: unknown;
279
280
  _isHtmlOnly: boolean;
280
- _passToClient: string[];
281
+ _passToClient: import("../html/serializeContext.js").PassToClient;
281
282
  _pageFilePathsLoaded: string[];
283
+ headersResponse: Headers;
282
284
  } & {
283
285
  __getPageAssets: () => Promise<import("./getPageAssets.js").PageAsset[]>;
284
286
  } & {
@@ -14,6 +14,7 @@ import { preparePageContextForPublicUsageServer } from './preparePageContextForP
14
14
  import { execHookGuard } from '../../../shared/route/execHookGuard.js';
15
15
  import pc from '@brillout/picocolors';
16
16
  import { isServerSideError } from '../../../shared/misc/isServerSideError.js';
17
+ // TODO/now: rename?
17
18
  async function renderPageAlreadyRouted(pageContext) {
18
19
  // pageContext.pageId can either be the:
19
20
  // - ID of the page matching the routing, or the
@@ -170,6 +170,7 @@ async function renderPageOnError(errNominalPage, pageContextBegin, pageContextNo
170
170
  return handleErrorWithoutErrorPage(pageContextErrorPageInit);
171
171
  }
172
172
  else {
173
+ // TODO/now: minor refactor
173
174
  objectAssign(pageContextErrorPageInit, { pageId: errorPageId });
174
175
  }
175
176
  }
@@ -210,6 +210,10 @@ const configDefinitionsBuiltIn = {
210
210
  env: { server: true },
211
211
  global: true,
212
212
  },
213
+ headersResponse: {
214
+ env: { server: true },
215
+ cumulative: true,
216
+ },
213
217
  };
214
218
  function getConfigEnv(configValueSources, configName) {
215
219
  const configValueSource = getConfigValueSource(configValueSources, configName);
@@ -32,12 +32,10 @@ function getFilesystemRouteString(locationId) {
32
32
  function getInheritanceRoot(locationId) {
33
33
  return getLogicalPath(locationId, [
34
34
  'renderer',
35
- // - Enable hooks defined by vike-{react,vue,solid} such as +onBeforeRenderClient to be defined at the root directory. In other words, avoid following error:
36
- // ```bash
37
- // [11:09:43.072][/test-preview.test.ts][npm run preview][stderr] Error: [vike][Wrong Usage] /+onBeforeRenderClient.ts sets the value of the config onBeforeRenderClient which is a custom config that is defined with https://vike.dev/meta at a path that doesn't apply to / — see https://vike.dev/config#inheritance
38
- // ```
39
- // - Not sure if it's a good idea? Could it make config inheritance confusing? Let's try for now and see how it goes.
40
- // - TO-DO/eventually: update docs https://github.com/vikejs/vike/blob/5fcdc4d5094f1a4dcbefc0b481cdd30a205aef2d/docs/pages/filesystem-routing/%2BPage.mdx?plain=1#L98
35
+ // Enable hooks defined by vike-{react,vue,solid} such as +onBeforeRenderClient to be defined at the root directory. In other words, avoid following error:
36
+ // ```bash
37
+ // [11:09:43.072][/test-preview.test.ts][npm run preview][stderr] Error: [vike][Wrong Usage] /+onBeforeRenderClient.ts sets the value of the config onBeforeRenderClient which is a custom config that is defined with https://vike.dev/meta at a path that doesn't apply to / — see https://vike.dev/config#inheritance
38
+ // ```
41
39
  'pages',
42
40
  ]);
43
41
  }
@@ -9,10 +9,10 @@ import type { GlobalContextServerInternal } from '../node/runtime/globalContext.
9
9
  import type { GlobalContextClientInternal } from '../client/runtime-client-routing/globalContext.js';
10
10
  import { type Hook } from './hooks/getHook.js';
11
11
  declare const getGlobalContextSyncErrMsg = "The global context isn't set yet, call getGlobalContextSync() later or use getGlobalContext() instead.";
12
- declare function createGlobalContextShared<GlobalContextAddendum extends object>(virtualFileExports: unknown, globalObject: {
12
+ declare function createGlobalContextShared<GlobalContextAddendum extends Record<string, any>>(virtualFileExports: unknown, globalObject: {
13
13
  globalContext?: Record<string, unknown>;
14
14
  onCreateGlobalContextHooks?: Hook[];
15
- }, addGlobalContext?: (globalContext: GlobalContextBase) => Promise<GlobalContextAddendum>): Promise<{
15
+ }, addGlobalContextAsync?: (globalContext: GlobalContextBase) => Promise<GlobalContextAddendum>, addGlobalContextSync?: (globalContext: GlobalContextBase) => GlobalContextAddendum): Promise<{
16
16
  /**
17
17
  * Useful for distinguishing `globalContext` from other objects and narrowing down TypeScript unions.
18
18
  *
@@ -35,7 +35,7 @@ declare function createGlobalContextShared<GlobalContextAddendum extends object>
35
35
  pages: {
36
36
  [k: string]: import("./page-configs/resolveVikeConfigPublic.js").VikeConfigPublicPageEager;
37
37
  };
38
- } & Awaited<GlobalContextAddendum>>;
38
+ } & GlobalContextAddendum>;
39
39
  type GlobalContextBasePublic = Pick<GlobalContextBase, 'config' | 'pages' | 'isGlobalContext'>;
40
40
  type GlobalContextBase = ReturnType<typeof createGlobalContextBase>;
41
41
  declare function createGlobalContextBase(virtualFileExports: unknown): {
@@ -7,10 +7,26 @@ import { execHookGlobal } from './hooks/execHook.js';
7
7
  import { prepareGlobalContextForPublicUsage } from './prepareGlobalContextForPublicUsage.js';
8
8
  import { getHookFromPageConfigGlobalCumulative } from './hooks/getHook.js';
9
9
  const getGlobalContextSyncErrMsg = "The global context isn't set yet, call getGlobalContextSync() later or use getGlobalContext() instead.";
10
- async function createGlobalContextShared(virtualFileExports, globalObject, addGlobalContext) {
10
+ async function createGlobalContextShared(virtualFileExports, globalObject, addGlobalContextAsync, addGlobalContextSync) {
11
11
  const globalContext = createGlobalContextBase(virtualFileExports);
12
- const globalContextAddendum = await addGlobalContext?.(globalContext);
13
- objectAssign(globalContext, globalContextAddendum);
12
+ let isNewGlobalContext;
13
+ if (!globalObject.globalContext) {
14
+ globalObject.globalContext = globalContext;
15
+ isNewGlobalContext = false;
16
+ }
17
+ else {
18
+ isNewGlobalContext = true;
19
+ }
20
+ if (addGlobalContextSync &&
21
+ // TODO/next-major-release: remove
22
+ globalContext._pageConfigs.length > 0) {
23
+ const globalContextAddendum = addGlobalContextSync?.(globalContext);
24
+ objectAssign(globalContext, globalContextAddendum);
25
+ }
26
+ else {
27
+ const globalContextAddendum = await addGlobalContextAsync?.(globalContext);
28
+ objectAssign(globalContext, globalContextAddendum);
29
+ }
14
30
  const onCreateGlobalContextHooks = getHookFromPageConfigGlobalCumulative(globalContext._pageConfigGlobal, 'onCreateGlobalContext');
15
31
  let hooksCalled = false;
16
32
  if (!hooksAreEqual(globalObject.onCreateGlobalContextHooks ?? [], onCreateGlobalContextHooks)) {
@@ -18,10 +34,7 @@ async function createGlobalContextShared(virtualFileExports, globalObject, addGl
18
34
  await execHookGlobal('onCreateGlobalContext', globalContext._pageConfigGlobal, null, globalContext, prepareGlobalContextForPublicUsage);
19
35
  hooksCalled = true;
20
36
  }
21
- if (!globalObject.globalContext) {
22
- globalObject.globalContext = globalContext;
23
- }
24
- else {
37
+ if (isNewGlobalContext) {
25
38
  // Singleton: ensure all `globalContext` user-land references are preserved & updated.
26
39
  if (hooksCalled) {
27
40
  objectReplace(globalObject.globalContext, globalContext);
@@ -1,4 +1,5 @@
1
1
  export { loadPageRoutes };
2
+ export { loadPageRoutesSync };
2
3
  export type { PageRoutes };
3
4
  export type { RouteType };
4
5
  import type { PageFile } from '../getPageFiles.js';
@@ -28,3 +29,7 @@ declare function loadPageRoutes(pageFilesAll: PageFile[], pageConfigs: PageConfi
28
29
  pageRoutes: PageRoutes;
29
30
  onBeforeRouteHook: null | Hook;
30
31
  }>;
32
+ declare function loadPageRoutesSync(pageFilesAll: PageFile[], pageConfigs: PageConfigRuntime[], pageConfigGlobal: PageConfigGlobalRuntime, allPageIds: string[]): {
33
+ pageRoutes: PageRoutes;
34
+ onBeforeRouteHook: null | Hook;
35
+ };
@@ -1,4 +1,5 @@
1
1
  export { loadPageRoutes };
2
+ export { loadPageRoutesSync };
2
3
  import { isErrorPageId } from '../error-page.js';
3
4
  import { assert, assertUsage, hasProp, slice } from './utils.js';
4
5
  import { deduceRouteStringFromFilesystemPath } from './deduceRouteStringFromFilesystemPath.js';
@@ -10,8 +11,13 @@ import { getHookFromPageConfigGlobal, getHookTimeoutDefault } from '../hooks/get
10
11
  async function loadPageRoutes(
11
12
  // Remove all arguments and use GlobalContextServerInternal instead?
12
13
  pageFilesAll, pageConfigs, pageConfigGlobal, allPageIds) {
13
- // TO-DO/next-major-release: remove & make this function sync
14
+ // TO-DO/next-major-release: remove this line, remove this function, rename loadPageRoutesSync() to loadPageRoutes()
14
15
  await Promise.all(pageFilesAll.filter((p) => p.fileType === '.page.route').map((p) => p.loadFile?.()));
16
+ return loadPageRoutesSync(pageFilesAll, pageConfigs, pageConfigGlobal, allPageIds);
17
+ }
18
+ function loadPageRoutesSync(
19
+ // Remove all arguments and use GlobalContextServerInternal instead?
20
+ pageFilesAll, pageConfigs, pageConfigGlobal, allPageIds) {
15
21
  const { onBeforeRouteHook, filesystemRoots } = getGlobalHooks(pageFilesAll, pageConfigs, pageConfigGlobal);
16
22
  const pageRoutes = getPageRoutes(filesystemRoots, pageFilesAll, pageConfigs, allPageIds);
17
23
  return { pageRoutes, onBeforeRouteHook };
@@ -44,6 +44,7 @@ import type { Vike, VikePackages } from './VikeNamespace.js';
44
44
  import type { HooksTimeoutProvidedByUser } from '../shared/hooks/getHook.js';
45
45
  import type { GlobalContext, PageContextClient, PageContextServer } from './PageContext.js';
46
46
  import type { InlineConfig } from 'vite';
47
+ import type { PassToClient } from '../node/runtime/html/serializeContext.js';
47
48
  type HookNameOld = HookName | HookNameOldDesign;
48
49
  type HookName = HookNamePage | HookNameGlobal;
49
50
  type HookNamePage = 'onHydrationEnd' | 'onBeforePrerenderStart' | 'onBeforeRender' | 'onPageTransitionStart' | 'onPageTransitionEnd' | 'onRenderHtml' | 'onRenderClient' | 'guard' | 'data' | 'onData' | 'route';
@@ -362,7 +363,7 @@ type ConfigBuiltIn = {
362
363
  *
363
364
  * https://vike.dev/passToClient
364
365
  */
365
- passToClient?: string[] | ImportString;
366
+ passToClient?: PassToClient | ImportString;
366
367
  /** Hook called when page is rendered on the client-side.
367
368
  *
368
369
  * https://vike.dev/onRenderClient
@@ -508,6 +509,12 @@ type ConfigBuiltIn = {
508
509
  * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
509
510
  */
510
511
  cacheControl?: string;
512
+ /**
513
+ * Add HTTP headers to the HTTP response.
514
+ *
515
+ * https://vike.dev/headers#response
516
+ */
517
+ headersResponse?: HeadersInit;
511
518
  /**
512
519
  * Make development/preview server available over LAN and public addresses.
513
520
  *
@@ -561,6 +568,7 @@ type ConfigBuiltInResolved = {
561
568
  redirects?: Record<string, string>[];
562
569
  prerender?: Exclude<Config['prerender'], ImportString | undefined>[];
563
570
  middleware?: Function[];
571
+ headersResponse?: HeadersInit[];
564
572
  };
565
573
  type ConfigMeta = Record<string, ConfigDefinition>;
566
574
  type ImportString = `import:${string}`;