vike 0.4.199 → 0.4.200
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/client/router.js +3 -1
- package/dist/cjs/node/plugin/plugins/envVars.js +3 -0
- package/dist/cjs/node/plugin/plugins/extractAssetsPlugin.js +2 -0
- package/dist/cjs/node/plugin/plugins/extractExportNamesPlugin.js +2 -0
- package/dist/cjs/node/plugin/plugins/fileEnv.js +2 -0
- package/dist/cjs/node/plugin/plugins/importBuild/index.js +4 -4
- package/dist/cjs/node/plugin/plugins/importUserCode/index.js +7 -6
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +1 -1
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +1 -1
- package/dist/cjs/node/plugin/shared/normalizeId.js +9 -0
- package/dist/cjs/node/prerender/runPrerender.js +3 -1
- package/dist/cjs/node/runtime/globalContext/loadImportBuild.js +1 -1
- package/dist/cjs/node/runtime/renderPage.js +15 -5
- package/dist/cjs/utils/PROJECT_VERSION.js +1 -1
- package/dist/cjs/utils/parseUrl-extras.js +4 -3
- package/dist/esm/client/client-routing-runtime/history.d.ts +19 -9
- package/dist/esm/client/client-routing-runtime/history.js +121 -68
- package/dist/esm/client/client-routing-runtime/index.d.ts +1 -0
- package/dist/esm/client/client-routing-runtime/index.js +1 -0
- package/dist/esm/client/client-routing-runtime/initClientRouter.js +2 -5
- package/dist/esm/client/client-routing-runtime/initOnPopState.d.ts +12 -0
- package/dist/esm/client/client-routing-runtime/initOnPopState.js +72 -0
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.d.ts +1 -2
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +4 -6
- package/dist/esm/node/client/router.d.ts +2 -0
- package/dist/esm/node/client/router.js +2 -0
- package/dist/esm/node/plugin/plugins/envVars.js +3 -0
- package/dist/esm/node/plugin/plugins/extractAssetsPlugin.js +2 -0
- package/dist/esm/node/plugin/plugins/extractExportNamesPlugin.js +2 -0
- package/dist/esm/node/plugin/plugins/fileEnv.js +2 -0
- package/dist/esm/node/plugin/plugins/importBuild/index.js +5 -5
- package/dist/esm/node/plugin/plugins/importUserCode/index.js +8 -7
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/transpileAndExecuteFile.js +1 -1
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js +1 -1
- package/dist/esm/node/plugin/shared/normalizeId.d.ts +2 -0
- package/dist/esm/node/plugin/shared/normalizeId.js +7 -0
- package/dist/esm/node/prerender/runPrerender.js +3 -1
- package/dist/esm/node/runtime/globalContext/loadImportBuild.js +2 -2
- package/dist/esm/node/runtime/renderPage.js +16 -6
- package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -1
- package/dist/esm/utils/PROJECT_VERSION.js +1 -1
- package/dist/esm/utils/getCurrentUrl.d.ts +1 -1
- package/dist/esm/utils/parseUrl-extras.d.ts +2 -2
- package/dist/esm/utils/parseUrl-extras.js +4 -3
- package/dist/esm/utils/projectInfo.d.ts +1 -1
- package/package.json +2 -11
- package/dist/esm/client/client-routing-runtime/onBrowserHistoryNavigation.d.ts +0 -4
- 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.
|
|
33
|
-
|
|
34
|
-
return
|
|
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
|
|
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)) {
|
|
@@ -88,7 +88,7 @@ async function transpileWithEsbuild(filePath, userRootDir, transformImports) {
|
|
|
88
88
|
metafile: true,
|
|
89
89
|
bundle: true
|
|
90
90
|
};
|
|
91
|
-
|
|
91
|
+
const pointerImports = {};
|
|
92
92
|
options.plugins = [
|
|
93
93
|
// Determine whether an import should be:
|
|
94
94
|
// - A pointer import
|
package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
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
|
|
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) {
|
|
@@ -6,7 +6,7 @@ exports.normalizeUrlPathname = normalizeUrlPathname;
|
|
|
6
6
|
exports.removeBaseServer = removeBaseServer;
|
|
7
7
|
exports.modifyUrlPathname = modifyUrlPathname;
|
|
8
8
|
exports.removeUrlOrigin = removeUrlOrigin;
|
|
9
|
-
exports.
|
|
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
|
|
99
|
+
function setUrlOrigin(url, origin) {
|
|
100
100
|
const { origin: originCurrent, pathnameOriginal, searchOriginal, hashOriginal } = (0, parseUrl_js_1.parseUrl)(url, '/');
|
|
101
|
-
|
|
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 {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
16
|
-
|
|
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 {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
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 =
|
|
66
|
+
const state = getState();
|
|
47
67
|
replaceHistoryState({ ...state, scrollPosition });
|
|
48
68
|
}
|
|
49
|
-
function
|
|
69
|
+
function pushHistoryState(url, overwriteLastHistoryEntry) {
|
|
50
70
|
if (!overwriteLastHistoryEntry) {
|
|
51
|
-
const
|
|
52
|
-
|
|
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(
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
|
96
|
-
|
|
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
|
|
@@ -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 {
|
|
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
|
-
|
|
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;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export { initOnPopState };
|
|
2
|
+
export { onPopState };
|
|
3
|
+
import { assertWarning, getGlobalObject } from './utils.js';
|
|
4
|
+
import { onPopStateBegin } from './history.js';
|
|
5
|
+
import { renderPageClientSide } from './renderPageClientSide.js';
|
|
6
|
+
import { setScrollPosition } from './setScrollPosition.js';
|
|
7
|
+
const globalObject = getGlobalObject('initOnPopState.ts', { listeners: [] });
|
|
8
|
+
function initOnPopState() {
|
|
9
|
+
// - The popstate event is trigged upon:
|
|
10
|
+
// - Back-/forward navigation.
|
|
11
|
+
// - By user clicking on his browser's back-/forward navigation (or using a shortcut)
|
|
12
|
+
// - By JavaScript: `history.back()` / `history.forward()`
|
|
13
|
+
// - URL hash change.
|
|
14
|
+
// - Click on `<a href="#some-hash" />`
|
|
15
|
+
// - The popstate event is *only* triggered if `href` starts with '#' (even if `href` is '/#some-hash' while the current URL's pathname is '/' then the popstate still isn't triggered)
|
|
16
|
+
// - `location.hash = 'some-hash'`
|
|
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
|
|
18
|
+
window.addEventListener('popstate', async () => {
|
|
19
|
+
const { isNewState, previous, current } = onPopStateBegin();
|
|
20
|
+
const scrollTarget = current.state.scrollPosition || undefined;
|
|
21
|
+
const isUserPushStateNavigation = current.state.triggeredBy === 'user' || previous.state.triggeredBy === 'user';
|
|
22
|
+
const isHashNavigation = removeHash(current.url) === removeHash(previous.url) && current.url !== previous.url;
|
|
23
|
+
// - `isNewState === true` when:
|
|
24
|
+
// - Click on `<a href="#some-hash" />` (note that Vike's `initOnLinkClick()` handler skips hash links)
|
|
25
|
+
// - `location.hash = 'some-hash'`
|
|
26
|
+
// - `isNewState === false` when `popstate` was triggered by the user clicking on his browser's forward/backward history button.
|
|
27
|
+
const isHashNavigationNew = isHashNavigation && isNewState;
|
|
28
|
+
const isBackwardNavigation = !current.state.timestamp || !previous.state.timestamp ? null : current.state.timestamp < previous.state.timestamp;
|
|
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:
|
|
30
|
+
// - Alternative: we use `window.history.scrollRestoration = 'auto'`
|
|
31
|
+
// - Problem: I don't think it's possbible to set `window.history.scrollRestoration = 'auto'` only for hash navigation and not for non-hash navigations?
|
|
32
|
+
// - Problem: inconsistencies between browsers? For example specification says that setting `window.history.scrollRestoration` only affects the current entry in the session history but this contradicts what people are experiencing in practice.
|
|
33
|
+
// - Specification: https://html.spec.whatwg.org/multipage/history.html#the-history-interface
|
|
34
|
+
// - Practice: https://stackoverflow.com/questions/70188241/history-scrollrestoration-manual-doesnt-prevent-safari-from-restoring-scrol
|
|
35
|
+
// - Alternative: we completely take over hash navigation and reproduce the browser's native behavior upon hash navigation.
|
|
36
|
+
// - By using the `hashchange` event.
|
|
37
|
+
// - Problem: conflict if user wants to override the browser's default behavior? E.g. for smooth scrolling, or when using hashes for saving states of some fancy animations.
|
|
38
|
+
if (isHashNavigation) {
|
|
39
|
+
if (!isHashNavigationNew) {
|
|
40
|
+
setScrollPosition(scrollTarget);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
// The browser already scrolled to `#${hash}` => the current scroll position is the right one => we saved it with `enhanceHistoryState()`.
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
let doNotRenderIfSamePage = isUserPushStateNavigation;
|
|
48
|
+
let abort;
|
|
49
|
+
globalObject.listeners.forEach((listener) => {
|
|
50
|
+
abort || (abort = listener({ previous }));
|
|
51
|
+
});
|
|
52
|
+
if (abort) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (abort === false) {
|
|
56
|
+
doNotRenderIfSamePage = false;
|
|
57
|
+
}
|
|
58
|
+
await renderPageClientSide({ scrollTarget, isBackwardNavigation, doNotRenderIfSamePage });
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// TODO/eventually: deprecate this onPopState(listener) function and let the user define +onPopState.js instead?
|
|
62
|
+
/** Control back-/forward navigation.
|
|
63
|
+
*
|
|
64
|
+
* https://vike.dev/onPopState
|
|
65
|
+
*/
|
|
66
|
+
function onPopState(listener) {
|
|
67
|
+
assertWarning(false, 'onPopState() is experimental', { onlyOnce: true });
|
|
68
|
+
globalObject.listeners.push(listener);
|
|
69
|
+
}
|
|
70
|
+
function removeHash(url) {
|
|
71
|
+
return url.split('#')[0];
|
|
72
|
+
}
|
|
@@ -12,8 +12,7 @@ type RenderArgs = {
|
|
|
12
12
|
overwriteLastHistoryEntry?: boolean;
|
|
13
13
|
pageContextsFromRewrite?: PageContextFromRewrite[];
|
|
14
14
|
redirectCount?: number;
|
|
15
|
-
|
|
16
|
-
isUserLandPushStateNavigation?: boolean;
|
|
15
|
+
doNotRenderIfSamePage?: boolean;
|
|
17
16
|
isClientSideNavigation?: boolean;
|
|
18
17
|
};
|
|
19
18
|
declare function renderPageClientSide(renderArgs: RenderArgs): Promise<void>;
|
|
@@ -10,12 +10,11 @@ import { assertInfo, assertWarning, isReact } from './utils.js';
|
|
|
10
10
|
import { executeOnRenderClientHook } from '../shared/executeOnRenderClientHook.js';
|
|
11
11
|
import { assertHook, getHook } from '../../shared/hooks/getHook.js';
|
|
12
12
|
import { isErrorFetchingStaticAssets, loadUserFilesClientSide } from '../shared/loadUserFilesClientSide.js';
|
|
13
|
-
import {
|
|
13
|
+
import { pushHistoryState } from './history.js';
|
|
14
14
|
import { assertNoInfiniteAbortLoop, getPageContextFromAllRewrites, isAbortError, logAbortErrorHandled } from '../../shared/route/abort.js';
|
|
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 './onBrowserHistoryNavigation.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,
|
|
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();
|
|
@@ -120,7 +119,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
120
119
|
const isSamePage = pageContextFromRoute.pageId &&
|
|
121
120
|
previousPageContext?.pageId &&
|
|
122
121
|
pageContextFromRoute.pageId === previousPageContext.pageId;
|
|
123
|
-
if (
|
|
122
|
+
if (doNotRenderIfSamePage && isSamePage) {
|
|
124
123
|
// Skip's Vike's rendering; let the user handle the navigation
|
|
125
124
|
return;
|
|
126
125
|
}
|
|
@@ -476,8 +475,7 @@ function changeUrl(url, overwriteLastHistoryEntry) {
|
|
|
476
475
|
if (getCurrentUrl() === url)
|
|
477
476
|
return;
|
|
478
477
|
browserNativeScrollRestoration_disable();
|
|
479
|
-
|
|
480
|
-
updateState();
|
|
478
|
+
pushHistoryState(url, overwriteLastHistoryEntry);
|
|
481
479
|
}
|
|
482
480
|
function handleErrorFetchingStaticAssets(err, pageContext, isFirstRender) {
|
|
483
481
|
if (!isErrorFetchingStaticAssets(err)) {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
export { navigate };
|
|
2
2
|
export { reload };
|
|
3
3
|
export { prefetch };
|
|
4
|
+
export { onPopState };
|
|
4
5
|
import { assertWarning } from '../../utils/assert.js';
|
|
5
6
|
// `never` to ensure package.json#exports["./client/router"].types points to type defined by the client-side code
|
|
6
7
|
const navigate = (() => warnNoEffect('navigate'));
|
|
7
8
|
const reload = (() => warnNoEffect('reload'));
|
|
8
9
|
const prefetch = (() => warnNoEffect('prefetch'));
|
|
10
|
+
const onPopState = (() => { });
|
|
9
11
|
function warnNoEffect(caller) {
|
|
10
12
|
assertWarning(false, `Calling ${caller}() on the server-side has no effect`, {
|
|
11
13
|
showStackTrace: true,
|
|
@@ -3,6 +3,7 @@ import { loadEnv } from 'vite';
|
|
|
3
3
|
import { assert, assertPosixPath, assertUsage, assertWarning, escapeRegex, isArray, lowerFirst } from '../utils.js';
|
|
4
4
|
import { sourceMapPassthrough } from '../shared/rollupSourceMap.js';
|
|
5
5
|
import { getModuleFilePathAbsolute } from '../shared/getFilePath.js';
|
|
6
|
+
import { normalizeId } from '../shared/normalizeId.js';
|
|
6
7
|
// TODO/enventually: (after we implemented vike.config.js)
|
|
7
8
|
// - Make import.meta.env work inside +config.js
|
|
8
9
|
// - 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
|
|
@@ -25,9 +26,11 @@ function envVarsPlugin() {
|
|
|
25
26
|
config.plugins.sort(lowerFirst((plugin) => (plugin.name === 'vite:define' ? 1 : 0)));
|
|
26
27
|
},
|
|
27
28
|
transform(code, id, options) {
|
|
29
|
+
id = normalizeId(id);
|
|
28
30
|
assertPosixPath(id);
|
|
29
31
|
if (id.includes('/node_modules/'))
|
|
30
32
|
return;
|
|
33
|
+
assertPosixPath(config.root);
|
|
31
34
|
if (!id.startsWith(config.root))
|
|
32
35
|
return;
|
|
33
36
|
if (!code.includes('import.meta.env.'))
|
|
@@ -16,6 +16,7 @@ import pc from '@brillout/picocolors';
|
|
|
16
16
|
import { fixServerAssets_isEnabled } from './buildConfig/fixServerAssets.js';
|
|
17
17
|
import { getVikeConfig, isV1Design } from './importUserCode/v1-design/getVikeConfig.js';
|
|
18
18
|
import { assertV1Design } from '../../shared/assertV1Design.js';
|
|
19
|
+
import { normalizeId } from '../shared/normalizeId.js';
|
|
19
20
|
const extractAssetsRE = /(\?|&)extractAssets(?:&|$)/;
|
|
20
21
|
const rawRE = /(\?|&)raw(?:&|$)/;
|
|
21
22
|
const urlRE = /(\?|&)url(?:&|$)/;
|
|
@@ -34,6 +35,7 @@ function extractAssetsPlugin() {
|
|
|
34
35
|
apply: 'build',
|
|
35
36
|
enforce: 'post',
|
|
36
37
|
async transform(src, id, options) {
|
|
38
|
+
id = normalizeId(id);
|
|
37
39
|
if (!extractAssetsRE.test(id)) {
|
|
38
40
|
return;
|
|
39
41
|
}
|
|
@@ -4,6 +4,7 @@ export { extractExportNamesRE };
|
|
|
4
4
|
import { assert, getFileExtension, viteIsSSR_options, createDebugger, getGlobalObject, assertUsage } from '../utils.js';
|
|
5
5
|
import { getExportNames } from '../shared/parseEsModule.js';
|
|
6
6
|
import { sourceMapRemove } from '../shared/rollupSourceMap.js';
|
|
7
|
+
import { normalizeId } from '../shared/normalizeId.js';
|
|
7
8
|
const extractExportNamesRE = /(\?|&)extractExportNames(?:&|$)/;
|
|
8
9
|
const debug = createDebugger('vike:extractExportNames');
|
|
9
10
|
const globalObject = getGlobalObject('extractExportNamesPlugin.ts', {});
|
|
@@ -13,6 +14,7 @@ function extractExportNamesPlugin() {
|
|
|
13
14
|
name: 'vike:extractExportNames',
|
|
14
15
|
enforce: 'post',
|
|
15
16
|
async transform(src, id, options) {
|
|
17
|
+
id = normalizeId(id);
|
|
16
18
|
const isClientSide = !viteIsSSR_options(options);
|
|
17
19
|
if (extractExportNamesRE.test(id)) {
|
|
18
20
|
const code = await getExtractExportNamesCode(src, isClientSide, !isDev, id);
|
|
@@ -6,6 +6,7 @@ import pc from '@brillout/picocolors';
|
|
|
6
6
|
import { getModuleFilePathAbsolute } from '../shared/getFilePath.js';
|
|
7
7
|
import { sourceMapRemove } from '../shared/rollupSourceMap.js';
|
|
8
8
|
import { getExportNames } from '../shared/parseEsModule.js';
|
|
9
|
+
import { normalizeId } from '../shared/normalizeId.js';
|
|
9
10
|
function fileEnv() {
|
|
10
11
|
let config;
|
|
11
12
|
let viteDevServer;
|
|
@@ -31,6 +32,7 @@ function fileEnv() {
|
|
|
31
32
|
},
|
|
32
33
|
// 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.
|
|
33
34
|
async transform(code, id, options) {
|
|
35
|
+
id = normalizeId(id);
|
|
34
36
|
// In dev, only using load() is enough as it also works for dynamic imports (see sibling comment).
|
|
35
37
|
if (viteDevServer)
|
|
36
38
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { importBuild };
|
|
2
2
|
export { set_ASSETS_MAP };
|
|
3
|
-
import {
|
|
3
|
+
import { serverProductionEntryPlugin } from '@brillout/vite-plugin-server-entry/plugin';
|
|
4
4
|
import { assert, getOutDirs, toPosixPath } from '../../utils.js';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { createRequire } from 'module';
|
|
@@ -24,15 +24,15 @@ function importBuild() {
|
|
|
24
24
|
configVike = await getConfigVike(config);
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
-
...
|
|
28
|
-
|
|
29
|
-
return
|
|
27
|
+
...serverProductionEntryPlugin({
|
|
28
|
+
getServerProductionEntry: () => {
|
|
29
|
+
return getServerProductionEntryCode(config, configVike);
|
|
30
30
|
},
|
|
31
31
|
libraryName: 'Vike'
|
|
32
32
|
})
|
|
33
33
|
];
|
|
34
34
|
}
|
|
35
|
-
function
|
|
35
|
+
function getServerProductionEntryCode(config, configVike) {
|
|
36
36
|
const importPath = getImportPath(config);
|
|
37
37
|
const vikeManifest = getVikeManifest(configVike);
|
|
38
38
|
const importerCode = [
|
|
@@ -6,7 +6,7 @@ import { getVirtualFileImportUserCode } from './getVirtualFileImportUserCode.js'
|
|
|
6
6
|
import { assert, assertPosixPath, getOutDirs, getVirtualFileId, isDev3, isVirtualFileId, resolveVirtualFileId } from '../../utils.js';
|
|
7
7
|
import { isVirtualFileIdPageConfigValuesAll } from '../../../shared/virtual-files/virtualFilePageConfigValuesAll.js';
|
|
8
8
|
import { isVirtualFileIdImportUserCode } from '../../../shared/virtual-files/virtualFileImportUserCode.js';
|
|
9
|
-
import { vikeConfigDependencies, reloadVikeConfig, isVikeConfigFile } from './v1-design/getVikeConfig.js';
|
|
9
|
+
import { vikeConfigDependencies, reloadVikeConfig, isVikeConfigFile, isV1Design } from './v1-design/getVikeConfig.js';
|
|
10
10
|
import pc from '@brillout/picocolors';
|
|
11
11
|
import { logConfigInfo } from '../../shared/loggerNotProd.js';
|
|
12
12
|
import { getModuleFilePathAbsolute } from '../../shared/getFilePath.js';
|
|
@@ -18,16 +18,17 @@ function importUserCode() {
|
|
|
18
18
|
name: 'vike:importUserCode',
|
|
19
19
|
config(_, env) {
|
|
20
20
|
isDev = isDev3(env);
|
|
21
|
-
return {
|
|
22
|
-
experimental: {
|
|
23
|
-
// TODO/v1-release: remove
|
|
24
|
-
importGlobRestoreExtension: true
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
21
|
},
|
|
28
22
|
async configResolved(config_) {
|
|
29
23
|
configVike = await getConfigVike(config_);
|
|
30
24
|
config = config_;
|
|
25
|
+
// TODO/v1-release: remove
|
|
26
|
+
{
|
|
27
|
+
assert(isDev !== undefined);
|
|
28
|
+
const isV1 = await isV1Design(config, isDev);
|
|
29
|
+
if (!isV1)
|
|
30
|
+
config.experimental.importGlobRestoreExtension = true;
|
|
31
|
+
}
|
|
31
32
|
},
|
|
32
33
|
resolveId(id) {
|
|
33
34
|
if (isVirtualFileId(id)) {
|
|
@@ -83,7 +83,7 @@ async function transpileWithEsbuild(filePath, userRootDir, transformImports) {
|
|
|
83
83
|
metafile: true,
|
|
84
84
|
bundle: true
|
|
85
85
|
};
|
|
86
|
-
|
|
86
|
+
const pointerImports = {};
|
|
87
87
|
options.plugins = [
|
|
88
88
|
// Determine whether an import should be:
|
|
89
89
|
// - A pointer import
|
package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigValuesAll.js
CHANGED
|
@@ -21,7 +21,7 @@ async function getVirtualFilePageConfigValuesAll(id, isDev, config) {
|
|
|
21
21
|
const { pageId, isForClientSide } = result;
|
|
22
22
|
const { pageConfigs } = await getVikeConfig(config, isDev, { tolerateInvalidConfig: true });
|
|
23
23
|
const pageConfig = pageConfigs.find((pageConfig) => pageConfig.pageId === pageId);
|
|
24
|
-
assert(pageConfig);
|
|
24
|
+
assert(pageConfig, { id, pageId });
|
|
25
25
|
const configVike = await getConfigVike(config);
|
|
26
26
|
const code = getLoadConfigValuesAll(pageConfig, isForClientSide, pageId, configVike.includeAssetsImportedByServer, isDev);
|
|
27
27
|
debug(id, isForClientSide ? 'CLIENT-SIDE' : 'SERVER-SIDE', code);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { normalizeId };
|
|
2
|
+
import { toPosixPath } from '../utils.js';
|
|
3
|
+
// In principle Vite/Rollup should always normalize the `id` in `transform(code, id)` but it seems to not always do it.
|
|
4
|
+
// https://github.com/vikejs/vike/issues/1935
|
|
5
|
+
function normalizeId(id) {
|
|
6
|
+
return toPosixPath(id);
|
|
7
|
+
}
|
|
@@ -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,6 +1,6 @@
|
|
|
1
1
|
export { loadImportBuild };
|
|
2
2
|
export { setImportBuildGetters };
|
|
3
|
-
import {
|
|
3
|
+
import { importServerProductionEntry } from '@brillout/vite-plugin-server-entry/runtime';
|
|
4
4
|
import { assert } from '../utils.js';
|
|
5
5
|
const buildGetters = (globalThis.__vike_buildGetters = globalThis.__vike_buildGetters || {
|
|
6
6
|
getters: null
|
|
@@ -10,7 +10,7 @@ function setImportBuildGetters(getters) {
|
|
|
10
10
|
}
|
|
11
11
|
async function loadImportBuild(outDir) {
|
|
12
12
|
if (!buildGetters.getters) {
|
|
13
|
-
await
|
|
13
|
+
await importServerProductionEntry({ outDir });
|
|
14
14
|
assert(buildGetters.getters);
|
|
15
15
|
}
|
|
16
16
|
const [pageFiles, assetsManifest, pluginManifest] = await Promise.all([
|
|
@@ -2,7 +2,7 @@ export { renderPage };
|
|
|
2
2
|
export { renderPage_addWrapper };
|
|
3
3
|
import { getRenderContext, getPageContextInitEnhanced, renderPageAlreadyRouted } from './renderPage/renderPageAlreadyRouted.js';
|
|
4
4
|
import { route } from '../../shared/route/index.js';
|
|
5
|
-
import { assert, hasProp, objectAssign, isUrl, parseUrl, assertEnv, assertWarning, getGlobalObject, checkType, assertUsage, normalizeUrlPathname, removeBaseServer, modifyUrlPathname, prependBase, removeUrlOrigin,
|
|
5
|
+
import { assert, hasProp, objectAssign, isUrl, parseUrl, assertEnv, assertWarning, getGlobalObject, checkType, assertUsage, normalizeUrlPathname, removeBaseServer, modifyUrlPathname, prependBase, removeUrlOrigin, setUrlOrigin, createUrlFromComponents, isUri, getUrlPretty } from './utils.js';
|
|
6
6
|
import { assertNoInfiniteAbortLoop, getPageContextFromAllRewrites, isAbortError, logAbortErrorHandled } from '../../shared/route/abort.js';
|
|
7
7
|
import { getGlobalContext, initGlobalContext_renderPage } from './globalContext.js';
|
|
8
8
|
import { handlePageContextRequestUrl } from './renderPage/handlePageContextRequestUrl.js';
|
|
@@ -374,19 +374,29 @@ function getPermanentRedirect(pageContextInit, httpRequestId) {
|
|
|
374
374
|
urlTarget = urlTargetExternal;
|
|
375
375
|
}
|
|
376
376
|
else {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
377
|
+
let originChanged = false;
|
|
378
|
+
if (origin) {
|
|
379
|
+
const urlModified = setUrlOrigin(urlTarget, origin);
|
|
380
|
+
if (urlModified !== false) {
|
|
381
|
+
originChanged = true;
|
|
382
|
+
urlTarget = urlModified;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (normalize(urlTarget) === normalize(urlWithoutBase))
|
|
380
386
|
return null;
|
|
381
|
-
|
|
387
|
+
if (!originChanged)
|
|
388
|
+
urlTarget = prependBase(urlTarget, baseServer);
|
|
382
389
|
assert(urlTarget !== pageContextInit.urlOriginal);
|
|
383
390
|
}
|
|
384
|
-
logRuntimeInfo?.(`Permanent
|
|
391
|
+
logRuntimeInfo?.(`Permanent redirection defined by config.redirects (https://vike.dev/redirects)`, httpRequestId, 'info');
|
|
385
392
|
const httpResponse = createHttpResponseRedirect({ url: urlTarget, statusCode: 301 }, urlWithoutBase);
|
|
386
393
|
const pageContextHttpResponse = createPageContext(pageContextInit);
|
|
387
394
|
objectAssign(pageContextHttpResponse, { httpResponse });
|
|
388
395
|
return pageContextHttpResponse;
|
|
389
396
|
}
|
|
397
|
+
function normalize(url) {
|
|
398
|
+
return url || '/';
|
|
399
|
+
}
|
|
390
400
|
async function handleAbortError(errAbort, pageContextsFromRewrite, pageContextInit,
|
|
391
401
|
// handleAbortError() creates a new pageContext object and we don't merge pageContextNominalPageInit to it: we only use some pageContextNominalPageInit information.
|
|
392
402
|
pageContextNominalPageInit, httpRequestId, renderContext, pageContextErrorPageInit) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PROJECT_VERSION: "0.4.
|
|
1
|
+
export declare const PROJECT_VERSION: "0.4.200";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Automatically updated by @brillout/release-me
|
|
2
|
-
export const PROJECT_VERSION = '0.4.
|
|
2
|
+
export const PROJECT_VERSION = '0.4.200';
|
|
@@ -4,7 +4,7 @@ export { normalizeUrlPathname };
|
|
|
4
4
|
export { removeBaseServer };
|
|
5
5
|
export { modifyUrlPathname };
|
|
6
6
|
export { removeUrlOrigin };
|
|
7
|
-
export {
|
|
7
|
+
export { setUrlOrigin };
|
|
8
8
|
export { getUrlPretty };
|
|
9
9
|
declare function prependBase(url: string, baseServer: string): string;
|
|
10
10
|
declare function removeBaseServer(url: string, baseServer: string): string;
|
|
@@ -15,5 +15,5 @@ declare function removeUrlOrigin(url: string): {
|
|
|
15
15
|
urlModified: string;
|
|
16
16
|
origin: string | null;
|
|
17
17
|
};
|
|
18
|
-
declare function
|
|
18
|
+
declare function setUrlOrigin(url: string, origin: string | null): false | string;
|
|
19
19
|
declare function getUrlPretty(url: string): string;
|
|
@@ -4,7 +4,7 @@ export { normalizeUrlPathname };
|
|
|
4
4
|
export { removeBaseServer };
|
|
5
5
|
export { modifyUrlPathname };
|
|
6
6
|
export { removeUrlOrigin };
|
|
7
|
-
export {
|
|
7
|
+
export { setUrlOrigin };
|
|
8
8
|
export { getUrlPretty };
|
|
9
9
|
import { assertUrlComponents, createUrlFromComponents, isBaseServer, parseUrl } from './parseUrl.js';
|
|
10
10
|
import { assert } from './assert.js';
|
|
@@ -94,9 +94,10 @@ function removeUrlOrigin(url) {
|
|
|
94
94
|
const urlModified = createUrlFromComponents(null, pathnameOriginal, searchOriginal, hashOriginal);
|
|
95
95
|
return { urlModified, origin };
|
|
96
96
|
}
|
|
97
|
-
function
|
|
97
|
+
function setUrlOrigin(url, origin) {
|
|
98
98
|
const { origin: originCurrent, pathnameOriginal, searchOriginal, hashOriginal } = parseUrl(url, '/');
|
|
99
|
-
|
|
99
|
+
if (origin === originCurrent)
|
|
100
|
+
return false;
|
|
100
101
|
assert(origin === null || origin.startsWith('http'));
|
|
101
102
|
const urlModified = createUrlFromComponents(origin, pathnameOriginal, searchOriginal, hashOriginal);
|
|
102
103
|
return urlModified;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vike",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.200",
|
|
4
4
|
"repository": "https://github.com/vikejs/vike",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./server": {
|
|
@@ -125,14 +125,13 @@
|
|
|
125
125
|
"@brillout/json-serializer": "^0.5.13",
|
|
126
126
|
"@brillout/picocolors": "^1.0.15",
|
|
127
127
|
"@brillout/require-shim": "^0.1.2",
|
|
128
|
-
"@brillout/vite-plugin-server-entry": "^0.
|
|
128
|
+
"@brillout/vite-plugin-server-entry": "^0.5.0",
|
|
129
129
|
"acorn": "^8.0.0",
|
|
130
130
|
"cac": "^6.0.0",
|
|
131
131
|
"es-module-lexer": "^1.0.0",
|
|
132
132
|
"esbuild": "^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0",
|
|
133
133
|
"fast-glob": "^3.0.0",
|
|
134
134
|
"semver": "^7.0.0",
|
|
135
|
-
"sirv": "^2.0.0",
|
|
136
135
|
"source-map-support": "^0.5.0"
|
|
137
136
|
},
|
|
138
137
|
"peerDependencies": {
|
|
@@ -232,16 +231,8 @@
|
|
|
232
231
|
"@types/resolve": "^1.20.6",
|
|
233
232
|
"@types/semver": "^7.5.8",
|
|
234
233
|
"@types/source-map-support": "^0.5.10",
|
|
235
|
-
"acorn": "^8.11.2",
|
|
236
|
-
"cac": "^6.7.14",
|
|
237
|
-
"es-module-lexer": "^1.4.1",
|
|
238
|
-
"esbuild": "^0.23.0",
|
|
239
|
-
"fast-glob": "^3.3.2",
|
|
240
234
|
"react-streaming": "^0.3.43",
|
|
241
235
|
"rimraf": "^5.0.5",
|
|
242
|
-
"semver": "^7.6.3",
|
|
243
|
-
"sirv": "^2.0.4",
|
|
244
|
-
"source-map-support": "^0.5.21",
|
|
245
236
|
"typescript": "^5.6.2",
|
|
246
237
|
"vite": "^5.4.0"
|
|
247
238
|
},
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
export { onBrowserHistoryNavigation };
|
|
2
|
-
export { updateState };
|
|
3
|
-
import { getCurrentUrl, getGlobalObject } from './utils.js';
|
|
4
|
-
import { initHistoryState, getHistoryState } from './history.js';
|
|
5
|
-
import { renderPageClientSide } from './renderPageClientSide.js';
|
|
6
|
-
import { setScrollPosition } from './setScrollPosition.js';
|
|
7
|
-
const globalObject = getGlobalObject('onBrowserHistoryNavigation.ts', { previousState: getState() });
|
|
8
|
-
function onBrowserHistoryNavigation() {
|
|
9
|
-
// - The popstate event is trigged upon:
|
|
10
|
-
// - Back-/forward navigation.
|
|
11
|
-
// - By user clicking on his browser's back-/forward navigation (or using a shortcut)
|
|
12
|
-
// - By JavaScript: `history.back()` / `history.forward()`
|
|
13
|
-
// - URL hash change.
|
|
14
|
-
// - By user clicking on a hash link `<a href="#some-hash" />`
|
|
15
|
-
// - The popstate event is *only* triggered if `href` starts with '#' (even if `href` is '/#some-hash' while the current URL's pathname is '/' then the popstate still isn't triggered)
|
|
16
|
-
// - By JavaScript: `location.hash = 'some-hash'`
|
|
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
|
|
18
|
-
window.addEventListener('popstate', async () => {
|
|
19
|
-
const currentState = getState();
|
|
20
|
-
const scrollTarget = currentState.historyState.scrollPosition || undefined;
|
|
21
|
-
const isUserLandPushStateNavigation = currentState.historyState.triggeredBy === 'user';
|
|
22
|
-
const isHashNavigation = currentState.urlWithoutHash === globalObject.previousState.urlWithoutHash;
|
|
23
|
-
const isBackwardNavigation = !currentState.historyState.timestamp || !globalObject.previousState.historyState.timestamp
|
|
24
|
-
? null
|
|
25
|
-
: currentState.historyState.timestamp < globalObject.previousState.historyState.timestamp;
|
|
26
|
-
globalObject.previousState = currentState;
|
|
27
|
-
if (isHashNavigation && !isUserLandPushStateNavigation) {
|
|
28
|
-
// - `history.state` is uninitialized (`null`) when:
|
|
29
|
-
// - The user's code runs `window.location.hash = '#section'`.
|
|
30
|
-
// - The user clicks on an anchor link `<a href="#section">Section</a>` (because Vike's `initOnLinkClick()` handler skips hash links).
|
|
31
|
-
// - `history.state` is `null` when uninitialized: https://developer.mozilla.org/en-US/docs/Web/API/History/state
|
|
32
|
-
// - Alternatively, we completely take over hash navigation and reproduce the browser's native behavior upon hash navigation.
|
|
33
|
-
// - Problem: we cannot intercept `window.location.hash = '#section'`. (Or maybe we can with the `hashchange` event?)
|
|
34
|
-
// - Other potential problem: would there be a conflict when the user wants to override the browser's default behavior? E.g. for smooth scrolling, or when using hashes for saving states of some fancy animations.
|
|
35
|
-
// - Another alternative: we use the browser's scroll restoration mechanism (see `browserNativeScrollRestoration_enable()` below).
|
|
36
|
-
// - Problem: not clear when to call `browserNativeScrollRestoration_disable()`/`browserNativeScrollRestoration_enable()`
|
|
37
|
-
// - Other potential problem are inconsistencies between browsers: specification says that setting `window.history.scrollRestoration` only affects the current entry in the session history. But this seems to contradict what folks saying.
|
|
38
|
-
// - Specification: https://html.spec.whatwg.org/multipage/history.html#the-history-interface
|
|
39
|
-
// - https://stackoverflow.com/questions/70188241/history-scrollrestoration-manual-doesnt-prevent-safari-from-restoring-scrol
|
|
40
|
-
if (window.history.state === null) {
|
|
41
|
-
// The browser already scrolled to `#${hash}` => the current scroll position is the right one => we save it with `initHistoryState()`.
|
|
42
|
-
initHistoryState();
|
|
43
|
-
globalObject.previousState = getState();
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
// If `history.state !== null` then it means that `popstate` was triggered by the user clicking on his browser's forward/backward history button.
|
|
47
|
-
setScrollPosition(scrollTarget);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
await renderPageClientSide({ scrollTarget, isBackwardNavigation, isUserLandPushStateNavigation });
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
function getState() {
|
|
56
|
-
return {
|
|
57
|
-
urlWithoutHash: getCurrentUrl({ withoutHash: true }),
|
|
58
|
-
historyState: getHistoryState()
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function updateState() {
|
|
62
|
-
globalObject.previousState = getState();
|
|
63
|
-
}
|