vike 0.4.199-commit-5883046 → 0.4.199-commit-dc15087
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.
- package/dist/cjs/node/prerender/runPrerender.js +3 -1
- package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
- package/dist/esm/client/client-routing-runtime/history.d.ts +14 -3
- package/dist/esm/client/client-routing-runtime/history.js +59 -40
- package/dist/esm/client/client-routing-runtime/initOnPopState.d.ts +3 -13
- package/dist/esm/client/client-routing-runtime/initOnPopState.js +16 -25
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.d.ts +1 -0
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +8 -3
- package/dist/esm/node/prerender/runPrerender.js +3 -1
- package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
- package/dist/esm/utils/PROJECT_VERSION.js +1 -1
- package/dist/esm/utils/projectInfo.d.ts +1 -1
- package/package.json +1 -1
|
@@ -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);
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { pushHistoryState };
|
|
2
|
+
export { onPopStateBegin };
|
|
3
|
+
export { saveScrollPosition };
|
|
4
|
+
export type { HistoryInfo };
|
|
5
|
+
export type { ScrollPosition };
|
|
2
6
|
type StateEnhanced = {
|
|
3
7
|
timestamp: number;
|
|
4
8
|
scrollPosition: null | ScrollPosition;
|
|
@@ -9,7 +13,14 @@ type ScrollPosition = {
|
|
|
9
13
|
x: number;
|
|
10
14
|
y: number;
|
|
11
15
|
};
|
|
12
|
-
declare function enhanceHistoryState(): void;
|
|
13
|
-
declare function getHistoryState(): StateEnhanced;
|
|
14
16
|
declare function saveScrollPosition(): void;
|
|
15
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,7 +1,9 @@
|
|
|
1
|
-
export {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export { pushHistoryState };
|
|
2
|
+
export { onPopStateBegin };
|
|
3
|
+
export { saveScrollPosition };
|
|
4
|
+
import { assert, assertUsage, getCurrentUrl, getGlobalObject, hasProp, isObject } from './utils.js';
|
|
4
5
|
init();
|
|
6
|
+
const globalObject = getGlobalObject('history.ts', { previous: getHistoryInfo() });
|
|
5
7
|
// `window.history.state === null` when:
|
|
6
8
|
// - The very first render
|
|
7
9
|
// - Click on `<a href="#some-hash" />`
|
|
@@ -38,11 +40,13 @@ function enhance(stateNotEnhanced) {
|
|
|
38
40
|
assert(isVikeEnhanced(stateVikeEnhanced));
|
|
39
41
|
return stateVikeEnhanced;
|
|
40
42
|
}
|
|
41
|
-
function
|
|
43
|
+
function getState() {
|
|
42
44
|
const state = getStateNotEnhanced();
|
|
43
|
-
//
|
|
44
|
-
// -
|
|
45
|
-
// -
|
|
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 wrongfully skipped.)
|
|
47
|
+
// - Therefore, we monkey patch history.pushState() and history.replaceState()
|
|
48
|
+
// - Therefore, we assert() below that history.state has been enhanced by Vike
|
|
49
|
+
// - If users stumble upon this assert() then make it a assertUsage()
|
|
46
50
|
assert(isVikeEnhanced(state));
|
|
47
51
|
return state;
|
|
48
52
|
}
|
|
@@ -50,11 +54,6 @@ function getStateNotEnhanced() {
|
|
|
50
54
|
const state = window.history.state;
|
|
51
55
|
return state;
|
|
52
56
|
}
|
|
53
|
-
function getHistoryState() {
|
|
54
|
-
if (!initStateEnhanced)
|
|
55
|
-
enhanceHistoryState(); // avoid race condition
|
|
56
|
-
return getStateEnhanced();
|
|
57
|
-
}
|
|
58
57
|
function getScrollPosition() {
|
|
59
58
|
const scrollPosition = { x: window.scrollX, y: window.scrollY };
|
|
60
59
|
return scrollPosition;
|
|
@@ -64,48 +63,54 @@ function getTimestamp() {
|
|
|
64
63
|
}
|
|
65
64
|
function saveScrollPosition() {
|
|
66
65
|
const scrollPosition = getScrollPosition();
|
|
67
|
-
const state =
|
|
66
|
+
const state = getState();
|
|
68
67
|
replaceHistoryState({ ...state, scrollPosition });
|
|
69
68
|
}
|
|
70
69
|
function pushHistoryState(url, overwriteLastHistoryEntry) {
|
|
71
70
|
if (!overwriteLastHistoryEntry) {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
timestamp,
|
|
71
|
+
const state = {
|
|
72
|
+
timestamp: getTimestamp(),
|
|
75
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.
|
|
76
74
|
scrollPosition: null,
|
|
77
75
|
triggeredBy: 'vike',
|
|
78
76
|
_isVikeEnhanced: true
|
|
79
|
-
}
|
|
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);
|
|
80
81
|
}
|
|
81
82
|
else {
|
|
82
|
-
replaceHistoryState(
|
|
83
|
+
replaceHistoryState(getState(), url);
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
function replaceHistoryState(state, url) {
|
|
86
87
|
const url_ = url ?? null; // Passing `undefined` chokes older Edge versions.
|
|
87
88
|
window.history.replaceState(state, '', url_);
|
|
88
89
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
+
});
|
|
109
114
|
}
|
|
110
115
|
function isVikeEnhanced(state) {
|
|
111
116
|
const yes = isObject(state) && '_isVikeEnhanced' in state;
|
|
@@ -126,6 +131,20 @@ function assertStateVikeEnhanced(state) {
|
|
|
126
131
|
}
|
|
127
132
|
function init() {
|
|
128
133
|
enhanceHistoryState();
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
monkeyPatchHistoryAPI();
|
|
135
|
+
}
|
|
136
|
+
function getHistoryInfo() {
|
|
137
|
+
return {
|
|
138
|
+
url: getCurrentUrl(),
|
|
139
|
+
state: getState()
|
|
140
|
+
};
|
|
141
|
+
}
|
|
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 };
|
|
131
150
|
}
|
|
@@ -1,22 +1,12 @@
|
|
|
1
1
|
export { initOnPopState };
|
|
2
|
-
export { updateState };
|
|
3
2
|
export { onPopState };
|
|
3
|
+
import { type HistoryInfo } from './history.js';
|
|
4
4
|
declare function initOnPopState(): void;
|
|
5
5
|
type Listener = (arg: {
|
|
6
|
-
previous:
|
|
6
|
+
previous: HistoryInfo;
|
|
7
7
|
}) => void | boolean;
|
|
8
|
-
/** Control
|
|
8
|
+
/** Control back-/forward navigation.
|
|
9
9
|
*
|
|
10
10
|
* https://vike.dev/onPopState
|
|
11
11
|
*/
|
|
12
12
|
declare function onPopState(listener: Listener): void;
|
|
13
|
-
declare function getInfo(): {
|
|
14
|
-
url: `/${string}`;
|
|
15
|
-
state: {
|
|
16
|
-
timestamp: number;
|
|
17
|
-
scrollPosition: null | import("./history.js").ScrollPosition;
|
|
18
|
-
triggeredBy: "user" | "vike" | "browser";
|
|
19
|
-
_isVikeEnhanced: true;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
declare function updateState(): void;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
export { initOnPopState };
|
|
2
|
-
export { updateState };
|
|
3
2
|
export { onPopState };
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { getGlobalObject } from './utils.js';
|
|
4
|
+
import { onPopStateBegin } from './history.js';
|
|
6
5
|
import { renderPageClientSide } from './renderPageClientSide.js';
|
|
7
6
|
import { setScrollPosition } from './setScrollPosition.js';
|
|
8
|
-
const globalObject = getGlobalObject('initOnPopState.ts', {
|
|
7
|
+
const globalObject = getGlobalObject('initOnPopState.ts', { listeners: [] });
|
|
9
8
|
function initOnPopState() {
|
|
10
9
|
// - The popstate event is trigged upon:
|
|
11
10
|
// - Back-/forward navigation.
|
|
@@ -17,18 +16,14 @@ function initOnPopState() {
|
|
|
17
16
|
// - `location.hash = 'some-hash'`
|
|
18
17
|
// - The `event` argument of `window.addEventListener('popstate', (event) => /*...*/)` is useless: the History API doesn't provide the previous state (the popped state), see https://stackoverflow.com/questions/48055323/is-history-state-always-the-same-as-popstate-event-state
|
|
19
18
|
window.addEventListener('popstate', async () => {
|
|
20
|
-
const isNewState
|
|
21
|
-
if (isNewState)
|
|
22
|
-
enhanceHistoryState();
|
|
23
|
-
const { previous } = globalObject;
|
|
24
|
-
const current = getInfo();
|
|
25
|
-
globalObject.previous = current;
|
|
19
|
+
const { isNewState, previous, current } = onPopStateBegin();
|
|
26
20
|
const scrollTarget = current.state.scrollPosition || undefined;
|
|
27
|
-
const
|
|
28
|
-
|
|
21
|
+
const isUserPushStateNavigation = current.state.triggeredBy === 'user' || previous.state.triggeredBy === 'user';
|
|
22
|
+
const isHashNavigation = current.url !== previous.url && removeHash(current.url) === removeHash(previous.url);
|
|
23
|
+
// - `isNewState === true` when:
|
|
29
24
|
// - Click on `<a href="#some-hash" />` (note that Vike's `initOnLinkClick()` handler skips hash links)
|
|
30
25
|
// - `location.hash = 'some-hash'`
|
|
31
|
-
// - `
|
|
26
|
+
// - `isNewState === false` when `popstate` was triggered by the user clicking on his browser's forward/backward history button.
|
|
32
27
|
const isHashNavigationNew = isHashNavigation && isNewState;
|
|
33
28
|
const isBackwardNavigation = !current.state.timestamp || !previous.state.timestamp ? null : current.state.timestamp < previous.state.timestamp;
|
|
34
29
|
// We have to scroll ourselves because we use `window.history.scrollRestoration = 'manual'`. So far this seems to work. Alternatives in case it doesn't work:
|
|
@@ -49,31 +44,27 @@ function initOnPopState() {
|
|
|
49
44
|
}
|
|
50
45
|
return;
|
|
51
46
|
}
|
|
47
|
+
let doNotRenderIfSamePage = isUserPushStateNavigation;
|
|
52
48
|
let abort;
|
|
53
49
|
globalObject.listeners.forEach((listener) => {
|
|
54
50
|
abort || (abort = listener({ previous }));
|
|
55
51
|
});
|
|
56
|
-
if (abort)
|
|
52
|
+
if (abort) {
|
|
57
53
|
return;
|
|
58
|
-
|
|
54
|
+
}
|
|
55
|
+
if (abort === false) {
|
|
56
|
+
doNotRenderIfSamePage = false;
|
|
57
|
+
}
|
|
58
|
+
await renderPageClientSide({ scrollTarget, isBackwardNavigation, doNotRenderIfSamePage });
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
|
-
/** Control
|
|
61
|
+
/** Control back-/forward navigation.
|
|
62
62
|
*
|
|
63
63
|
* https://vike.dev/onPopState
|
|
64
64
|
*/
|
|
65
65
|
function onPopState(listener) {
|
|
66
66
|
globalObject.listeners.push(listener);
|
|
67
67
|
}
|
|
68
|
-
function getInfo() {
|
|
69
|
-
return {
|
|
70
|
-
url: getCurrentUrl(),
|
|
71
|
-
state: getHistoryState()
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
68
|
function removeHash(url) {
|
|
75
69
|
return url.split('#')[0];
|
|
76
70
|
}
|
|
77
|
-
function updateState() {
|
|
78
|
-
globalObject.previous = getInfo();
|
|
79
|
-
}
|
|
@@ -12,6 +12,7 @@ type RenderArgs = {
|
|
|
12
12
|
overwriteLastHistoryEntry?: boolean;
|
|
13
13
|
pageContextsFromRewrite?: PageContextFromRewrite[];
|
|
14
14
|
redirectCount?: number;
|
|
15
|
+
doNotRenderIfSamePage?: boolean;
|
|
15
16
|
isClientSideNavigation?: boolean;
|
|
16
17
|
};
|
|
17
18
|
declare function renderPageClientSide(renderArgs: RenderArgs): Promise<void>;
|
|
@@ -15,7 +15,6 @@ import { assertNoInfiniteAbortLoop, getPageContextFromAllRewrites, isAbortError,
|
|
|
15
15
|
import { route } from '../../shared/route/index.js';
|
|
16
16
|
import { isClientSideRoutable } from './isClientSideRoutable.js';
|
|
17
17
|
import { setScrollPosition } from './setScrollPosition.js';
|
|
18
|
-
import { updateState } from './initOnPopState.js';
|
|
19
18
|
import { browserNativeScrollRestoration_disable, setInitialRenderIsDone } from './scrollRestoration.js';
|
|
20
19
|
import { getErrorPageId } from '../../shared/error-page.js';
|
|
21
20
|
import { setPageContextCurrent } from './getPageContextCurrent.js';
|
|
@@ -30,7 +29,7 @@ const globalObject = getGlobalObject('renderPageClientSide.ts', (() => {
|
|
|
30
29
|
})());
|
|
31
30
|
const { firstRenderStartPromise } = globalObject;
|
|
32
31
|
async function renderPageClientSide(renderArgs) {
|
|
33
|
-
const { urlOriginal = getCurrentUrl(), overwriteLastHistoryEntry = false, isBackwardNavigation, pageContextsFromRewrite = [], redirectCount = 0, isClientSideNavigation = true } = renderArgs;
|
|
32
|
+
const { urlOriginal = getCurrentUrl(), overwriteLastHistoryEntry = false, isBackwardNavigation, pageContextsFromRewrite = [], redirectCount = 0, doNotRenderIfSamePage, isClientSideNavigation = true } = renderArgs;
|
|
34
33
|
let { scrollTarget } = renderArgs;
|
|
35
34
|
const { previousPageContext } = globalObject;
|
|
36
35
|
addLinkPrefetchHandlers_unwatch();
|
|
@@ -117,6 +116,13 @@ async function renderPageClientSide(renderArgs) {
|
|
|
117
116
|
redirectHard(urlOriginal);
|
|
118
117
|
return;
|
|
119
118
|
}
|
|
119
|
+
const isSamePage = pageContextFromRoute.pageId &&
|
|
120
|
+
previousPageContext?.pageId &&
|
|
121
|
+
pageContextFromRoute.pageId === previousPageContext.pageId;
|
|
122
|
+
if (doNotRenderIfSamePage && isSamePage) {
|
|
123
|
+
// Skip's Vike's rendering; let the user handle the navigation
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
120
126
|
// TODO/eventually: create helper assertPageContextFromHook()
|
|
121
127
|
assert(!('urlOriginal' in pageContextFromRoute));
|
|
122
128
|
objectAssign(pageContext, pageContextFromRoute);
|
|
@@ -470,7 +476,6 @@ function changeUrl(url, overwriteLastHistoryEntry) {
|
|
|
470
476
|
return;
|
|
471
477
|
browserNativeScrollRestoration_disable();
|
|
472
478
|
pushHistoryState(url, overwriteLastHistoryEntry);
|
|
473
|
-
updateState();
|
|
474
479
|
}
|
|
475
480
|
function handleErrorFetchingStaticAssets(err, pageContext, isFirstRender) {
|
|
476
481
|
if (!isErrorFetchingStaticAssets(err)) {
|
|
@@ -577,7 +577,9 @@ async function write(urlOriginal, pageContext, fileExtension, fileContent, root,
|
|
|
577
577
|
assertPosixPath(fileUrl);
|
|
578
578
|
assert(fileUrl.startsWith('/'));
|
|
579
579
|
const filePathRelative = fileUrl.slice(1);
|
|
580
|
-
assert(!filePathRelative.startsWith('/')
|
|
580
|
+
assert(!filePathRelative.startsWith('/'),
|
|
581
|
+
// Let's remove this debug info after we add a assertUsage() avoiding https://github.com/vikejs/vike/issues/1929
|
|
582
|
+
{ urlOriginal, fileUrl });
|
|
581
583
|
assertPosixPath(outDirClient);
|
|
582
584
|
assertPosixPath(filePathRelative);
|
|
583
585
|
const filePath = path.posix.join(outDirClient, filePathRelative);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PROJECT_VERSION: "0.4.199-commit-
|
|
1
|
+
export declare const PROJECT_VERSION: "0.4.199-commit-dc15087";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Automatically updated by @brillout/release-me
|
|
2
|
-
export const PROJECT_VERSION = '0.4.199-commit-
|
|
2
|
+
export const PROJECT_VERSION = '0.4.199-commit-dc15087';
|