vike 0.4.171-commit-978d69d → 0.4.171-commit-42245b5

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/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +2 -2
  2. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolvePointerImport.js +38 -4
  3. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +1 -1
  4. package/dist/cjs/node/plugin/shared/addSsrMiddleware.js +2 -1
  5. package/dist/cjs/node/runtime/html/renderHtml.js +19 -20
  6. package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +6 -5
  7. package/dist/cjs/node/runtime/renderPage.js +17 -13
  8. package/dist/cjs/node/runtime/utils.js +1 -0
  9. package/dist/cjs/shared/sortPageContext.js +4 -8
  10. package/dist/cjs/utils/escapeHtml.js +14 -0
  11. package/dist/cjs/utils/objectKeys.js +8 -4
  12. package/dist/cjs/utils/projectInfo.js +1 -1
  13. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/loadFileAtConfigTime.js +2 -2
  14. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/resolvePointerImport.js +39 -5
  15. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +1 -1
  16. package/dist/esm/node/plugin/shared/addSsrMiddleware.js +2 -1
  17. package/dist/esm/node/runtime/html/renderHtml.js +19 -20
  18. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +10 -5
  19. package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +6 -5
  20. package/dist/esm/node/runtime/renderPage.js +17 -13
  21. package/dist/esm/node/runtime/utils.d.ts +1 -0
  22. package/dist/esm/node/runtime/utils.js +1 -0
  23. package/dist/esm/shared/sortPageContext.js +4 -8
  24. package/dist/esm/utils/escapeHtml.d.ts +1 -0
  25. package/dist/esm/utils/escapeHtml.js +10 -0
  26. package/dist/esm/utils/objectKeys.d.ts +1 -3
  27. package/dist/esm/utils/objectKeys.js +8 -4
  28. package/dist/esm/utils/projectInfo.d.ts +2 -2
  29. package/dist/esm/utils/projectInfo.js +1 -1
  30. package/package.json +1 -1
@@ -13,7 +13,7 @@ const transformFileImports_js_1 = require("./transformFileImports.js");
13
13
  const getConfigFileExport_js_1 = require("../getConfigFileExport.js");
14
14
  const resolvePointerImport_js_1 = require("./resolvePointerImport.js");
15
15
  (0, utils_js_1.assertIsNotProductionRuntime)();
16
- // Load fake import
16
+ // Load pointer import
17
17
  async function loadImportedFile(import_, userRootDir, importedFilesLoaded) {
18
18
  const f = import_.filePathAbsoluteFilesystem;
19
19
  if (!importedFilesLoaded[f]) {
@@ -35,7 +35,7 @@ async function loadValueFile(interfaceValueFile, configName, userRootDir) {
35
35
  });
36
36
  }
37
37
  exports.loadValueFile = loadValueFile;
