vike 0.4.199 → 0.4.200-commit-de0e6ef

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 (48) hide show
  1. package/dist/cjs/node/client/router.js +3 -1
  2. package/dist/cjs/node/plugin/plugins/envVars.js +3 -0
  3. package/dist/cjs/node/plugin/plugins/extractAssetsPlugin.js +2 -0
  4. package/dist/cjs/node/plugin/plugins/extractExportNamesPlugin.js +2 -0
  5. package/dist/cjs/node/plugin/plugins/fileEnv.js +2 -0
  6. package/dist/cjs/node/plugin/plugins/importBuild/index.js +4 -4
  7. package/dist/cjs/node/plugin/plugins/importUserCode/index.js +7 -6
  8. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +15 -3
  9. package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +1 -1
  10. package/dist/cjs/node/plugin/shared/normalizeId.js +9 -0
  11. package/dist/cjs/node/prerender/runPrerender.js +3 -1
  12. package/dist/cjs/node/runtime/globalContext/loadImportBuild.js +1 -1
  13. package/dist/cjs/node/runtime/renderPage.js +15 -5
  14. package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
  15. package/dist/cjs/utils/parseUrl-extras.js +4 -3
  16. package/dist/esm/client/client-routing-runtime/history.d.ts +19 -9
  17. package/dist/esm/client/client-routing-runtime/history.js +121 -68
  18. package/dist/esm/client/client-routing-runtime/index.d.ts +1 -0
  19. package/dist/esm/client/client-routing-runtime/index.js +1 -0
  20. package/dist/esm/client/client-routing-runtime/initClientRouter.js +2 -5
  21. package/dist/esm/client/client-routing-runtime/initOnPopState.d.ts +12 -0
  22. package/dist/esm/client/client-routing-runtime/initOnPopState.js +72 -0
  23. package/dist/esm/client/client-routing-runtime/renderPageClientSide.d.ts +1 -2
  24. package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +4 -6
  25. package/dist/esm/node/client/router.d.ts +2 -0
  26. package/dist/esm/node/client/router.js +2 -0
  27. package/dist/esm/node/plugin/plugins/envVars.js +3 -0
  28. package/dist/esm/node/plugin/plugins/extractAssetsPlugin.js +2 -0
  29. package/dist/esm/node/plugin/plugins/extractExportNamesPlugin.js +2 -0
  30. package/dist/esm/node/plugin/plugins/fileEnv.js +2 -0
  31. package/dist/esm/node/plugin/plugins/importBuild/index.js +5 -5
  32. package/dist/esm/node/plugin/plugins/importUserCode/index.js +8 -7
  33. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +16 -4
  34. package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +1 -1
  35. package/dist/esm/node/plugin/shared/normalizeId.d.ts +2 -0
  36. package/dist/esm/node/plugin/shared/normalizeId.js +7 -0
  37. package/dist/esm/node/prerender/runPrerender.js +3 -1
  38. package/dist/esm/node/runtime/globalContext/loadImportBuild.js +2 -2
  39. package/dist/esm/node/runtime/renderPage.js +16 -6
  40. package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
  41. package/dist/esm/utils/PROJECT_VERSION.js +1 -1
  42. package/dist/esm/utils/getCurrentUrl.d.ts +1 -1
  43. package/dist/esm/utils/parseUrl-extras.d.ts +2 -2
  44. package/dist/esm/utils/parseUrl-extras.js +4 -3
  45. package/dist/esm/utils/projectInfo.d.ts +1 -1
  46. package/package.json +2 -11
  47. package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.d.ts +0 -4
  48. package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.js +0 -63
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.prefetch = exports.reload = exports.navigate = void 0;
3
+ exports.onPopState = exports.prefetch = exports.reload = exports.navigate = void 0;
4
4
  const assert_js_1 = require("../../utils/assert.js");
5
5
  // `never` to ensure package.json#exports["./client/router"].types points to type defined by the client-side code
6
6
  const navigate = (() => warnNoEffect('navigate'));
@@ -9,6 +9,8 @@ const reload = (() => warnNoEffect('reload'));
9
9
  exports.reload = reload;
10
10
  const prefetch = (() => warnNoEffect('prefetch'));
11
11
  exports.prefetch = prefetch;
