vike 0.4.265 → 0.4.266-commit-e71fad0

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.
@@ -1,11 +1,28 @@
1
- export { pushHistoryState };
2
- export { replaceHistoryStateOriginal };
1
+ export { changeUrl };
3
2
  export { onPopStateBegin };
4
3
  export { saveScrollPosition };
5
4
  export { initHistory };
5
+ export { historyApiReplaceStateOriginal };
6
6
  export type { HistoryInfo };
7
7
  export type { ScrollPosition };
8
8
  import '../assertEnvClient.js';
9
+ declare function changeUrl(url: string, overwriteLastHistoryEntry: boolean): void;
10
+ declare function historyApiReplaceStateOriginal(state: unknown, url?: Parameters<typeof window.history.replaceState>[2]): void;
11
+ declare function onPopStateBegin(): {
12
+ skip: true;
13
+ previous?: undefined;
14
+ current?: undefined;
15
+ } | {
16
+ skip?: undefined;
17
+ previous: HistoryInfo;
18
+ current: HistoryInfo;
19
+ };
20
+ type ScrollPosition = {
21
+ x: number;
22
+ y: number;
23
+ };
24
+ declare function saveScrollPosition(scrollPosition?: ScrollPosition): void;
25
+ declare function initHistory(): void;
9
26
  type StateEnhanced = {
10
27
  vike: {
11
28
  timestamp: number;
@@ -13,24 +30,7 @@ type StateEnhanced = {
13
30
  triggeredBy: 'user' | 'vike' | 'browser';
14
31
  };
15
32
  };
16
- type ScrollPosition = {
17
- x: number;
18
- y: number;
19
- };
20
- declare function saveScrollPosition(scrollPosition?: ScrollPosition): void;
21
- declare function pushHistoryState(url: string, overwriteLastHistoryEntry: boolean): void;
22
- declare function replaceHistoryStateOriginal(state: unknown, url?: Parameters<typeof window.history.replaceState>[2]): void;
23
33
  type HistoryInfo = {
24
34
  url: `/${string}`;
25
35
  state: StateEnhanced;
26
36
  };
27
- declare function onPopStateBegin(): {
28
- skip: true;
29
- previous?: undefined;
30
- current?: undefined;
31
- } | {
32
- skip?: undefined;
33
- previous: HistoryInfo;
34
- current: HistoryInfo;
35
- };
36
- declare function initHistory(): void;
@@ -1,8 +1,8 @@
1
- export { pushHistoryState };
2
- export { replaceHistoryStateOriginal };
1
+ export { changeUrl };
3
2
  export { onPopStateBegin };
4
3
  export { saveScrollPosition };
5
4
  export { initHistory };
5
+ export { historyApiReplaceStateOriginal };
6
6
  import { getCurrentUrl } from '../shared/getCurrentUrl.js';
7
7
  import { assert, assertUsage } from '../../utils/assert.js';
8
8
  import { getGlobalObject } from '../../utils/getGlobalObject.js';
@@ -15,49 +15,9 @@ const globalObject = getGlobalObject('history.ts', {
15
15
  });
16
16
  initHistory(); // we redundantly call initHistory() to ensure it's called early
17
17
  globalObject.previous = getHistoryInfo();
18
- // `window.history.state === null` when:
19
- // - The very first render
20
- // - Click on `<a href="#some-hash" />`
21
- // - `location.hash = 'some-hash'`
22
- function enhance() {
23
- if (isEnhanced(window.history.state))
24
- return;
25
- const stateEnhanced = {
26
- vike: {
27
- timestamp: getTimestamp(),
28
- scrollPosition: getScrollPosition(),
29
- triggeredBy: 'browser',
30
- },
31
- };
32
- replaceHistoryState(stateEnhanced);
33
- }
34
- function getState() {
35
- const state = window.history.state;
36
- // *Every* state added to the history needs to go through Vike.
37
- // - Otherwise Vike's `popstate` listener won't work. (Because, for example, if globalObject.previous is outdated => isHashNavigation faulty => client-side navigation is wrongfully skipped.)
38
- // - Therefore, we have to monkey patch history.pushState() and history.replaceState()
39
- // - Therefore, we need the assert() below to ensure history.state has been enhanced by Vike
40
- // - If users stumble upon this assert() then let's make it a assertUsage()
41
- assertIsEnhanced(state);
42
- return state;
43
- }
44
- function getScrollPosition() {
45
- const scrollPosition = { x: window.scrollX, y: window.scrollY };
46
- return scrollPosition;
47
- }
48
- function getTimestamp() {
49
- return new Date().getTime();
50
- }
51
- function saveScrollPosition(scrollPosition) {
52
- scrollPosition || (scrollPosition = getScrollPosition());
53
- // Don't overwrite history.state if it was set by a non-Vike history.pushState() call.
54
- // https://github.com/vikejs/vike/issues/2801#issuecomment-3490431479
55
- if (!isEnhanced(window.history.state))
18
+ function changeUrl(url, overwriteLastHistoryEntry) {
19
+ if (getCurrentUrl() === url)
56
20
  return;
57
- const state = getState();
58
- replaceHistoryState({ ...state, vike: { ...state.vike, scrollPosition } });
59
- }
60
- function pushHistoryState(url, overwriteLastHistoryEntry) {
61
21
  if (!overwriteLastHistoryEntry) {
62
22
  const state = {
63
23
  vike: {
@@ -67,24 +27,68 @@ function pushHistoryState(url, overwriteLastHistoryEntry) {
67
27
  triggeredBy: 'vike',
68
28
  },
69
29
  };
70
- // Calling the monkey patched history.pushState() (and not the original) so that other tools (e.g. user tracking) can listen to Vike's pushState() calls.
71
- // - https://github.com/vikejs/vike/issues/1582
72
- window.history.pushState(state, '', url);
30
+ historyApiPushState(state, url);
73
31
  }
74
32
  else {
75
- replaceHistoryState(getState(), url);
33
+ historyApiReplaceState(getState(), url);
76
34
  }
77
35
  }
78
- function replaceHistoryState(state, url) {
36
+ function historyApiPushState(state, url) {
37
+ // Calling the monkey patched history.pushState() (not the original) so that other tools (e.g. user tracking) can listen to Vike's pushState() calls.
38
+ // - https://github.com/vikejs/vike/issues/1582
39
+ window.history.pushState(state, '', url);
40
+ assertIsEnhanced(window.history.state);
41
+ }
42
+ function historyApiReplaceState(state, url) {
79
43
  const url_ = url ?? null; // Passing `undefined` chokes older Edge versions.
80
44
  window.history.replaceState(state, '', url_);
81
45
  assertIsEnhanced(window.history.state);
82
46
  }
83
- function replaceHistoryStateOriginal(state, url) {
47
+ function historyApiReplaceStateOriginal(state, url) {
84
48
  // Bypass all monkey patches.
85
49
  // - Useful, for example, to avoid other tools listening to history.replaceState() calls
86
50
  History.prototype.replaceState.bind(window.history)(state, '', url);
87
51
  }
52
+ function onPopStateBegin() {
53
+ const { previous } = globalObject;
54
+ const isStateEnhanced = isEnhanced(window.history.state);
55
+ // Either:
56
+ // - `window.history.pushState(null, '', '/some-path')` , or
57
+ // - hash navigation
58
+ // - Click on `<a href="#some-hash">`
59
+ // - Using the `location` API (only hash navigation)
60
+ // See comments a the top of the ./initOnPopState.ts file.
61
+ const isStatePristine = window.history.state === null;
62
+ if (!isStateEnhanced && !isStatePristine) {
63
+ // Going to a history entry not created by Vike — entering another "SPA realm" => hard reload
64
+ // https://github.com/vikejs/vike/issues/2801#issuecomment-3490431479
65
+ redirectHard(getCurrentUrl());
66
+ return { skip: true };
67
+ }
68
+ if (!isStateEnhanced)
69
+ enhanceState();
70
+ const current = getHistoryInfo();
71
+ globalObject.previous = current;
72
+ // Let the browser handle hash navigations.
73
+ // - Upon hash navigation: `isHistoryStatePristine===true` (see comment above).
74
+ if (isStatePristine) {
75
+ return { skip: true };
76
+ }
77
+ return { previous, current };
78
+ }
79
+ function saveScrollPosition(scrollPosition) {
80
+ scrollPosition || (scrollPosition = getScrollPosition());
81
+ // Don't overwrite history.state if it was set by a non-Vike history.pushState() call.
82
+ // https://github.com/vikejs/vike/issues/2801#issuecomment-3490431479
83
+ if (!isEnhanced(window.history.state))
84
+ return;
85
+ const state = getState();
86
+ historyApiReplaceState({ ...state, vike: { ...state.vike, scrollPosition } });
87
+ }
88
+ function initHistory() {
89
+ monkeyPatchHistoryAPI(); // the earlier we call it the better (Vike can workaround erroneous library monkey patches if Vike is the last one in the monkey patch chain)
90
+ enhanceState(); // enhance very first window.history.state which is `null`
91
+ }
88
92
  // Monkey patch:
89
93
  // - history.pushState()
90
94
  // - history.replaceState()
@@ -114,11 +118,26 @@ function monkeyPatchHistoryAPI() {
114
118
  if (isEnhanced(window.history.state))
115
119
  return;
116
120
  Object.assign(state, window.history.state);
117
- replaceHistoryStateOriginal(state);
121
+ historyApiReplaceStateOriginal(state);
118
122
  });
119
123
  };
120
124
  });
121
125
  }