38
- // Load +config.js, including all its extends fake imports
38
+ // Load +config.js, including all its extends pointer imports
39
39
  async function loadConfigFile(configFilePath, userRootDir, visited, isExtensionConfig) {
40
40
  const { filePathAbsoluteFilesystem } = configFilePath;
41
41
  assertNoInfiniteLoop(visited, filePathAbsoluteFilesystem);
@@ -11,11 +11,19 @@ const path_1 = __importDefault(require("path"));
11
11
  const getFilePath_js_1 = require("../../../../shared/getFilePath.js");
12
12
  const filesEnvMap = new Map();
13
13
  function resolvePointerImportOfConfig(configValue, importerFilePath, userRootDir, configEnv, configName) {
14
- if (typeof configValue !== 'string')
15
- return null;
16
- const pointerImportData = (0, transformFileImports_js_1.parsePointerImportData)(configValue);
17
- if (!pointerImportData)
14
+ const pointerImportData = typeof configValue === 'string' && (0, transformFileImports_js_1.parsePointerImportData)(configValue);
15
+ if (!pointerImportData) {
16
+ // Temporary workaround to support document.title config.
17
+ // - We'll be able to remove that workaround once Vike supports custom nested configs (being able to define document.title and document.description as two different configs).
18
+ replaceStringValues(configValue, (str) => {
19
+ const pointerImportData = (0, transformFileImports_js_1.parsePointerImportData)(str);
20
+ if (pointerImportData) {
21
+ const filePath = resolvePointerImport(pointerImportData, importerFilePath, userRootDir);
22
+ return filePath.filePathAbsoluteVite;
23
+ }
24
+ });
18
25
  return null;
26
+ }
19
27
  const { importPath, exportName } = pointerImportData;
20
28
  const filePath = resolvePointerImport(pointerImportData, importerFilePath, userRootDir);
21
29
  const fileExportPathToShowToUser = exportName === 'default' || exportName === configName ? [] : [exportName];
@@ -127,3 +135,29 @@ function clearFilesEnvMap() {
127
135
  filesEnvMap.clear();
128
136
  }
129
137
  exports.clearFilesEnvMap = clearFilesEnvMap;
138
+ function replaceStringValues(obj, replacer) {
139
+ const visited = new WeakSet();
140
+ return traverse(obj, replacer);
141
+ function traverse(obj, replacer) {
142
+ // Check if the input is an object
143
+ if ((0, utils_js_1.isObject)(obj)) {
144
+ if (visited.has(obj))
145
+ return;
146
+ visited.add(obj);
147
+ for (const key in obj) {
148
+ if (!obj.hasOwnProperty(key))
149
+ continue;
150
+ const val = obj[key];
151
+ if (typeof val !== 'string') {
152
+ traverse(val, replacer);
153
+ }
154
+ else {
155
+ const replacement = replacer(val);
156
+ if (replacement) {
157
+ obj[key] = replacement;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
@@ -552,7 +552,7 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
552
552
  valueIsDefinedByValueFile: false,
553
553
  definedAtFilePath: pointerImport
554
554
  };
555
- // Load fake import
555
+ // Load pointer import
556
556
  if (isConfigEnv(configDef, configName) &&
557
557
  // The value of `extends` was already loaded and already used: we don't need the value of `extends` anymore
558
558
  configName !== 'extends') {
@@ -13,7 +13,8 @@ function addSsrMiddleware(middlewares) {
13
13
  const userAgent = headers['user-agent'];
14
14
  const pageContextInit = {
15
15
  urlOriginal: url,
16
- userAgent
16
+ userAgent,
17
+ headers
17
18
  };
18
19
  let pageContext;
19
20
  try {
@@ -170,35 +170,44 @@ async function renderTemplate(templateContent, pageContext) {
170
170
  setStream(templateVar);
171
171
  continue;
172
172
  }
173
- const getErrMsg = (typeText, end) => {
173
+ const getErrMsg = (msg) => {
174
174
  const { hookName, hookFilePath } = pageContext._renderHook;
175
175
  const nth = (i === 0 && '1st') || (i === 1 && '2nd') || (i === 2 && '3rd') || `${i}-th`;
176
- return [`The ${nth} HTML variable is ${typeText}, see ${hookName}() hook defined by ${hookFilePath}.`, end]
176
+ return [
177
+ `The ${nth} HTML variable is ${msg}`,
178
+ `The HTML was provided by the ${hookName}() hook at ${hookFilePath}.`
179
+ ]
177
180
  .filter(Boolean)
178
181
  .join(' ');
179
182
  };
180
- (0, utils_js_1.assertUsage)(!(0, utils_js_1.isPromise)(templateVar), getErrMsg('a promise', `Did you forget to ${picocolors_1.default.cyan('await')} the promise?`));
183
+ (0, utils_js_1.assertUsage)(!(0, utils_js_1.isPromise)(templateVar), getErrMsg(`a promise, did you forget to ${picocolors_1.default.cyan('await')} the promise?`));
181
184
  if (templateVar === undefined || templateVar === null) {
182
- (0, utils_js_1.assertWarning)(false, getErrMsg(`${picocolors_1.default.cyan(String(templateVar))} which will be converted to an empty string`, `Pass the empty string ${picocolors_1.default.cyan("''")} instead of ${picocolors_1.default.cyan(String(templateVar))} to remove this warning.`), { onlyOnce: false });
185
+ const msgVal = picocolors_1.default.cyan(String(templateVar));
186
+ const msgEmptyString = picocolors_1.default.cyan("''");
187
+ const msg = `${msgVal} which will be converted to an empty string. Pass the empty string ${msgEmptyString} instead of ${msgVal} to remove this warning.`;
188
+ (0, utils_js_1.assertWarning)(false, getErrMsg(msg), { onlyOnce: false });
183
189
  templateVar = '';
184
190
  }
185
191
  {
186
192
  const varType = typeof templateVar;
187
- const streamNote = ['boolean', 'number', 'bigint', 'symbol'].includes(varType)
188
- ? null
189
- : '(See https://vike.dev/streaming for HTML streaming.)';
190
- (0, utils_js_1.assertUsage)(varType === 'string', getErrMsg(picocolors_1.default.cyan(`typeof htmlVar === "${varType}"`), streamNote));
193
+ if (varType !== 'string') {
194
+ const msgType = picocolors_1.default.cyan(`typeof htmlVariable === "${varType}"`);
195
+ const msg = `${msgType} but a string or stream (https://vike.dev/streaming) is expected instead.`;
196
+ (0, utils_js_1.assertUsage)(false, getErrMsg(msg));
197
+ }
191
198
  }
192
199
  {
193
200
  const { isProduction } = (0, globalContext_js_1.getGlobalContext)();
194
201
  if ((0, utils_js_1.isHtml)(templateVar) &&
195
202
  // We don't show this warning in production because it's expected that some users may (un)willingly do some XSS injection: we avoid flooding the production logs.
196
203
  !isProduction) {
197
- (0, utils_js_1.assertWarning)(false, getErrMsg(`${picocolors_1.default.cyan(templateVar)} which seems to be HTML code`, 'Did you forget to wrap the value with dangerouslySkipEscape()?'), { onlyOnce: false });
204
+ const msgVal = picocolors_1.default.cyan(String(templateVar));
205
+ const msg = `${msgVal} which seems to be HTML code. Did you forget to wrap the value with dangerouslySkipEscape()?`;
206
+ (0, utils_js_1.assertWarning)(false, getErrMsg(msg), { onlyOnce: false });
198
207
  }
199
208
  }
200
209
  // Escape untrusted template variable
201
- addHtmlPart(escapeHtml(templateVar));
210
+ addHtmlPart((0, utils_js_1.escapeHtml)(templateVar));
202
211
  }
203
212
  (0, utils_js_1.assert)(templateStrings.length === templateVariables.length + 1);
204
213
  addHtmlPart(templateStrings[templateStrings.length - 1]);
@@ -214,16 +223,6 @@ async function renderTemplate(templateContent, pageContext) {
214
223
  htmlPartsEnd
215
224
  };
216
225
  }
217
- function escapeHtml(unsafeString) {
218
- // Source: https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript/6234804#6234804
219
- const safe = unsafeString
220
- .replace(/&/g, '&')
221
- .replace(/</g, '&lt;')
222
- .replace(/>/g, '&gt;')
223
- .replace(/"/g, '&quot;')
224
- .replace(/'/g, '&#039;');
225
- return safe;
226
- }
227
226
  async function getHtmlString(htmlRender) {
228
227
  if (typeof htmlRender === 'string') {
229
228
  return htmlRender;
@@ -109,9 +109,9 @@ async function prerender404Page(renderContext, pageContextInit_) {
109
109
  _debugRouteMatches: []
110
110
  };
111
111
  const pageContextInit = {
112
- urlOriginal: '/fake-404-url', // A URL is needed for `applyViteHtmlTransform`
113
- ...pageContextInit_
112
+ urlOriginal: '/fake-404-url' // A URL is needed for `applyViteHtmlTransform`
114
113
  };
114
+ (0, utils_js_1.objectAssign)(pageContextInit, pageContextInit_);
115
115
  {
116
116
  const pageContextInitEnhanced = getPageContextInitEnhanced(pageContextInit, renderContext);
117
117
  (0, utils_js_1.objectAssign)(pageContext, pageContextInitEnhanced);
@@ -127,8 +127,9 @@ function getPageContextInitEnhanced(pageContextInit, renderContext, { urlCompute
127
127
  } } = {}) {
128
128
  (0, utils_js_1.assert)(pageContextInit.urlOriginal);
129
129
  const globalContext = (0, globalContext_js_1.getGlobalContext)();
130
- const pageContextInitEnhanced = {
131
- ...pageContextInit,
130
+ const pageContextInitEnhanced = {};
131
+ (0, utils_js_1.objectAssign)(pageContextInitEnhanced, pageContextInit);
132
+ (0, utils_js_1.objectAssign)(pageContextInitEnhanced, {
132
133
  _objectCreatedByVike: true,
133
134
  // The following is defined on `pageContext` because we can eventually make these non-global (e.g. sot that two pages can have different includeAssetsImportedByServer settings)
134
135
  _baseServer: globalContext.baseServer,
@@ -145,7 +146,7 @@ function getPageContextInitEnhanced(pageContextInit, renderContext, { urlCompute
145
146
  _urlRewrite: urlRewrite,
146
147
  _urlHandler: urlHandler,
147
148
  isClientSideNavigation
148
- };
149
+ });
149
150
  (0, addUrlComputedProps_js_1.addUrlComputedProps)(pageContextInitEnhanced, !urlComputedPropsNonEnumerable);
150
151
  return pageContextInitEnhanced;
151
152
  }
@@ -289,12 +289,13 @@ async function renderPageNominal(pageContext) {
289
289
  async function getPageContextErrorPageInit(pageContextInit, errNominalPage, pageContextNominalPagePartial, renderContext, httpRequestId) {
290
290
  const pageContextInitEnhanced = getPageContextInitEnhancedSSR(pageContextInit, renderContext, null, httpRequestId);
291
291
  (0, utils_js_1.assert)(errNominalPage);
292
- const pageContext = {
293
- ...pageContextInitEnhanced,
292
+ const pageContext = {};
293
+ (0, utils_js_1.objectAssign)(pageContext, pageContextInitEnhanced);
294
+ (0, utils_js_1.objectAssign)(pageContext, {
294
295
  is404: false,
295
296
  errorWhileRendering: errNominalPage,
296
297
  routeParams: {}
297
- };
298
+ });
298
299
  (0, utils_js_1.objectAssign)(pageContext, {
299
300
  _debugRouteMatches: pageContextNominalPagePartial._debugRouteMatches || 'ROUTING_ERROR'
300
301
  });
@@ -346,7 +347,9 @@ function normalizeUrl(pageContextInit, httpRequestId) {
346
347
  return null;
347
348
  (0, loggerRuntime_js_1.logRuntimeInfo)?.(`URL normalized from ${picocolors_1.default.cyan(urlOriginal)} to ${picocolors_1.default.cyan(urlNormalized)} (https://vike.dev/url-normalization)`, httpRequestId, 'info');
348
349
  const httpResponse = (0, createHttpResponseObject_js_1.createHttpResponseObjectRedirect)({ url: urlNormalized, statusCode: 301 }, pageContextInit.urlOriginal);
349
- const pageContextHttpResponse = { ...pageContextInit, httpResponse };
350
+ const pageContextHttpResponse = {};
351
+ (0, utils_js_1.objectAssign)(pageContextHttpResponse, pageContextInit);
352
+ (0, utils_js_1.objectAssign)(pageContextHttpResponse, { httpResponse });
350
353
  return pageContextHttpResponse;
351
354
  }
352
355
  function getPermanentRedirect(pageContextInit, httpRequestId) {
@@ -381,7 +384,9 @@ function getPermanentRedirect(pageContextInit, httpRequestId) {
381
384
  }
382
385
  (0, loggerRuntime_js_1.logRuntimeInfo)?.(`Permanent redirect defined by your config.redirects (https://vike.dev/redirects)`, httpRequestId, 'info');
383
386
  const httpResponse = (0, createHttpResponseObject_js_1.createHttpResponseObjectRedirect)({ url: urlTarget, statusCode: 301 }, urlWithoutBase);
384
- const pageContextHttpResponse = { ...pageContextInit, httpResponse };
387
+ const pageContextHttpResponse = {};
388
+ (0, utils_js_1.objectAssign)(pageContextHttpResponse, pageContextInit);
389
+ (0, utils_js_1.objectAssign)(pageContextHttpResponse, { httpResponse });
385
390
  return pageContextHttpResponse;
386
391
  }
387
392
  async function handleAbortError(errAbort, pageContextsFromRewrite, pageContextInit,
@@ -397,11 +402,11 @@ pageContextNominalPageInit, httpRequestId, renderContext, pageContextErrorPageIn
397
402
  (0, utils_js_1.assert)(abortCall);
398
403
  (0, utils_js_1.assertUsage)(errorPageId, `You called ${picocolors_1.default.cyan(abortCall)} but you didn't define an error page, make sure to define one https://vike.dev/error-page`);
399
404
  const pageContext = {
400
- _pageId: errorPageId,
401
- ...pageContextAbort,
402
- ...pageContextErrorPageInit,
403
- ...renderContext
405
+ _pageId: errorPageId
404
406
  };
407
+ (0, utils_js_1.objectAssign)(pageContext, pageContextAbort);
408
+ (0, utils_js_1.objectAssign)(pageContext, pageContextErrorPageInit);
409
+ (0, utils_js_1.objectAssign)(pageContext, renderContext);
405
410
  (0, utils_js_1.objectAssign)(pageContext, await (0, loadUserFilesServerSide_js_1.loadUserFilesServerSide)(pageContext));
406
411
  // We include pageContextInit: we don't only serialize pageContextAbort because the error page may need to access pageContextInit
407
412
  pageContextSerialized = (0, serializePageContextClientSide_js_1.serializePageContextClientSide)(pageContext);
@@ -422,10 +427,9 @@ pageContextNominalPageInit, httpRequestId, renderContext, pageContextErrorPageIn
422
427
  return { pageContextReturn };
423
428
  }
424
429
  if (pageContextAbort._urlRedirect) {
425
- const pageContextReturn = {
426
- ...pageContextInit,
427
- ...pageContextAbort
428
- };
430
+ const pageContextReturn = {};
431
+ (0, utils_js_1.objectAssign)(pageContextReturn, pageContextInit);
432
+ (0, utils_js_1.objectAssign)(pageContextReturn, pageContextAbort);
429
433
  const httpResponse = (0, createHttpResponseObject_js_1.createHttpResponseObjectRedirect)(pageContextAbort._urlRedirect, (() => {
430
434
  const { pathname, searchOriginal } = pageContextNominalPageInit.urlParsed;
431
435
  const urlLogical = (0, utils_js_1.createUrlFromComponents)(null, pathname, searchOriginal,
@@ -68,3 +68,4 @@ __exportStar(require("../../utils/truncateString.js"), exports);
68
68
  __exportStar(require("../../utils/formatHintLog.js"), exports);
69
69
  __exportStar(require("../../utils/joinEnglish.js"), exports);
70
70
  __exportStar(require("../../utils/isArrayOfStrings.js"), exports);
71
+ __exportStar(require("../../utils/escapeHtml.js"), exports);
@@ -4,14 +4,10 @@ exports.sortPageContext = void 0;
4
4
  const utils_js_1 = require("./utils.js");
5
5
  // Sort `pageContext` keys alphabetically, in order to make reading `console.log(pageContext)` easier
6
6
  function sortPageContext(pageContext) {
7
- const entries = Object.entries(pageContext);
8
- for (const key in pageContext) {
7
+ let descriptors = Object.getOwnPropertyDescriptors(pageContext);
8
+ for (const key of Object.keys(pageContext))
9
9
  delete pageContext[key];
10
- }
11
- entries
12
- .sort(([key1], [key2]) => (0, utils_js_1.compareString)(key1, key2))
13
- .forEach(([key, val]) => {
14
- pageContext[key] = val;
15
- });
10
+ descriptors = Object.fromEntries(Object.entries(descriptors).sort(([key1], [key2]) => (0, utils_js_1.compareString)(key1, key2)));
11
+ Object.defineProperties(pageContext, descriptors);
16
12
  }
17
13
  exports.sortPageContext = sortPageContext;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.escapeHtml = void 0;
4
+ // Copied from https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript/6234804#6234804
5
+ function escapeHtml(unsafeString) {
6
+ const safe = unsafeString
7
+ .replace(/&/g, '&amp;')
8
+ .replace(/</g, '&lt;')
9
+ .replace(/>/g, '&gt;')
10
+ .replace(/"/g, '&quot;')
11
+ .replace(/'/g, '&#039;');
12
+ return safe;
13
+ }
14
+ exports.escapeHtml = escapeHtml;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.objectKeys = exports.objectFromEntries = exports.objectEntries = void 0;
4
+ // export { forEach }
4
5
  // https://stackoverflow.com/questions/60141960/typescript-key-value-relation-preserving-object-entries-type/75337277#75337277
5
6
  /** Same as Object.entries() but with type inference */
6
7
  function objectEntries(obj) {
@@ -19,8 +20,11 @@ function objectKeys(obj) {
19
20
  return Object.keys(obj);
20
21
  }
21
22
  exports.objectKeys = objectKeys;
22
- /*
23
- function objectKeys2<T extends Record<string, unknown>>(obj: T): Array<keyof T> {
24
- return Object.keys(obj)
23
+ /* Not used yet, but can be quite useful.
24
+ function forEach<Obj extends object>(
25
+ obj: Obj,
26
+ iterator: <Key extends keyof Obj>(key: Key, val: Obj[Key]) => void
27
+ ): void {
28
+ Object.entries(obj).forEach(([key, val]) => iterator(key as keyof Obj, val))
25
29
  }
26
- */
30
+ //*/
@@ -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-978d69d';
4
+ const PROJECT_VERSION = '0.4.171-commit-42245b5';
5
5
  exports.PROJECT_VERSION = PROJECT_VERSION;
6
6
  const projectInfo = {
7
7
  projectName: 'Vike',
@@ -10,7 +10,7 @@ import { parsePointerImportData } from './transformFileImports.js';
10
10
  import { getConfigFileExport } from '../getConfigFileExport.js';
11
11
  import { resolvePointerImport } from './resolvePointerImport.js';
12
12
  assertIsNotProductionRuntime();
13
- // Load fake import
13
+ // Load pointer import
14
14
  async function loadImportedFile(import_, userRootDir, importedFilesLoaded) {
15
15
  const f = import_.filePathAbsoluteFilesystem;
16
16
  if (!importedFilesLoaded[f]) {
@@ -30,7 +30,7 @@ async function loadValueFile(interfaceValueFile, configName, userRootDir) {
30
30
  interfaceValueFile.fileExportsByConfigName[configName_] = { configValue };
31
31
  });
32
32
  }
33
- // Load +config.js, including all its extends fake imports
33
+ // Load +config.js, including all its extends pointer imports
34
34
  async function loadConfigFile(configFilePath, userRootDir, visited, isExtensionConfig) {
35
35
  const { filePathAbsoluteFilesystem } = configFilePath;
36
36
  assertNoInfiniteLoop(visited, filePathAbsoluteFilesystem);
@@ -2,17 +2,25 @@ export { resolvePointerImportOfConfig };
2
2
  export { resolvePointerImport };
3
3
  export { clearFilesEnvMap };
4
4
  import pc from '@brillout/picocolors';
5
- import { assert, assertIsNpmPackageImport, assertPosixPath, assertUsage, deepEqual, isPathFilesystemAbsolute, requireResolve } from '../../../../utils.js';
5
+ import { assert, assertIsNpmPackageImport, assertPosixPath, assertUsage, deepEqual, isObject, isPathFilesystemAbsolute, requireResolve } from '../../../../utils.js';
6
6
  import { parsePointerImportData } from './transformFileImports.js';
7
7
  import path from 'path';
8
8
  import { getFilePathAbsoluteUserRootDir, getFilePathResolved, getFilePathUnresolved } from '../../../../shared/getFilePath.js';
9
9
  const filesEnvMap = new Map();
10
10
  function resolvePointerImportOfConfig(configValue, importerFilePath, userRootDir, configEnv, configName) {
11
- if (typeof configValue !== 'string')
12
- return null;
13
- const pointerImportData = parsePointerImportData(configValue);
14
- if (!pointerImportData)
11
+ const pointerImportData = typeof configValue === 'string' && parsePointerImportData(configValue);
12
+ if (!pointerImportData) {
13
+ // Temporary workaround to support document.title config.
14
+ // - We'll be able to remove that workaround once Vike supports custom nested configs (being able to define document.title and document.description as two different configs).
15
+ replaceStringValues(configValue, (str) => {
16
+ const pointerImportData = parsePointerImportData(str);
17
+ if (pointerImportData) {
18
+ const filePath = resolvePointerImport(pointerImportData, importerFilePath, userRootDir);
19
+ return filePath.filePathAbsoluteVite;
20
+ }
21
+ });
15
22
  return null;
23
+ }
16
24
  const { importPath, exportName } = pointerImportData;
17
25
  const filePath = resolvePointerImport(pointerImportData, importerFilePath, userRootDir);
18
26
  const fileExportPathToShowToUser = exportName === 'default' || exportName === configName ? [] : [exportName];
@@ -121,3 +129,29 @@ function assertFileEnv(filePathAbsoluteFilesystem, importPath, configEnv, config
121
129
  function clearFilesEnvMap() {
122
130
  filesEnvMap.clear();
123
131
  }
132
+ function replaceStringValues(obj, replacer) {
133
+ const visited = new WeakSet();
134
+ return traverse(obj, replacer);
135
+ function traverse(obj, replacer) {
136
+ // Check if the input is an object
137
+ if (isObject(obj)) {
138
+ if (visited.has(obj))
139
+ return;
140
+ visited.add(obj);
141
+ for (const key in obj) {
142
+ if (!obj.hasOwnProperty(key))
143
+ continue;
144
+ const val = obj[key];
145
+ if (typeof val !== 'string') {
146
+ traverse(val, replacer);
147
+ }
148
+ else {
149
+ const replacement = replacer(val);
150
+ if (replacement) {
151
+ obj[key] = replacement;
152
+ }
153
+ }
154
+ }
155
+ }
156
+ }
157
+ }
@@ -547,7 +547,7 @@ async function getConfigValueSource(configName, interfaceFile, configDef, userRo
547
547
  valueIsDefinedByValueFile: false,
548
548
  definedAtFilePath: pointerImport
549
549
  };
550
- // Load fake import
550
+ // Load pointer import
551
551
  if (isConfigEnv(configDef, configName) &&
552
552
  // The value of `extends` was already loaded and already used: we don't need the value of `extends` anymore
553
553
  configName !== 'extends') {
@@ -11,7 +11,8 @@ function addSsrMiddleware(middlewares) {
11
11
  const userAgent = headers['user-agent'];
12
12
  const pageContextInit = {
13
13
  urlOriginal: url,
14
- userAgent
14
+ userAgent,
15
+ headers
15
16
  };
16
17
  let pageContext;
17
18
  try {
@@ -3,7 +3,7 @@ export { dangerouslySkipEscape };
3
3
  export { renderDocumentHtml };
4
4
  export { isDocumentHtml };
5
5
  export { getHtmlString };
6
- import { assert, assertUsage, assertWarning, checkType, hasProp, isHtml, isPromise, objectAssign } from '../utils.js';
6
+ import { assert, assertUsage, assertWarning, checkType, escapeHtml, hasProp, isHtml, isPromise, objectAssign } from '../utils.js';
7
7
  import { injectHtmlTagsToString, injectHtmlTagsToStream } from './injectAssets.js';
8
8
  import { processStream, isStream, streamToString } from './stream.js';
9
9
  import { isStreamReactStreaming } from './stream/react-streaming.js';
@@ -165,31 +165,40 @@ async function renderTemplate(templateContent, pageContext) {
165
165
  setStream(templateVar);
166
166
  continue;
167
167
  }
168
- const getErrMsg = (typeText, end) => {
168
+ const getErrMsg = (msg) => {
169
169
  const { hookName, hookFilePath } = pageContext._renderHook;
170
170
  const nth = (i === 0 && '1st') || (i === 1 && '2nd') || (i === 2 && '3rd') || `${i}-th`;
171
- return [`The ${nth} HTML variable is ${typeText}, see ${hookName}() hook defined by ${hookFilePath}.`, end]
171
+ return [
172
+ `The ${nth} HTML variable is ${msg}`,
173
+ `The HTML was provided by the ${hookName}() hook at ${hookFilePath}.`
174
+ ]
172
175
  .filter(Boolean)
173
176
  .join(' ');
174
177
  };
175
- assertUsage(!isPromise(templateVar), getErrMsg('a promise', `Did you forget to ${pc.cyan('await')} the promise?`));
178
+ assertUsage(!isPromise(templateVar), getErrMsg(`a promise, did you forget to ${pc.cyan('await')} the promise?`));
176
179
  if (templateVar === undefined || templateVar === null) {
177
- assertWarning(false, getErrMsg(`${pc.cyan(String(templateVar))} which will be converted to an empty string`, `Pass the empty string ${pc.cyan("''")} instead of ${pc.cyan(String(templateVar))} to remove this warning.`), { onlyOnce: false });
180
+ const msgVal = pc.cyan(String(templateVar));
181
+ const msgEmptyString = pc.cyan("''");
182
+ const msg = `${msgVal} which will be converted to an empty string. Pass the empty string ${msgEmptyString} instead of ${msgVal} to remove this warning.`;
183
+ assertWarning(false, getErrMsg(msg), { onlyOnce: false });
178
184
  templateVar = '';
179
185
  }
180
186
  {
181
187
  const varType = typeof templateVar;
182
- const streamNote = ['boolean', 'number', 'bigint', 'symbol'].includes(varType)
183
- ? null
184
- : '(See https://vike.dev/streaming for HTML streaming.)';
185
- assertUsage(varType === 'string', getErrMsg(pc.cyan(`typeof htmlVar === "${varType}"`), streamNote));
188
+ if (varType !== 'string') {
189
+ const msgType = pc.cyan(`typeof htmlVariable === "${varType}"`);
190
+ const msg = `${msgType} but a string or stream (https://vike.dev/streaming) is expected instead.`;
191
+ assertUsage(false, getErrMsg(msg));
192
+ }
186
193
  }
187
194
  {
188
195
  const { isProduction } = getGlobalContext();
189
196
  if (isHtml(templateVar) &&
190
197
  // We don't show this warning in production because it's expected that some users may (un)willingly do some XSS injection: we avoid flooding the production logs.
191
198
  !isProduction) {
192
- assertWarning(false, getErrMsg(`${pc.cyan(templateVar)} which seems to be HTML code`, 'Did you forget to wrap the value with dangerouslySkipEscape()?'), { onlyOnce: false });
199
+ const msgVal = pc.cyan(String(templateVar));
200
+ const msg = `${msgVal} which seems to be HTML code. Did you forget to wrap the value with dangerouslySkipEscape()?`;
201
+ assertWarning(false, getErrMsg(msg), { onlyOnce: false });
193
202
  }
194
203
  }
195
204
  // Escape untrusted template variable
@@ -209,16 +218,6 @@ async function renderTemplate(templateContent, pageContext) {
209
218
  htmlPartsEnd
210
219
  };
211
220
  }
212
- function escapeHtml(unsafeString) {
213
- // Source: https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript/6234804#6234804
214
- const safe = unsafeString
215
- .replace(/&/g, '&amp;')
216
- .replace(/</g, '&lt;')
217
- .replace(/>/g, '&gt;')
218
- .replace(/"/g, '&quot;')
219
- .replace(/'/g, '&#039;');
220
- return safe;
221
- }
222
221
  async function getHtmlString(htmlRender) {
223
222
  if (typeof htmlRender === 'string') {
224
223
  return htmlRender;
@@ -37,6 +37,8 @@ declare function prerenderPage(pageContext: PageContextInitEnhanced & PageFiles
37
37
  documentHtml: string;
38
38
  pageContextSerialized: null;
39
39
  pageContext: {
40
+ urlOriginal: string;
41
+ } & {
40
42
  _objectCreatedByVike: boolean;
41
43
  _baseServer: string;
42
44
  _baseAssets: string | null;
@@ -53,7 +55,6 @@ declare function prerenderPage(pageContext: PageContextInitEnhanced & PageFiles
53
55
  _urlRewrite: string | null;
54
56
  _urlHandler: ((url: string) => string) | null;
55
57
  isClientSideNavigation: boolean;
56
- urlOriginal: string;
57
58
  } & import("../../../shared/addUrlComputedProps.js").PageContextUrlComputedPropsClient & {
58
59
  _urlRewrite: string | null;
59
60
  } & {
@@ -87,6 +88,8 @@ declare function prerenderPage(pageContext: PageContextInitEnhanced & PageFiles
87
88
  documentHtml: string;
88
89
  pageContextSerialized: string;
89
90
  pageContext: {
91
+ urlOriginal: string;
92
+ } & {
90
93
  _objectCreatedByVike: boolean;
91
94
  _baseServer: string;
92
95
  _baseAssets: string | null;
@@ -103,7 +106,6 @@ declare function prerenderPage(pageContext: PageContextInitEnhanced & PageFiles
103
106
  _urlRewrite: string | null;
104
107
  _urlHandler: ((url: string) => string) | null;
105
108
  isClientSideNavigation: boolean;
106
- urlOriginal: string;
107
109
  } & import("../../../shared/addUrlComputedProps.js").PageContextUrlComputedPropsClient & {
108
110
  _urlRewrite: string | null;
109
111
  } & {
@@ -138,6 +140,8 @@ declare function prerender404Page(renderContext: RenderContext, pageContextInit_
138
140
  documentHtml: string;
139
141
  pageContextSerialized: null;
140
142
  pageContext: {
143
+ urlOriginal: string;
144
+ } & {
141
145
  _objectCreatedByVike: boolean;
142
146
  _baseServer: string;
143
147
  _baseAssets: string | null;
@@ -154,7 +158,6 @@ declare function prerender404Page(renderContext: RenderContext, pageContextInit_
154
158
  _urlRewrite: string | null;
155
159
  _urlHandler: ((url: string) => string) | null;
156
160
  isClientSideNavigation: boolean;
157
- urlOriginal: string;
158
161
  } & import("../../../shared/addUrlComputedProps.js").PageContextUrlComputedPropsClient & {
159
162
  _urlRewrite: string | null;
160
163
  } & {
@@ -188,6 +191,8 @@ declare function prerender404Page(renderContext: RenderContext, pageContextInit_
188
191
  documentHtml: string;
189
192
  pageContextSerialized: string;
190
193
  pageContext: {
194
+ urlOriginal: string;
195
+ } & {
191
196
  _objectCreatedByVike: boolean;
192
197
  _baseServer: string;
193
198
  _baseAssets: string | null;
@@ -204,7 +209,6 @@ declare function prerender404Page(renderContext: RenderContext, pageContextInit_
204
209
  _urlRewrite: string | null;
205
210
  _urlHandler: ((url: string) => string) | null;
206
211
  isClientSideNavigation: boolean;
207
- urlOriginal: string;
208
212
  } & import("../../../shared/addUrlComputedProps.js").PageContextUrlComputedPropsClient & {
209
213
  _urlRewrite: string | null;
210
214
  } & {
@@ -246,6 +250,8 @@ declare function getPageContextInitEnhanced(pageContextInit: {
246
250
  isClientSideNavigation: boolean;
247
251
  };
248
252
  }): {
253
+ urlOriginal: string;
254
+ } & {
249
255
  _objectCreatedByVike: boolean;
250
256
  _baseServer: string;
251
257
  _baseAssets: string | null;
@@ -262,7 +268,6 @@ declare function getPageContextInitEnhanced(pageContextInit: {
262
268
  _urlRewrite: string | null;
263
269
  _urlHandler: ((url: string) => string) | null;
264
270
  isClientSideNavigation: boolean;
265
- urlOriginal: string;
266
271
  } & import("../../../shared/addUrlComputedProps.js").PageContextUrlComputedPropsClient & {
267
272
  _urlRewrite: string | null;
268
273
  };
@@ -106,9 +106,9 @@ async function prerender404Page(renderContext, pageContextInit_) {
106
106
  _debugRouteMatches: []
107
107
  };
108
108
  const pageContextInit = {
109
- urlOriginal: '/fake-404-url', // A URL is needed for `applyViteHtmlTransform`
110
- ...pageContextInit_
109
+ urlOriginal: '/fake-404-url' // A URL is needed for `applyViteHtmlTransform`
111
110
  };
111
+ objectAssign(pageContextInit, pageContextInit_);
112
112
  {
113
113
  const pageContextInitEnhanced = getPageContextInitEnhanced(pageContextInit, renderContext);
114
114
  objectAssign(pageContext, pageContextInitEnhanced);
@@ -123,8 +123,9 @@ function getPageContextInitEnhanced(pageContextInit, renderContext, { urlCompute
123
123
  } } = {}) {
124
124
  assert(pageContextInit.urlOriginal);
125
125
  const globalContext = getGlobalContext();
126
- const pageContextInitEnhanced = {
127
- ...pageContextInit,
126
+ const pageContextInitEnhanced = {};
127
+ objectAssign(pageContextInitEnhanced, pageContextInit);
128
+ objectAssign(pageContextInitEnhanced, {
128
129
  _objectCreatedByVike: true,
129
130
  // The following is defined on `pageContext` because we can eventually make these non-global (e.g. sot that two pages can have different includeAssetsImportedByServer settings)
130
131
  _baseServer: globalContext.baseServer,
@@ -141,7 +142,7 @@ function getPageContextInitEnhanced(pageContextInit, renderContext, { urlCompute
141
142
  _urlRewrite: urlRewrite,
142
143
  _urlHandler: urlHandler,
143
144
  isClientSideNavigation
144
- };
145
+ });
145
146
  addUrlComputedProps(pageContextInitEnhanced, !urlComputedPropsNonEnumerable);
146
147
  return pageContextInitEnhanced;
147
148
  }
@@ -283,12 +283,13 @@ async function renderPageNominal(pageContext) {
283
283
  async function getPageContextErrorPageInit(pageContextInit, errNominalPage, pageContextNominalPagePartial, renderContext, httpRequestId) {
284
284
  const pageContextInitEnhanced = getPageContextInitEnhancedSSR(pageContextInit, renderContext, null, httpRequestId);
285
285
  assert(errNominalPage);
286
- const pageContext = {
287
- ...pageContextInitEnhanced,
286
+ const pageContext = {};
287
+ objectAssign(pageContext, pageContextInitEnhanced);
288
+ objectAssign(pageContext, {
288
289
  is404: false,
289
290
  errorWhileRendering: errNominalPage,
290
291
  routeParams: {}
291
- };
292
+ });
292
293
  objectAssign(pageContext, {
293
294
  _debugRouteMatches: pageContextNominalPagePartial._debugRouteMatches || 'ROUTING_ERROR'
294
295
  });
@@ -340,7 +341,9 @@ function normalizeUrl(pageContextInit, httpRequestId) {
340
341
  return null;
341
342
  logRuntimeInfo?.(`URL normalized from ${pc.cyan(urlOriginal)} to ${pc.cyan(urlNormalized)} (https://vike.dev/url-normalization)`, httpRequestId, 'info');
342
343
  const httpResponse = createHttpResponseObjectRedirect({ url: urlNormalized, statusCode: 301 }, pageContextInit.urlOriginal);
343
- const pageContextHttpResponse = { ...pageContextInit, httpResponse };
344
+ const pageContextHttpResponse = {};
345
+ objectAssign(pageContextHttpResponse, pageContextInit);
346
+ objectAssign(pageContextHttpResponse, { httpResponse });
344
347
  return pageContextHttpResponse;
345
348
  }
346
349
  function getPermanentRedirect(pageContextInit, httpRequestId) {
@@ -375,7 +378,9 @@ function getPermanentRedirect(pageContextInit, httpRequestId) {
375
378
  }
376
379
  logRuntimeInfo?.(`Permanent redirect defined by your config.redirects (https://vike.dev/redirects)`, httpRequestId, 'info');
377
380
  const httpResponse = createHttpResponseObjectRedirect({ url: urlTarget, statusCode: 301 }, urlWithoutBase);
378
- const pageContextHttpResponse = { ...pageContextInit, httpResponse };
381
+ const pageContextHttpResponse = {};
382
+ objectAssign(pageContextHttpResponse, pageContextInit);
383
+ objectAssign(pageContextHttpResponse, { httpResponse });
379
384
  return pageContextHttpResponse;
380
385
  }
381
386
  async function handleAbortError(errAbort, pageContextsFromRewrite, pageContextInit,
@@ -391,11 +396,11 @@ pageContextNominalPageInit, httpRequestId, renderContext, pageContextErrorPageIn
391
396
  assert(abortCall);
392
397
  assertUsage(errorPageId, `You called ${pc.cyan(abortCall)} but you didn't define an error page, make sure to define one https://vike.dev/error-page`);
393
398
  const pageContext = {
394
- _pageId: errorPageId,
395
- ...pageContextAbort,
396
- ...pageContextErrorPageInit,
397
- ...renderContext
399
+ _pageId: errorPageId
398
400
  };
401
+ objectAssign(pageContext, pageContextAbort);
402
+ objectAssign(pageContext, pageContextErrorPageInit);
403
+ objectAssign(pageContext, renderContext);
399
404
  objectAssign(pageContext, await loadUserFilesServerSide(pageContext));
400
405
  // We include pageContextInit: we don't only serialize pageContextAbort because the error page may need to access pageContextInit
401
406
  pageContextSerialized = serializePageContextClientSide(pageContext);
@@ -416,10 +421,9 @@ pageContextNominalPageInit, httpRequestId, renderContext, pageContextErrorPageIn
416
421
  return { pageContextReturn };
417
422
  }
418
423
  if (pageContextAbort._urlRedirect) {
419
- const pageContextReturn = {
420
- ...pageContextInit,
421
- ...pageContextAbort
422
- };
424
+ const pageContextReturn = {};
425
+ objectAssign(pageContextReturn, pageContextInit);
426
+ objectAssign(pageContextReturn, pageContextAbort);
423
427
  const httpResponse = createHttpResponseObjectRedirect(pageContextAbort._urlRedirect, (() => {
424
428
  const { pathname, searchOriginal } = pageContextNominalPageInit.urlParsed;
425
429
  const urlLogical = createUrlFromComponents(null, pathname, searchOriginal,
@@ -49,3 +49,4 @@ export * from '../../utils/truncateString.js';
49
49
  export * from '../../utils/formatHintLog.js';
50
50
  export * from '../../utils/joinEnglish.js';
51
51
  export * from '../../utils/isArrayOfStrings.js';
52
+ export * from '../../utils/escapeHtml.js';
@@ -52,3 +52,4 @@ export * from '../../utils/truncateString.js';
52
52
  export * from '../../utils/formatHintLog.js';
53
53
  export * from '../../utils/joinEnglish.js';
54
54
  export * from '../../utils/isArrayOfStrings.js';
55
+ export * from '../../utils/escapeHtml.js';
@@ -2,13 +2,9 @@ import { compareString } from './utils.js';
2
2
  export { sortPageContext };
3
3
  // Sort `pageContext` keys alphabetically, in order to make reading `console.log(pageContext)` easier
4
4
  function sortPageContext(pageContext) {
5
- const entries = Object.entries(pageContext);
6
- for (const key in pageContext) {
5
+ let descriptors = Object.getOwnPropertyDescriptors(pageContext);
6
+ for (const key of Object.keys(pageContext))
7
7
  delete pageContext[key];
8
- }
9
- entries
10
- .sort(([key1], [key2]) => compareString(key1, key2))
11
- .forEach(([key, val]) => {
12
- pageContext[key] = val;
13
- });
8
+ descriptors = Object.fromEntries(Object.entries(descriptors).sort(([key1], [key2]) => compareString(key1, key2)));
9
+ Object.defineProperties(pageContext, descriptors);
14
10
  }
@@ -0,0 +1 @@
1
+ export declare function escapeHtml(unsafeString: string): string;
@@ -0,0 +1,10 @@
1
+ // Copied from https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript/6234804#6234804
2
+ export function escapeHtml(unsafeString) {
3
+ const safe = unsafeString
4
+ .replace(/&/g, '&amp;')
5
+ .replace(/</g, '&lt;')
6
+ .replace(/>/g, '&gt;')
7
+ .replace(/"/g, '&quot;')
8
+ .replace(/'/g, '&#039;');
9
+ return safe;
10
+ }
@@ -1,10 +1,8 @@
1
1
  export { objectEntries };
2
2
  export { objectFromEntries };
3
3
  export { objectKeys };
4
- type ValueOf<T> = T[keyof T];
5
- type Entries<T> = [keyof T, ValueOf<T>][];
6
4
  /** Same as Object.entries() but with type inference */
7
- declare function objectEntries<T extends object>(obj: T): Entries<T>;
5
+ declare function objectEntries<T extends object>(obj: T): [keyof T, T[keyof T]][];
8
6
  /** Same as Object.fromEntries() but with type inference */
9
7
  declare function objectFromEntries<T extends [PropertyKey, unknown][]>(arr: T): Record<T[number][0], T[number][1]>;
10
8
  /** Same as Object.keys() but with type inference */
@@ -1,6 +1,7 @@
1
1
  export { objectEntries };
2
2
  export { objectFromEntries };
3
3
  export { objectKeys };
4
+ // export { forEach }
4
5
  // https://stackoverflow.com/questions/60141960/typescript-key-value-relation-preserving-object-entries-type/75337277#75337277
5
6
  /** Same as Object.entries() but with type inference */
6
7
  function objectEntries(obj) {
@@ -16,8 +17,11 @@ function objectFromEntries(arr) {
16
17
  function objectKeys(obj) {
17
18
  return Object.keys(obj);
18
19
  }
19
- /*
20
- function objectKeys2<T extends Record<string, unknown>>(obj: T): Array<keyof T> {
21
- return Object.keys(obj)
20
+ /* Not used yet, but can be quite useful.
21
+ function forEach<Obj extends object>(
22
+ obj: Obj,
23
+ iterator: <Key extends keyof Obj>(key: Key, val: Obj[Key]) => void
24
+ ): void {
25
+ Object.entries(obj).forEach(([key, val]) => iterator(key as keyof Obj, val))
22
26
  }
23
- */
27
+ //*/
@@ -1,7 +1,7 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
- declare const PROJECT_VERSION: "0.4.171-commit-978d69d";
3
+ declare const PROJECT_VERSION: "0.4.171-commit-42245b5";
4
4
  declare const projectInfo: {
5
5
  projectName: "Vike";
6
- projectVersion: "0.4.171-commit-978d69d";
6
+ projectVersion: "0.4.171-commit-42245b5";
7
7
  };
@@ -1,6 +1,6 @@
1
1
  export { projectInfo };
2
2
  export { PROJECT_VERSION };
3
- const PROJECT_VERSION = '0.4.171-commit-978d69d';
3
+ const PROJECT_VERSION = '0.4.171-commit-42245b5';
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-978d69d",
3
+ "version": "0.4.171-commit-42245b5",
4
4
  "scripts": {
5
5
  "dev": "tsc --watch",
6
6
  "build": "rimraf dist/ && pnpm run build:esm && pnpm run build:cjs",