12
+ const onPopState = (() => { });
13
+ exports.onPopState = onPopState;
12
14
  function warnNoEffect(caller) {
13
15
  (0, assert_js_1.assertWarning)(false, `Calling ${caller}() on the server-side has no effect`, {
14
16
  showStackTrace: true,
@@ -5,6 +5,7 @@ const vite_1 = require("vite");
5
5
  const utils_js_1 = require("../utils.js");
6
6
  const rollupSourceMap_js_1 = require("../shared/rollupSourceMap.js");
7
7
  const getFilePath_js_1 = require("../shared/getFilePath.js");
8
+ const normalizeId_js_1 = require("../shared/normalizeId.js");
8
9
  // TODO/enventually: (after we implemented vike.config.js)
9
10
  // - Make import.meta.env work inside +config.js
10
11
  // - For it to work, we'll probably need the user to define the settings (e.g. `envDir`) for loadEnv() inside vike.config.js instead of vite.config.js
@@ -27,9 +28,11 @@ function envVarsPlugin() {
27
28
  config.plugins.sort((0, utils_js_1.lowerFirst)((plugin) => (plugin.name === 'vite:define' ? 1 : 0)));
28
29
  },
29
30
  transform(code, id, options) {
31
+ id = (0, normalizeId_js_1.normalizeId)(id);
30
32
  (0, utils_js_1.assertPosixPath)(id);
31
33
  if (id.includes('/node_modules/'))
32
34
  return;
35
+ (0, utils_js_1.assertPosixPath)(config.root);
33
36
  if (!id.startsWith(config.root))
34
37
  return;
35
38
  if (!code.includes('import.meta.env.'))
@@ -17,6 +17,7 @@ const picocolors_1 = __importDefault(require("@brillout/picocolors"));
17
17
  const fixServerAssets_js_1 = require("./buildConfig/fixServerAssets.js");
18
18
  const getVikeConfig_js_1 = require("./importUserCode/v1-design/getVikeConfig.js");
19
19
  const assertV1Design_js_1 = require("../../shared/assertV1Design.js");
20
+ const normalizeId_js_1 = require("../shared/normalizeId.js");
20
21
  const extractAssetsRE = /(\?|&)extractAssets(?:&|$)/;
21
22
  exports.extractAssetsRE = extractAssetsRE;
22
23
  const rawRE = /(\?|&)raw(?:&|$)/;
@@ -36,6 +37,7 @@ function extractAssetsPlugin() {
36
37
  apply: 'build',
37
38
  enforce: 'post',
38
39
  async transform(src, id, options) {
40
+ id = (0, normalizeId_js_1.normalizeId)(id);
39
41
  if (!extractAssetsRE.test(id)) {
40
42
  return;
41
43
  }
@@ -6,6 +6,7 @@ exports.isUsingClientRouter = isUsingClientRouter;
6
6
  const utils_js_1 = require("../utils.js");
7
7
  const parseEsModule_js_1 = require("../shared/parseEsModule.js");
8
8
  const rollupSourceMap_js_1 = require("../shared/rollupSourceMap.js");
9
+ const normalizeId_js_1 = require("../shared/normalizeId.js");
9
10
  const extractExportNamesRE = /(\?|&)extractExportNames(?:&|$)/;
10
11
  exports.extractExportNamesRE = extractExportNamesRE;
11
12
  const debug = (0, utils_js_1.createDebugger)('vike:extractExportNames');
@@ -16,6 +17,7 @@ function extractExportNamesPlugin() {
16
17
  name: 'vike:extractExportNames',
17
18
  enforce: 'post',
18
19
  async transform(src, id, options) {
20
+ id = (0, normalizeId_js_1.normalizeId)(id);
19
21
  const isClientSide = !(0, utils_js_1.viteIsSSR_options)(options);
20
22
  if (extractExportNamesRE.test(id)) {
21
23
  const code = await getExtractExportNamesCode(src, isClientSide, !isDev, id);
@@ -11,6 +11,7 @@ const picocolors_1 = __importDefault(require("@brillout/picocolors"));
11
11
  const getFilePath_js_1 = require("../shared/getFilePath.js");
12
12
  const rollupSourceMap_js_1 = require("../shared/rollupSourceMap.js");
13
13
  const parseEsModule_js_1 = require("../shared/parseEsModule.js");
14
+ const normalizeId_js_1 = require("../shared/normalizeId.js");
14
15
  function fileEnv() {
15
16
  let config;
16
17
  let viteDevServer;
@@ -36,6 +37,7 @@ function fileEnv() {
36
37
  },
37
38
  // In production, we have to use transform() to replace modules with a runtime error because generateBundle() doesn't work for dynamic imports. In production, dynamic imports can only be verified at runtime.
38
39
  async transform(code, id, options) {
40
+ id = (0, normalizeId_js_1.normalizeId)(id);
39
41
  // In dev, only using load() is enough as it also works for dynamic imports (see sibling comment).
40
42
  if (viteDevServer)
41
43
  return;
@@ -29,15 +29,15 @@ function importBuild() {
29
29
  configVike = await (0, getConfigVike_js_1.getConfigVike)(config);
30
30
  }
31
31
  },
32
- ...(0, plugin_1.serverEntryPlugin)({
33
- getImporterCode: () => {
34
- return getEntryCode(config, configVike);
32
+ ...(0, plugin_1.serverProductionEntryPlugin)({
33
+ getServerProductionEntry: () => {
34
+ return getServerProductionEntryCode(config, configVike);
35
35
  },
36
36
  libraryName: 'Vike'
37
37
  })
38
38
  ];
39
39
  }
40
- function getEntryCode(config, configVike) {
40
+ function getServerProductionEntryCode(config, configVike) {
41
41
  const importPath = getImportPath(config);
42
42
  const vikeManifest = (0, getVikeManifest_js_1.getVikeManifest)(configVike);
43
43
  const importerCode = [
@@ -23,16 +23,17 @@ function importUserCode() {
23
23
  name: 'vike:importUserCode',
24
24
  config(_, env) {
25
25
  isDev = (0, utils_js_1.isDev3)(env);
26
- return {
27
- experimental: {
28
- // TODO/v1-release: remove
29
- importGlobRestoreExtension: true
30
- }
31
- };
32
26
  },
33
27
  async configResolved(config_) {
34
28
  configVike = await (0, getConfigVike_js_1.getConfigVike)(config_);
35
29
  config = config_;
30
+ // TODO/v1-release: remove
31
+ {
32
+ (0, utils_js_1.assert)(isDev !== undefined);
33
+ const isV1 = await (0, getVikeConfig_js_1.isV1Design)(config, isDev);
34
+ if (!isV1)
35
+ config.experimental.importGlobRestoreExtension = true;
36
+ }
36
37
  },
37
38
  resolveId(id) {
38
39
  if ((0, utils_js_1.isVirtualFileId)(id)) {
@@ -19,6 +19,8 @@ require("source-map-support/register.js");
19
19
  const getFilePath_js_1 = require("../../../../shared/getFilePath.js");
20
20
  (0, utils_js_1.assertIsNotProductionRuntime)();
21
21
  const debug = (0, utils_js_1.createDebugger)('vike:pointer-imports');
22
+ console.log('esbuild version', esbuild_1.version);
23
+ console.log('require.resolve("vike-react/config")', require.resolve('vike-react/config'));
22
24
  async function transpileAndExecuteFile(filePath, userRootDir, isConfigFile) {
23
25
  const { filePathAbsoluteFilesystem, filePathToShowToUserResolved } = filePath;
24
26
  const fileExtension = getFileExtension(filePathAbsoluteFilesystem);
@@ -88,7 +90,7 @@ async function transpileWithEsbuild(filePath, userRootDir, transformImports) {
88
90
  metafile: true,
89
91
  bundle: true
90
92
  };
91
- let pointerImports = {};
93
+ const pointerImports = {};
92
94
  options.plugins = [
93
95
  // Determine whether an import should be:
94
96
  // - A pointer import
@@ -98,6 +100,7 @@ async function transpileWithEsbuild(filePath, userRootDir, transformImports) {
98
100
  setup(build) {
99
101
  // https://github.com/brillout/esbuild-playground
100
102
  build.onResolve({ filter: /.*/ }, async (args) => {
103
+ console.log('onResolve()', JSON.stringify(args, null, 2));
101
104
  if (args.kind !== 'import-statement')
102
105
  return;
103
106
  // Avoid infinite loop: https://github.com/evanw/esbuild/issues/3095#issuecomment-1546916366
@@ -106,14 +109,23 @@ async function transpileWithEsbuild(filePath, userRootDir, transformImports) {
106
109
  return;
107
110
  const { path, ...opts } = args;
108
111
  opts.pluginData = { [useEsbuildResolver]: true };
109
- const resolved = await build.resolve(path, opts);
112
+ let resolved = await build.resolve(path, opts);
110
113
  if (resolved.errors.length > 0) {
114
+ let resolvedWithNode;
115
+ try {
116
+ resolvedWithNode = require.resolve(args.path, { paths: [args.resolveDir] });
117
+ }
118
+ catch { }
119
+ if (resolvedWithNode)
120
+ resolved = { path: resolvedWithNode };
121
+ }
122
+ if (resolved.errors && resolved.errors.length > 0) {
111
123
  /* We could do the following to let Node.js throw the error, but we don't because the error shown by esbuild is prettier: the Node.js error refers to the transpiled [build-f7i251e0iwnw]+config.ts.mjs whereas esbuild refers to the source +config.ts file.
112
124
  pointerImports[args.path] = false
113
125
  return { external: true }
114
126
  */
115
- cleanEsbuildErrors(resolved.errors);
116
127
  // Let esbuild throw the error
128
+ cleanEsbuildErrors(resolved.errors);
117
129
  return resolved;
118
130
  }
119
131
  (0, utils_js_1.assert)(resolved.path);
@@ -23,7 +23,7 @@ async function getVirtualFilePageConfigValuesAll(id, isDev, config) {
23
23
  const { pageId, isForClientSide } = result;
24
24
  const { pageConfigs } = await (0, getVikeConfig_js_1.getVikeConfig)(config, isDev, { tolerateInvalidConfig: true });
25
25
  const pageConfig = pageConfigs.find((pageConfig) => pageConfig.pageId === pageId);
26
- (0, utils_js_1.assert)(pageConfig);
26
+ (0, utils_js_1.assert)(pageConfig, { id, pageId });
27
27
  const configVike = await (0, getConfigVike_js_1.getConfigVike)(config);
28
28
  const code = getLoadConfigValuesAll(pageConfig, isForClientSide, pageId, configVike.includeAssetsImportedByServer, isDev);
29
29
  (0, debug_js_1.debug)(id, isForClientSide ? 'CLIENT-SIDE' : 'SERVER-SIDE', code);
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeId = normalizeId;
4
+ const utils_js_1 = require("../utils.js");
5
+ // In principle Vite/Rollup should always normalize the `id` in `transform(code, id)` but it seems to not always do it.
6
+ // https://github.com/vikejs/vike/issues/1935
7
+ function normalizeId(id) {
8
+ return (0, utils_js_1.toPosixPath)(id);
9
+ }
@@ -605,7 +605,9 @@ async function write(urlOriginal, pageContext, fileExtension, fileContent, root,
605
605
  (0, utils_js_1.assertPosixPath)(fileUrl);
606
606
  (0, utils_js_1.assert)(fileUrl.startsWith('/'));
607
607
  const filePathRelative = fileUrl.slice(1);
608
- (0, utils_js_1.assert)(!filePathRelative.startsWith('/'));
608
+ (0, utils_js_1.assert)(!filePathRelative.startsWith('/'),
609
+ // Let's remove this debug info after we add a assertUsage() avoiding https://github.com/vikejs/vike/issues/1929
610
+ { urlOriginal, fileUrl });
609
611
  (0, utils_js_1.assertPosixPath)(outDirClient);
610
612
  (0, utils_js_1.assertPosixPath)(filePathRelative);
611
613
  const filePath = path_1.default.posix.join(outDirClient, filePathRelative);
@@ -12,7 +12,7 @@ function setImportBuildGetters(getters) {
12
12
  }
13
13
  async function loadImportBuild(outDir) {
14
14
  if (!buildGetters.getters) {
15
- await (0, runtime_1.importServerEntry)(outDir);
15
+ await (0, runtime_1.importServerProductionEntry)({ outDir });
16
16
  (0, utils_js_1.assert)(buildGetters.getters);
17
17
  }
18
18
  const [pageFiles, assetsManifest, pluginManifest] = await Promise.all([
@@ -380,19 +380,29 @@ function getPermanentRedirect(pageContextInit, httpRequestId) {
380
380
  urlTarget = urlTargetExternal;
381
381
  }
382
382
  else {
383
- if (origin)
384
- urlTarget = (0, utils_js_1.addUrlOrigin)(urlTarget, origin);
385
- if (urlTarget === urlWithoutBase)
383
+ let originChanged = false;
384
+ if (origin) {
385
+ const urlModified = (0, utils_js_1.setUrlOrigin)(urlTarget, origin);
386
+ if (urlModified !== false) {
387
+ originChanged = true;
388
+ urlTarget = urlModified;
389
+ }
390
+ }
391
+ if (normalize(urlTarget) === normalize(urlWithoutBase))
386
392
  return null;
387
- urlTarget = (0, utils_js_1.prependBase)(urlTarget, baseServer);
393
+ if (!originChanged)
394
+ urlTarget = (0, utils_js_1.prependBase)(urlTarget, baseServer);
388
395
  (0, utils_js_1.assert)(urlTarget !== pageContextInit.urlOriginal);
389
396
  }
390
- (0, loggerRuntime_js_1.logRuntimeInfo)?.(`Permanent redirect defined by your config.redirects (https://vike.dev/redirects)`, httpRequestId, 'info');
397
+ (0, loggerRuntime_js_1.logRuntimeInfo)?.(`Permanent redirection defined by config.redirects (https://vike.dev/redirects)`, httpRequestId, 'info');
391
398
  const httpResponse = (0, createHttpResponse_js_1.createHttpResponseRedirect)({ url: urlTarget, statusCode: 301 }, urlWithoutBase);
392
399
  const pageContextHttpResponse = createPageContext(pageContextInit);
393
400
  (0, utils_js_1.objectAssign)(pageContextHttpResponse, { httpResponse });
394
401
  return pageContextHttpResponse;
395
402
  }
403
+ function normalize(url) {
404
+ return url || '/';
405
+ }
396
406
  async function handleAbortError(errAbort, pageContextsFromRewrite, pageContextInit,
397
407
  // handleAbortError() creates a new pageContext object and we don't merge pageContextNominalPageInit to it: we only use some pageContextNominalPageInit information.
398
408
  pageContextNominalPageInit, httpRequestId, renderContext, pageContextErrorPageInit) {
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PROJECT_VERSION = void 0;
4
4
  // Automatically updated by @brillout/release-me
5
- exports.PROJECT_VERSION = '0.4.199';
5
+ exports.PROJECT_VERSION = '0.4.200-commit-de0e6ef';
@@ -6,7 +6,7 @@ exports.normalizeUrlPathname = normalizeUrlPathname;
6
6
  exports.removeBaseServer = removeBaseServer;
7
7
  exports.modifyUrlPathname = modifyUrlPathname;
8
8
  exports.removeUrlOrigin = removeUrlOrigin;
9
- exports.addUrlOrigin = addUrlOrigin;
9
+ exports.setUrlOrigin = setUrlOrigin;
10
10
  exports.getUrlPretty = getUrlPretty;
11
11
  const parseUrl_js_1 = require("./parseUrl.js");
12
12
  const assert_js_1 = require("./assert.js");
@@ -96,9 +96,10 @@ function removeUrlOrigin(url) {
96
96
  const urlModified = (0, parseUrl_js_1.createUrlFromComponents)(null, pathnameOriginal, searchOriginal, hashOriginal);
97
97
  return { urlModified, origin };
98
98
  }
99
- function addUrlOrigin(url, origin) {
99
+ function setUrlOrigin(url, origin) {
100
100
  const { origin: originCurrent, pathnameOriginal, searchOriginal, hashOriginal } = (0, parseUrl_js_1.parseUrl)(url, '/');
101
- (0, assert_js_1.assert)(originCurrent === null);
101
+ if (origin === originCurrent)
102
+ return false;
102
103
  (0, assert_js_1.assert)(origin === null || origin.startsWith('http'));
103
104
  const urlModified = (0, parseUrl_js_1.createUrlFromComponents)(origin, pathnameOriginal, searchOriginal, hashOriginal);
104
105
  return urlModified;
@@ -1,16 +1,26 @@
1
- export { initHistoryState, getHistoryState, pushHistory, ScrollPosition, saveScrollPosition, monkeyPatchHistoryPushState };
2
- type HistoryState = {
3
- timestamp?: number;
4
- scrollPosition?: null | ScrollPosition;
5
- triggeredBy?: 'user' | 'vike' | 'browser';
1
+ export { pushHistoryState };
2
+ export { onPopStateBegin };
3
+ export { saveScrollPosition };
4
+ export type { HistoryInfo };
5
+ export type { ScrollPosition };
6
+ type StateEnhanced = {
7
+ timestamp: number;
8
+ scrollPosition: null | ScrollPosition;
9
+ triggeredBy: 'user' | 'vike' | 'browser';
6
10
  _isVikeEnhanced: true;
7
11
  };
8
12
  type ScrollPosition = {
9
13
  x: number;
10
14
  y: number;
11
15
  };
12
- declare function initHistoryState(): void;
13
- declare function getHistoryState(): HistoryState;
14
16
  declare function saveScrollPosition(): void;
15
- declare function pushHistory(url: string, overwriteLastHistoryEntry: boolean): void;
16
- declare function monkeyPatchHistoryPushState(): void;
17
+ declare function pushHistoryState(url: string, overwriteLastHistoryEntry: boolean): void;
18
+ type HistoryInfo = {
19
+ url: `/${string}`;
20
+ state: StateEnhanced;
21
+ };
22
+ declare function onPopStateBegin(): {
23
+ isNewState: boolean;
24
+ previous: HistoryInfo;
25
+ current: HistoryInfo;
26
+ };
@@ -1,37 +1,57 @@
1
- export { initHistoryState, getHistoryState, pushHistory, saveScrollPosition, monkeyPatchHistoryPushState };
2
- import { assert, assertUsage, hasProp, isObject } from './utils.js';
3
- // Fill missing state information:
4
- // - `history.state` can uninitialized (i.e. `null`):
5
- // - The very first render
6
- // - The user's code runs `location.hash = '#section'`
7
- // - The user clicks on an anchor link `<a href="#section">Section</a>` (Vike's `initOnLinkClick()` handler skips hash links).
8
- // - State information may be incomplete if `history.state` is set by an old Vike version. (E.g. `state.timestamp` was introduced for `pageContext.isBackwardNavigation` in `0.4.19`.)
9
- function initHistoryState() {
10
- // No way found to add TypeScript types to `window.history.state`: https://github.com/microsoft/TypeScript/issues/36178
11
- let state = window.history.state;
12
- if (!state) {
13
- state = { _isVikeEnhanced: true };
14
- }
15
- let hasModifications = false;
16
- if (!('timestamp' in state)) {
17
- hasModifications = true;
18
- state.timestamp = getTimestamp();
19
- }
20
- if (!('scrollPosition' in state)) {
21
- hasModifications = true;
22
- state.scrollPosition = getScrollPosition();
23
- }
24
- if (!('triggeredBy' in state)) {
25
- state.triggeredBy = 'browser';
1
+ export { pushHistoryState };
2
+ export { onPopStateBegin };
3
+ export { saveScrollPosition };
4
+ import { assert, assertUsage, getCurrentUrl, getGlobalObject, hasProp, isObject } from './utils.js';
5
+ init();
6
+ const globalObject = getGlobalObject('history.ts', { previous: getHistoryInfo() });
7
+ // `window.history.state === null` when:
8
+ // - The very first render
9
+ // - Click on `<a href="#some-hash" />`
10
+ // - `location.hash = 'some-hash'`
11
+ function enhanceHistoryState() {
12
+ const stateNotEnhanced = getStateNotEnhanced();
13
+ if (isVikeEnhanced(stateNotEnhanced))
14
+ return;
15
+ const stateVikeEnhanced = enhance(stateNotEnhanced);
16
+ replaceHistoryState(stateVikeEnhanced);
17
+ }
18
+ function enhance(stateNotEnhanced) {
19
+ const timestamp = getTimestamp();
20
+ const scrollPosition = getScrollPosition();
21
+ const triggeredBy = 'browser';
22
+ let stateVikeEnhanced;
23
+ if (!stateNotEnhanced) {
24
+ stateVikeEnhanced = {
25
+ timestamp,
26
+ scrollPosition,
27
+ triggeredBy,
28
+ _isVikeEnhanced: true
29
+ };
26
30
  }
27
- assertState(state);
28
- if (hasModifications) {
29
- replaceHistoryState(state);
31
+ else {
32
+ // State information may be incomplete if `window.history.state` is set by an old Vike version. (E.g. `state.timestamp` was introduced for `pageContext.isBackwardNavigation` in `0.4.19`.)
33
+ stateVikeEnhanced = {
34
+ timestamp: stateNotEnhanced.timestamp ?? timestamp,
35
+ scrollPosition: stateNotEnhanced.scrollPosition ?? scrollPosition,
36
+ triggeredBy: stateNotEnhanced.triggeredBy ?? triggeredBy,
37
+ _isVikeEnhanced: true
38
+ };
30
39
  }
40
+ assert(isVikeEnhanced(stateVikeEnhanced));
41
+ return stateVikeEnhanced;
42
+ }
43
+ function getState() {
44
+ const state = getStateNotEnhanced();
45
+ // *Every* state added to the history needs to go through Vike.
46
+ // - Otherwise Vike's `popstate` listener won't work. (Because, for example, if globalObject.previous is outdated => isHashNavigation faulty => client-side navigation is wrongfully skipped.)
47
+ // - Therefore, we have to monkey patch history.pushState() and history.replaceState()
48
+ // - Therefore, we need the assert() below to ensure history.state has been enhanced by Vike
49
+ // - If users stumble upon this assert() then let's make it a assertUsage()
50
+ assert(isVikeEnhanced(state));
51
+ return state;
31
52
  }
32
- function getHistoryState() {
33
- const state = window.history.state || {};
34
- assertState(state);
53
+ function getStateNotEnhanced() {
54
+ const state = window.history.state;
35
55
  return state;
36
56
  }
37
57
  function getScrollPosition() {
@@ -43,55 +63,88 @@ function getTimestamp() {
43
63
  }
44
64
  function saveScrollPosition() {
45
65
  const scrollPosition = getScrollPosition();
46
- const state = getHistoryState();
66
+ const state = getState();
47
67
  replaceHistoryState({ ...state, scrollPosition });
48
68
  }
49
- function pushHistory(url, overwriteLastHistoryEntry) {
69
+ function pushHistoryState(url, overwriteLastHistoryEntry) {
50
70
  if (!overwriteLastHistoryEntry) {
51
- const timestamp = getTimestamp();
52
- pushHistoryState({ timestamp, scrollPosition: null, triggeredBy: 'vike', _isVikeEnhanced: true }, url);
71
+ const state = {
72
+ timestamp: getTimestamp(),
73
+ // I don't remember why I set it to `null`, maybe because setting it now would be too early? (Maybe there is a delay between renderPageClientSide() is finished and the browser updating the scroll position.) Anyways, it seems like autoSaveScrollPosition() is enough.
74
+ scrollPosition: null,
75
+ triggeredBy: 'vike',
76
+ _isVikeEnhanced: true
77
+ };
78
+ // Calling the monkey patched history.pushState() (and not the orignal) so that other tools (e.g. user tracking) can listen to Vike's pushState() calls.
79
+ // - https://github.com/vikejs/vike/issues/1582
80
+ window.history.pushState(state, '', url);
53
81
  }
54
82
  else {
55
- replaceHistoryState(getHistoryState(), url);
56
- }
57
- }
58
- function assertState(state) {
59
- assert(isObject(state));
60
- if ('timestamp' in state) {
61
- const { timestamp } = state;
62
- assert(typeof timestamp === 'number');
63
- }
64
- if ('scrollPosition' in state) {
65
- const { scrollPosition } = state;
66
- if (scrollPosition !== null) {
67
- assert(hasProp(scrollPosition, 'x', 'number') && hasProp(scrollPosition, 'y', 'number'));
68
- }
83
+ replaceHistoryState(getState(), url);
69
84
  }
70
85
  }
71
86
  function replaceHistoryState(state, url) {
72
87
  const url_ = url ?? null; // Passing `undefined` chokes older Edge versions.
73
88
  window.history.replaceState(state, '', url_);
74
89
  }
75
- function pushHistoryState(state, url) {
76
- // Vike should call window.history.pushState() (and not the orignal `pushStateOriginal()`) so that other tools (e.g. user tracking) can listen to Vike's pushState() calls, see https://github.com/vikejs/vike/issues/1582.
77
- window.history.pushState(state, '', url);
90
+ // Monkey patch:
91
+ // - history.pushState()
92
+ // - history.replaceState()
93
+ function monkeyPatchHistoryAPI() {
94
+ ;
95
+ ['pushState', 'replaceState'].forEach((funcName) => {
96
+ const funcOriginal = window.history[funcName].bind(window.history);
97
+ window.history[funcName] = (stateOriginal = {}, ...rest) => {
98
+ assertUsage(stateOriginal === undefined || stateOriginal === null || isObject(stateOriginal), `history.${funcName}(state) argument state must be an object`);
99
+ const stateEnhanced = isVikeEnhanced(stateOriginal)
100
+ ? stateOriginal
101
+ : {
102
+ _isVikeEnhanced: true,
103
+ scrollPosition: getScrollPosition(),
104
+ timestamp: getTimestamp(),
105
+ triggeredBy: 'user',
106
+ ...stateOriginal
107
+ };
108
+ assert(isVikeEnhanced(stateEnhanced));
109
+ const ret = funcOriginal(stateEnhanced, ...rest);
110
+ globalObject.previous = getHistoryInfo();
111
+ return ret;
112
+ };
113
+ });
78
114
  }
79
- function monkeyPatchHistoryPushState() {
80
- const pushStateOriginal = window.history.pushState.bind(window.history);
81
- window.history.pushState = (stateOriginal = {}, ...rest) => {
82
- assertUsage(stateOriginal === undefined || stateOriginal === null || isObject(stateOriginal), 'history.pushState(state) argument state must be an object');
83
- const stateEnhanced = isVikeEnhanced(stateOriginal)
84
- ? stateOriginal
85
- : {
86
- _isVikeEnhanced: true,
87
- scrollPosition: getScrollPosition(),
88
- timestamp: getTimestamp(),
89
- triggeredBy: 'user',
90
- ...stateOriginal
91
- };
92
- return pushStateOriginal(stateEnhanced, ...rest);
115
+ function isVikeEnhanced(state) {
116
+ const yes = isObject(state) && '_isVikeEnhanced' in state;
117
+ if (yes)
118
+ assertStateVikeEnhanced(state);
119
+ return yes;
120
+ }
121
+ function assertStateVikeEnhanced(state) {
122
+ assert(isObject(state));
123
+ assert(hasProp(state, '_isVikeEnhanced', 'true'));
124
+ // TODO/eventually: remove assert() below to save client-side KBs
125
+ assert(hasProp(state, 'timestamp', 'number'));
126
+ assert(hasProp(state, 'scrollPosition'));
127
+ if (state.scrollPosition !== null) {
128
+ assert(hasProp(state, 'scrollPosition', 'object'));
129
+ assert(hasProp(state.scrollPosition, 'x', 'number') && hasProp(state.scrollPosition, 'y', 'number'));
130
+ }
131
+ }
132
+ function init() {
133
+ enhanceHistoryState();
134
+ monkeyPatchHistoryAPI();
135
+ }
136
+ function getHistoryInfo() {
137
+ return {
138
+ url: getCurrentUrl(),
139
+ state: getState()
93
140
  };
94
141
  }
95
- function isVikeEnhanced(state) {
96
- return isObject(state) && '_isVikeEnhanced' in state;
142
+ function onPopStateBegin() {
143
+ const { previous } = globalObject;
144
+ const isNewState = window.history.state === null;
145
+ if (isNewState)
146
+ enhanceHistoryState();
147
+ const current = getHistoryInfo();
148
+ globalObject.previous = current;
149
+ return { isNewState, previous, current };
97
150
  }
@@ -1,5 +1,6 @@
1
1
  export { navigate, reload } from './navigate.js';
2
2
  export { prefetch } from './prefetch.js';
3
+ export { onPopState } from './initOnPopState.js';
3
4
  export { PROJECT_VERSION as version } from './utils.js';
4
5
  import type { PageContextBuiltInClientWithClientRouting } from '../../shared/types.js';
5
6
  /** @deprecated
@@ -5,4 +5,5 @@
5
5
  // Use package.json#exports to make the imports isomorphic.
6
6
  export { navigate, reload } from './navigate.js';
7
7
  export { prefetch } from './prefetch.js';
8
+ export { onPopState } from './initOnPopState.js';
8
9
  export { PROJECT_VERSION as version } from './utils.js';
@@ -1,8 +1,7 @@
1
1
  export { initClientRouter };
2
2
  import { assert } from './utils.js';
3
- import { initHistoryState, monkeyPatchHistoryPushState } from './history.js';
4
3
  import { getRenderCount, renderPageClientSide } from './renderPageClientSide.js';
5
- import { onBrowserHistoryNavigation } from './onBrowserHistoryNavigation.js';
4
+ import { initOnPopState } from './initOnPopState.js';
6
5
  import { initOnLinkClick } from './initOnLinkClick.js';
7
6
  import { setupNativeScrollRestoration } from './scrollRestoration.js';
8
7
  import { autoSaveScrollPosition } from './setScrollPosition.js';
@@ -29,9 +28,7 @@ async function renderFirstPage() {
29
28
  }
30
29
  function initHistoryAndScroll() {
31
30
  setupNativeScrollRestoration();
32
- initHistoryState();
33
31
  autoSaveScrollPosition();
34
- monkeyPatchHistoryPushState();
35
32
  // Handle back-/forward navigation
36
- onBrowserHistoryNavigation();
33
+ initOnPopState();
37
34
  }
@@ -0,0 +1,12 @@
1
+ export { initOnPopState };
2
+ export { onPopState };
3
+ import { type HistoryInfo } from './history.js';
4
+ declare function initOnPopState(): void;
5
+ type Listener = (arg: {
6
+ previous: HistoryInfo;
7
+ }) => void | boolean;
8
+ /** Control back-/forward navigation.
9
+ *
10
+ * https://vike.dev/onPopState
11
+ */
12
+ declare function onPopState(listener: Listener): void;