126
+ function getState() {
127
+ const state = window.history.state;
128
+ // *Every* state added to the history needs to go through Vike.
129
+ // - Otherwise Vike's `popstate` listener won't work. (Because, for example, if globalObject.previous is outdated => isHashNavigation faulty => client-side navigation is wrongfully skipped.)
130
+ // - Therefore, we have to monkey patch history.pushState() and history.replaceState()
131
+ // - Therefore, we need the assert() below to ensure history.state has been enhanced by Vike
132
+ // - If users stumble upon this assert() then let's make it a assertUsage()
133
+ assertIsEnhanced(state);
134
+ return state;
135
+ }
136
+ function assertIsEnhanced(state) {
137
+ if (isEnhanced(state))
138
+ return;
139
+ assert(false, { state });
140
+ }
122
141
  function isEnhanced(state) {
123
142
  if (state?.vike) {
124
143
  /* We don't use the assert() below to save client-side KBs.
@@ -135,10 +154,21 @@ function isEnhanced(state) {
135
154
  }
136
155
  return false;
137
156
  }
138
- function assertIsEnhanced(state) {
139
- if (isEnhanced(state))
157
+ // `window.history.state === null` when:
158
+ // - The very first render
159
+ // - Click on `<a href="#some-hash" />`
160
+ // - `location.hash = 'some-hash'`
161
+ function enhanceState() {
162
+ if (isEnhanced(window.history.state))
140
163
  return;
141
- assert(false, { state });
164
+ const stateEnhanced = {
165
+ vike: {
166
+ timestamp: getTimestamp(),
167
+ scrollPosition: getScrollPosition(),
168
+ triggeredBy: 'browser',
169
+ },
170
+ };
171
+ historyApiReplaceState(stateEnhanced);
142
172
  }
143
173
  function getHistoryInfo() {
144
174
  return {
@@ -146,34 +176,10 @@ function getHistoryInfo() {
146
176
  state: getState(),
147
177
  };
148
178
  }
149
- function onPopStateBegin() {
150
- const { previous } = globalObject;
151
- const isStateEnhanced = isEnhanced(window.history.state);
152
- // Either:
153
- // - `window.history.pushState(null, '', '/some-path')` , or
154
- // - hash navigation
155
- // - Click on `<a href="#some-hash">`
156
- // - Using the `location` API (only hash navigation)
157
- // See comments a the top of the ./initOnPopState.ts file.
158
- const isStatePristine = window.history.state === null;
159
- if (!isStateEnhanced && !isStatePristine) {
160
- // Going to a history entry not created by Vike — entering another "SPA realm" => hard reload
161
- // https://github.com/vikejs/vike/issues/2801#issuecomment-3490431479
162
- redirectHard(getCurrentUrl());
163
- return { skip: true };
164
- }
165
- if (!isStateEnhanced)
166
- enhance();
167
- const current = getHistoryInfo();
168
- globalObject.previous = current;
169
- // Let the browser handle hash navigations.
170
- // - Upon hash navigation: `isHistoryStatePristine===true` (see comment above).
171
- if (isStatePristine) {
172
- return { skip: true };
173
- }
174
- return { previous, current };
179
+ function getScrollPosition() {
180
+ const scrollPosition = { x: window.scrollX, y: window.scrollY };
181
+ return scrollPosition;
175
182
  }
176
- function initHistory() {
177
- monkeyPatchHistoryAPI(); // the earlier we call it the better (Vike can workaround erroneous library monkey patches if Vike is the last one in the monkey patch chain)
178
- enhance(); // enhance very first window.history.state which is `null`
183
+ function getTimestamp() {
184
+ return new Date().getTime();
179
185
  }
@@ -17,7 +17,7 @@ import { createPageContextClient } from './createPageContextClient.js';
17
17
  import { addLinkPrefetchHandlers, addLinkPrefetchHandlers_unwatch, addLinkPrefetchHandlers_watch, getPageContextPrefetched, populatePageContextPrefetchCache, } from './prefetch.js';
18
18
  import { execHookOnRenderClient } from '../shared/execHookOnRenderClient.js';
19
19
  import { isErrorFetchingStaticAssets, loadPageConfigsLazyClientSide, } from '../shared/loadPageConfigsLazyClientSide.js';
20
- import { pushHistoryState, saveScrollPosition } from './history.js';
20
+ import { changeUrl, saveScrollPosition } from './history.js';
21
21
  import { addNewPageContextAborted, getPageContextAddendumAbort, isAbortError, logAbort, } from '../../shared-server-client/route/abort.js';
22
22
  import { route } from '../../shared-server-client/route/index.js';
23
23
  import { isClientSideRoutable } from './isClientSideRoutable.js';
@@ -527,11 +527,6 @@ function stampFinished(urlOriginal) {
527
527
  window._vike ?? (window._vike = {});
528
528
  window._vike.fullyRenderedUrl = urlOriginal;
529
529
  }
530
- function changeUrl(url, overwriteLastHistoryEntry) {
531
- if (getCurrentUrl() === url)
532
- return;
533
- pushHistoryState(url, overwriteLastHistoryEntry);
534
- }
535
530
  function disableClientRouting(err, log) {
536
531
  globalObject.clientRoutingIsDisabled = true;
537
532
  assert(isErrorFetchingStaticAssets(err));
@@ -6,7 +6,7 @@ import { assert } from '../../utils/assert.js';
6
6
  import { onPageHide } from '../../utils/onPageVisibilityChange.js';
7
7
  import { sleep } from '../../utils/sleep.js';
8
8
  import { throttle } from '../../utils/throttle.js';
9
- import { replaceHistoryStateOriginal, saveScrollPosition } from './history.js';
9
+ import { historyApiReplaceStateOriginal, saveScrollPosition } from './history.js';
10
10
  import '../assertEnvClient.js';
11
11
  function setScrollPosition(scrollTarget, url) {
12
12
  if (!scrollTarget && url && hasTextFragment(url)) {
@@ -23,17 +23,18 @@ function setScrollPosition(scrollTarget, url) {
23
23
  const hash = getUrlHash();
24
24
  scrollToHashOrTop(hash);
25
25
  }
26
- // https://github.com/vikejs/vike/issues/2114
27
- // https://github.com/WICG/scroll-to-text-fragment/issues/261
26
+ // Scroll to the DOM element the URL fragment points to, using window.locale.replace()
27
+ // - https://github.com/vikejs/vike/issues/2114
28
+ // - https://github.com/WICG/scroll-to-text-fragment/issues/261
28
29
  function scrollToTextFragment(url) {
29
30
  const stateOriginal = window.history.state;
30
- replaceHistoryStateOriginal(null, url);
31
+ historyApiReplaceStateOriginal(null, url);
31
32
  // We need `history.state===null` before location.replace() so that our 'popstate' handling is correct
32
33
  assert(window.history.state === null);
33
34
  // - Chrome's location.replace() keeps the current state (`history.state===stateOriginal`)
34
35
  // - Firefox's location.replace() replaces the current state with `null` (`history.state===null`)
35
36
  window.location.replace(url);
36
- replaceHistoryStateOriginal(stateOriginal, url);
37
+ historyApiReplaceStateOriginal(stateOriginal, url);
37
38
  }
38
39
  function hasTextFragment(url) {
39
40
  return url.includes('#') && url.includes(':~:text');
@@ -310,7 +310,8 @@ async function handleAssetsManifest_getBuildConfig(config) {
310
310
  if (config.build?.cssMinify === undefined)
311
311
  build.cssMinify = isVite8OrAbove(config) ? true : 'esbuild';
312
312
  }
313
- if (config.build?.manifest === undefined)
313
+ assertWarning(config.build?.manifest !== false, `Setting Vite's configuration ${pc.cyan('build.manifest')} to ${pc.cyan('false')} is ignored — Vike overrides it to ${pc.cyan('true')} because Vike needs the manifest. Note that Vike removes the manifest from the client-side bundle, see ${pc.underline('https://github.com/vikejs/vike/issues/3505#issuecomment-5563748527')}`, { onlyOnce: true });
314
+ if (config.build?.manifest === undefined || config.build?.manifest === false)
314
315
  build.manifest = true;
315
316
  /* Already set by vike:build:pluginBuildApp
316
317
  if (config.build?.copyPublicDir === undefined) build.copyPublicDir = !isViteServerSide_viteEnvOptional(config)
@@ -15,6 +15,7 @@ import { requireResolveOptional } from '../../../../utils/requireResolve.js';
15
15
  import { setTimeoutUnref } from '../../../../utils/setTimeoutUnref.js';
16
16
  import { isObject } from '../../../../utils/isObject.js';
17
17
  import { toPosixPath } from '../../../../utils/path.js';
18
+ import { PROJECT_VERSION } from '../../../../utils/PROJECT_VERSION.js';
18
19
  import { unique } from '../../../../utils/unique.js';
19
20
  import { getVikeConfigInternal } from '../../shared/resolveVikeConfigInternal.js';
20
21
  import { getCacheValue, setCacheValue } from '../../shared/cache.js';
@@ -25,19 +26,19 @@ const globalObject = getGlobalObject('logSkillHint.ts', {
25
26
  alreadyChecked: false,
26
27
  });
27
28
  const docsUrl = 'https://vike.dev/ai#skill';
28
- const tellAgent = `by telling your agent "${pc.cyan(`Install skill ${docsUrl}`)}"`;
29
- const suppressHint = `set ${pc.cyan('+ai.skill')} to ${pc.cyan('false')} to suppress this log`;
30
- const logMissing = `Add Vike's skill for AI agents (Claude Code, Codex, Cursor, ...) ${tellAgent}, or ${suppressHint}`;
29
+ const seeDocs = `— see ${pc.underline(docsUrl)}`;
30
+ const suppressHint = `set ${pc.cyan('+ai.skill')} to ${pc.cyan('false')} to suppress this log.`;
31
+ const logMissing = `Add Vike's skill for AI agents (Claude Code, Codex, Cursor, ...) ${seeDocs}, or ${suppressHint}`;
31
32
  const logOutdated = (skillFilePaths) => {
32
33
  const isPlural = skillFilePaths.length > 1;
33
34
  const files = skillFilePaths.map((f) => pc.cyan(f)).join(', ');
34
- return `Your Vike skill${isPlural ? 's' : ''} ${files} ${isPlural ? "don't" : "doesn't"} match the official ${pc.cyan('vike/SKILL.md')}, update ${isPlural ? 'them' : 'it'} ${tellAgent}, or, if you maintain your own version, ${suppressHint}`;
35
+ return `Your Vike skill${isPlural ? 's' : ''} ${files} ${isPlural ? "don't" : "doesn't"} match the official ${pc.cyan('vike/SKILL.md')}, update ${isPlural ? 'them' : 'it'} ${seeDocs}, or, if you maintain your own version, ${suppressHint}`;
35
36
  };
36
37
  const skillName = 'vike';
37
38
  // The skill file shipped by the vike npm package: node_modules/vike/skills/vike/SKILL.md (see packages/vike/scripts/copySkill.mjs)
38
39
  const skillFilePathInsidePackage = 'skills/vike/SKILL.md';
39
40
  // Cache entry at node_modules/.vike/cache.json, see cache.ts
40
- // - `false` => the check didn't log anything last time => skip the check (forever, until node_modules/ is removed)
41
+ // - `{ skip: true, version }` => the check didn't log anything last time, with that Vike version => skip the check until Vike is upgraded (the official skill file may change between Vike versions) or node_modules/ is removed
41
42
  // - Nothing is written as long as the hint is logged => the check is re-run upon every dev start
42
43
  const cacheKey = 'logSkillHint';
43
44
  // Log a hint if the user didn't install Vike's skill for AI agents (vike/SKILL.md), or if it differs from the official one — https://vike.dev/ai#skill
@@ -95,8 +96,9 @@ async function checkSkillUnsafe(userRootDir) {
95
96
  if (!getConfigValueAiSkill(vikeConfig))
96
97
  return;
97
98
  globalObject.alreadyChecked = true;
98
- // The check is skipped forever once it didn't log anything (until node_modules/ is removed) — see cacheKey
99
- if ((await getCacheValue(userRootDir, cacheKey)) === false)
99
+ // The check is skipped once it didn't log anything, until Vike is upgraded (or node_modules/ is removed) — see cacheKey
100
+ const cached = await getCacheValue(userRootDir, cacheKey);
101
+ if (isObject(cached) && cached.skip === true && cached.version === PROJECT_VERSION)
100
102
  return;
101
103
  const skillState = await getSkillState(userRootDir);
102
104
  if (skillState.state === 'missing') {
@@ -110,7 +112,7 @@ async function checkSkillUnsafe(userRootDir) {
110
112
  if (skillState.state === 'installed' ||
111
113
  skillState.state === 'not-using-ai-agents' ||
112
114
  skillState.state === 'vike-not-from-npm') {
113
- await setCacheValue(userRootDir, cacheKey, false);
115
+ await setCacheValue(userRootDir, cacheKey, { skip: true, version: PROJECT_VERSION });
114
116
  return;
115
117
  }
116
118
  checkType(skillState);
@@ -148,7 +150,7 @@ function getConfigValueAiSkill(vikeConfig) {
148
150
  const skill = configAi.skill;
149
151
  if (skill === undefined)
150
152
  return true;
151
- assertUsage(typeof skill === 'boolean', `${pc.cyan('+ai.skill')} should be a boolean, see ${pc.underline('https://vike.dev/ai#skill')}`);
153
+ assertUsage(typeof skill === 'boolean', `${pc.cyan('+ai.skill')} should be a boolean, see ${pc.underline(docsUrl)}`);
152
154
  return skill;
153
155
  }
154
156
  // The root directory of the user's Git repository — skills directories usually live at the repository root (e.g. monorepos).
@@ -1 +1 @@
1
- export declare const PROJECT_VERSION: '0.4.265';
1
+ export declare const PROJECT_VERSION: '0.4.266-commit-e71fad0';
@@ -1,2 +1,2 @@
1
1
  // Automatically updated by @brillout/release-me
2
- export const PROJECT_VERSION = '0.4.265';
2
+ export const PROJECT_VERSION = '0.4.266-commit-e71fad0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vike",
3
- "version": "0.4.265",
3
+ "version": "0.4.266-commit-e71fad0",
4
4
  "repository": "https://github.com/vikejs/vike",
5
5
  "exports": {
6
6
  "./server": {
@@ -137,7 +137,7 @@
137
137
  "es-module-lexer": "^1.0.0",
138
138
  "esbuild": ">=0.19.0",
139
139
  "json5": "^2.0.0",
140
- "magic-string": "^1.2.3",
140
+ "magic-string": "^1.3.1",
141
141
  "picomatch": "^4.0.7",
142
142
  "semver": "^7.8.5",
143
143
  "sirv": "^3.0.2",