vike 0.4.180-commit-648cd01 → 0.4.181
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/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +1 -2
- package/dist/cjs/{shared/route → node/runtime/renderPage}/resolveRedirects.js +9 -11
- package/dist/cjs/node/runtime/renderPage.js +6 -9
- package/dist/cjs/shared/getPageContextUrlComputed.js +43 -37
- package/dist/cjs/shared/modifyUrl.js +31 -0
- package/dist/cjs/shared/route/abort.js +4 -10
- package/dist/cjs/shared/route/executeOnBeforeRouteHook.js +3 -1
- package/dist/cjs/utils/parseUrl.js +168 -87
- package/dist/cjs/utils/projectInfo.js +1 -1
- package/dist/cjs/utils/redirectHard.js +7 -0
- package/dist/cjs/utils/urlToFile.js +1 -1
- package/dist/esm/client/client-routing-runtime/createPageContext.d.ts +1 -1
- package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +2 -2
- package/dist/esm/client/client-routing-runtime/navigate.js +2 -1
- package/dist/esm/client/client-routing-runtime/prefetch.js +5 -4
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +7 -7
- package/dist/esm/client/client-routing-runtime/skipLink.js +11 -22
- package/dist/esm/client/client-routing-runtime/utils.d.ts +1 -2
- package/dist/esm/client/client-routing-runtime/utils.js +1 -2
- package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js +2 -3
- package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.d.ts +5 -5
- package/dist/esm/{shared/route → node/runtime/renderPage}/resolveRedirects.js +9 -11
- package/dist/esm/node/runtime/renderPage.d.ts +2 -2
- package/dist/esm/node/runtime/renderPage.js +7 -10
- package/dist/esm/shared/getPageContextUrlComputed.d.ts +2 -24
- package/dist/esm/shared/getPageContextUrlComputed.js +43 -37
- package/dist/esm/shared/modifyUrl.d.ts +14 -0
- package/dist/esm/shared/modifyUrl.js +28 -0
- package/dist/esm/shared/route/abort.js +5 -11
- package/dist/esm/shared/route/executeOnBeforeRouteHook.js +4 -2
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/utils/parseUrl.d.ts +43 -10
- package/dist/esm/utils/parseUrl.js +167 -86
- package/dist/esm/utils/projectInfo.d.ts +2 -2
- package/dist/esm/utils/projectInfo.js +1 -1
- package/dist/esm/utils/redirectHard.d.ts +1 -0
- package/dist/esm/utils/redirectHard.js +3 -0
- package/dist/esm/utils/urlToFile.js +1 -1
- package/package.json +17 -2
- package/dist/cjs/utils/isExternalLink.js +0 -7
- package/dist/cjs/utils/serverSideRouteTo.js +0 -7
- package/dist/esm/utils/isExternalLink.d.ts +0 -2
- package/dist/esm/utils/isExternalLink.js +0 -4
- package/dist/esm/utils/serverSideRouteTo.d.ts +0 -2
- package/dist/esm/utils/serverSideRouteTo.js +0 -4
- /package/dist/esm/{shared/route → node/runtime/renderPage}/resolveRedirects.d.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PROJECT_VERSION = exports.projectInfo = void 0;
|
|
4
|
-
const PROJECT_VERSION = '0.4.
|
|
4
|
+
const PROJECT_VERSION = '0.4.181';
|
|
5
5
|
exports.PROJECT_VERSION = PROJECT_VERSION;
|
|
6
6
|
const projectInfo = {
|
|
7
7
|
projectName: 'Vike',
|
|
@@ -5,7 +5,7 @@ const assert_js_1 = require("./assert.js");
|
|
|
5
5
|
const parseUrl_js_1 = require("./parseUrl.js");
|
|
6
6
|
const slice_js_1 = require("./slice.js");
|
|
7
7
|
// - When doing a `.pageContext.json` HTTP request, the base URL should be preserved. (The server-side will handle the base URL.)
|
|
8
|
-
// - While
|
|
8
|
+
// - While pre-rendering there is no base URL
|
|
9
9
|
const baseServer = '/';
|
|
10
10
|
exports.baseServer = baseServer;
|
|
11
11
|
function urlToFile(url, fileExtension, doNotCreateExtraDirectory) {
|
|
@@ -13,7 +13,7 @@ declare function createPageContext(urlOriginal: string): Promise<{
|
|
|
13
13
|
_onBeforeRouteHook: import("../../shared/hooks/getHook.js").Hook | null;
|
|
14
14
|
_isPageContextObject: boolean;
|
|
15
15
|
} & {
|
|
16
|
-
urlParsed: import("
|
|
16
|
+
urlParsed: import("./utils.js").UrlPublic;
|
|
17
17
|
urlPathname: string;
|
|
18
18
|
url: string;
|
|
19
19
|
}>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { getPageContextFromHooks_isHydration };
|
|
2
2
|
export { getPageContextFromHooks_isNotHydration };
|
|
3
3
|
export { getPageContextFromHooks_serialized };
|
|
4
|
-
import { assert, assertUsage, hasProp, objectAssign, getProjectError,
|
|
4
|
+
import { assert, assertUsage, hasProp, objectAssign, getProjectError, redirectHard, executeHook, isObject, getGlobalObject } from './utils.js';
|
|
5
5
|
import { parse } from '@brillout/json-serializer/parse';
|
|
6
6
|
import { getPageContextSerializedInHtml } from '../shared/getPageContextSerializedInHtml.js';
|
|
7
7
|
import { analyzePageServerSide } from '../../shared/getPageFiles/analyzePageServerSide.js';
|
|
@@ -208,7 +208,7 @@ async function fetchPageContextFromServer(pageContext) {
|
|
|
208
208
|
const isCorrect = contentType && contentType.includes(contentTypeCorrect);
|
|
209
209
|
// Static hosts + page doesn't exist
|
|
210
210
|
if (!isCorrect && response.status === 404) {
|
|
211
|
-
|
|
211
|
+
redirectHard(pageContext.urlOriginal);
|
|
212
212
|
return { is404ServerSideRouted: true };
|
|
213
213
|
}
|
|
214
214
|
assertUsage(isCorrect, `Wrong Content-Type for ${pageContextUrl}: it should be ${contentTypeCorrect} but it's ${contentType} instead. Make sure to properly use pageContext.httpResponse.headers, see https://vike.dev/renderPage`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { navigate };
|
|
2
2
|
export { reload };
|
|
3
3
|
import { renderPageClientSide } from './renderPageClientSide.js';
|
|
4
|
-
import { assertClientRouting, getCurrentUrl } from './utils.js';
|
|
4
|
+
import { assertClientRouting, assertUsageUrlPathname, getCurrentUrl } from './utils.js';
|
|
5
5
|
assertClientRouting();
|
|
6
6
|
/** Programmatically navigate to a new page.
|
|
7
7
|
*
|
|
@@ -12,6 +12,7 @@ assertClientRouting();
|
|
|
12
12
|
* @param overwriteLastHistoryEntry - Don't create a new entry in the browser's history, instead let the new URL replace the current URL. (This effectively removes the current URL from the browser history).
|
|
13
13
|
*/
|
|
14
14
|
async function navigate(url, { keepScrollPosition = false, overwriteLastHistoryEntry = false } = {}) {
|
|
15
|
+
assertUsageUrlPathname(url, '[navigate(url)] url');
|
|
15
16
|
const scrollTarget = { preserveScroll: keepScrollPosition };
|
|
16
17
|
await renderPageClientSide({
|
|
17
18
|
scrollTarget,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { prefetch };
|
|
2
2
|
export { addLinkPrefetchHandlers };
|
|
3
|
-
import { assert, assertClientRouting, assertUsage, assertWarning, checkIfClientRouting, getGlobalObject
|
|
3
|
+
import { assert, assertClientRouting, assertUsage, assertUsageUrlPathname, assertWarning, checkIfClientRouting, getGlobalObject } from './utils.js';
|
|
4
4
|
import { isErrorFetchingStaticAssets, loadUserFilesClientSide } from '../shared/loadUserFilesClientSide.js';
|
|
5
5
|
import { skipLink } from './skipLink.js';
|
|
6
6
|
import { getPrefetchSettings } from './prefetch/getPrefetchSettings.js';
|
|
@@ -10,6 +10,7 @@ import { isClientSideRoutable } from './isClientSideRoutable.js';
|
|
|
10
10
|
import { createPageContext } from './createPageContext.js';
|
|
11
11
|
import { route } from '../../shared/route/index.js';
|
|
12
12
|
import { noRouteMatch } from '../../shared/route/noRouteMatch.js';
|
|
13
|
+
import pc from '@brillout/picocolors';
|
|
13
14
|
assertClientRouting();
|
|
14
15
|
const globalObject = getGlobalObject('prefetch.ts', { linkPrefetchHandlerAdded: new WeakMap() });
|
|
15
16
|
async function prefetchAssets(pageId, pageContext) {
|
|
@@ -36,8 +37,8 @@ async function prefetch(url) {
|
|
|
36
37
|
assertUsage(checkIfClientRouting(), 'prefetch() only works with Client Routing, see https://vike.dev/prefetch', {
|
|
37
38
|
showStackTrace: true
|
|
38
39
|
});
|
|
39
|
-
const errPrefix =
|
|
40
|
-
|
|
40
|
+
const errPrefix = '[prefetch(url)] url';
|
|
41
|
+
assertUsageUrlPathname(url, errPrefix);
|
|
41
42
|
if (isAlreadyPrefetched(url))
|
|
42
43
|
return;
|
|
43
44
|
markAsAlreadyPrefetched(url);
|
|
@@ -52,7 +53,7 @@ async function prefetch(url) {
|
|
|
52
53
|
}
|
|
53
54
|
const pageId = pageContextFromRoute._pageId;
|
|
54
55
|
if (!pageId) {
|
|
55
|
-
assertWarning(false, `${errPrefix} ${noRouteMatch}`, {
|
|
56
|
+
assertWarning(false, `${errPrefix} ${pc.string(url)} ${noRouteMatch}`, {
|
|
56
57
|
showStackTrace: true,
|
|
57
58
|
onlyOnce: false
|
|
58
59
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { renderPageClientSide };
|
|
2
2
|
export { getRenderCount };
|
|
3
3
|
export { disableClientRouting };
|
|
4
|
-
import { assert, getCurrentUrl, isSameErrorMessage, objectAssign,
|
|
4
|
+
import { assert, getCurrentUrl, isSameErrorMessage, objectAssign, redirectHard, getGlobalObject, executeHook, hasProp, augmentType } from './utils.js';
|
|
5
5
|
import { getPageContextFromHooks_isHydration, getPageContextFromHooks_isNotHydration, getPageContextFromHooks_serialized } from './getPageContextFromHooks.js';
|
|
6
6
|
import { createPageContext } from './createPageContext.js';
|
|
7
7
|
import { addLinkPrefetchHandlers } from './prefetch.js';
|
|
@@ -25,7 +25,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
25
25
|
assert(isClientSideNavigation === !isHydrationRender); // isHydrationRender === (renderNumber === 1)
|
|
26
26
|
assertNoInfiniteAbortLoop(pageContextsFromRewrite.length, redirectCount);
|
|
27
27
|
if (globalObject.clientRoutingIsDisabled) {
|
|
28
|
-
|
|
28
|
+
redirectHard(urlOriginal);
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
await renderPageNominal();
|
|
@@ -89,7 +89,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
91
|
if (!isClientRoutable) {
|
|
92
|
-
|
|
92
|
+
redirectHard(urlOriginal);
|
|
93
93
|
return;
|
|
94
94
|
}
|
|
95
95
|
assert(hasProp(pageContextFromRoute, '_pageId', 'string')); // Help TS
|
|
@@ -183,7 +183,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
183
183
|
/* When we can't render the error page, we prefer showing a blank page over letting the server-side try because otherwise:
|
|
184
184
|
- We risk running into an infinite loop of reloads which would overload the server.
|
|
185
185
|
- An infinite reloading page is a even worse UX than a blank page.
|
|
186
|
-
|
|
186
|
+
redirectHard(urlOriginal)
|
|
187
187
|
*/
|
|
188
188
|
console.error(err);
|
|
189
189
|
}
|
|
@@ -228,9 +228,9 @@ async function renderPageClientSide(renderArgs) {
|
|
|
228
228
|
// throw redirect('/some-url')
|
|
229
229
|
if (pageContextAbort._urlRedirect) {
|
|
230
230
|
const urlRedirect = pageContextAbort._urlRedirect.url;
|
|
231
|
-
if (urlRedirect.startsWith('
|
|
231
|
+
if (!urlRedirect.startsWith('/')) {
|
|
232
232
|
// External redirection
|
|
233
|
-
|
|
233
|
+
redirectHard(urlRedirect);
|
|
234
234
|
return;
|
|
235
235
|
}
|
|
236
236
|
else {
|
|
@@ -408,7 +408,7 @@ function handleErrorFetchingStaticAssets(err, pageContext, isHydrationRender) {
|
|
|
408
408
|
else {
|
|
409
409
|
disableClientRouting(err, true);
|
|
410
410
|
}
|
|
411
|
-
|
|
411
|
+
redirectHard(pageContext.urlOriginal);
|
|
412
412
|
return true;
|
|
413
413
|
}
|
|
414
414
|
function disableClientRouting(err, log) {
|
|
@@ -1,30 +1,19 @@
|
|
|
1
1
|
export { skipLink };
|
|
2
2
|
import { getBaseServer } from './getBaseServer.js';
|
|
3
|
-
import { assert, parseUrl, isBaseServer,
|
|
3
|
+
import { assert, parseUrl, isBaseServer, isUrl, isUrlExternal } from './utils.js';
|
|
4
4
|
function skipLink(linkTag) {
|
|
5
5
|
const url = linkTag.getAttribute('href');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return true;
|
|
16
|
-
if (!hasBaseServer(url)) {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
if (!isParsable(url)) {
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
// Purposely last because disableAutomaticLinkInterception will be removed in the major release
|
|
23
|
-
if (!isVikeLink(linkTag))
|
|
24
|
-
return true;
|
|
25
|
-
return false;
|
|
6
|
+
return (url === null ||
|
|
7
|
+
!isUrl(url) ||
|
|
8
|
+
url === '' ||
|
|
9
|
+
isUrlExternal(url) ||
|
|
10
|
+
isHashUrl(url) ||
|
|
11
|
+
isNewTabLink(linkTag) ||
|
|
12
|
+
!hasBaseServer(url) ||
|
|
13
|
+
// Purposely last because disableAutomaticLinkInterception will be removed in the next major release
|
|
14
|
+
!isVikeLink(linkTag));
|
|
26
15
|
}
|
|
27
|
-
// TODO/
|
|
16
|
+
// TODO/next-major-release: remove this in favor of synchronously checking whether URL matches the route of a page (possible since Async Route Functions will be deprecated)
|
|
28
17
|
function isVikeLink(linkTag) {
|
|
29
18
|
const disableAutomaticLinkInterception = isDisableAutomaticLinkInterception();
|
|
30
19
|
if (!disableAutomaticLinkInterception) {
|
|
@@ -15,11 +15,10 @@ export * from '../../utils/objectAssign.js';
|
|
|
15
15
|
export * from '../../utils/parseUrl.js';
|
|
16
16
|
export * from '../../utils/projectInfo.js';
|
|
17
17
|
export * from '../../utils/PromiseType.js';
|
|
18
|
-
export * from '../../utils/
|
|
18
|
+
export * from '../../utils/redirectHard.js';
|
|
19
19
|
export * from '../../utils/sleep.js';
|
|
20
20
|
export * from '../../utils/slice.js';
|
|
21
21
|
export * from '../../utils/throttle.js';
|
|
22
22
|
export * from '../../utils/assertRoutingType.js';
|
|
23
23
|
export * from '../../utils/onPageVisibilityChange.js';
|
|
24
|
-
export * from '../../utils/isExternalLink.js';
|
|
25
24
|
export * from '../../utils/augmentType.js';
|
|
@@ -21,11 +21,10 @@ export * from '../../utils/objectAssign.js';
|
|
|
21
21
|
export * from '../../utils/parseUrl.js';
|
|
22
22
|
export * from '../../utils/projectInfo.js';
|
|
23
23
|
export * from '../../utils/PromiseType.js';
|
|
24
|
-
export * from '../../utils/
|
|
24
|
+
export * from '../../utils/redirectHard.js';
|
|
25
25
|
export * from '../../utils/sleep.js';
|
|
26
26
|
export * from '../../utils/slice.js';
|
|
27
27
|
export * from '../../utils/throttle.js';
|
|
28
28
|
export * from '../../utils/assertRoutingType.js';
|
|
29
29
|
export * from '../../utils/onPageVisibilityChange.js';
|
|
30
|
-
export * from '../../utils/isExternalLink.js';
|
|
31
30
|
export * from '../../utils/augmentType.js';
|
package/dist/esm/node/runtime/renderPage/createHttpResponseObject/assertNoInfiniteHttpRedirect.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export { assertNoInfiniteHttpRedirect };
|
|
2
|
-
import { assert, assertUsage, getGlobalObject
|
|
2
|
+
import { assert, assertUsage, getGlobalObject } from '../../utils.js';
|
|
3
3
|
import pc from '@brillout/picocolors';
|
|
4
4
|
const globalObject = getGlobalObject('assertNoInfiniteHttpRedirect.ts', {
|
|
5
5
|
redirectGraph: {}
|
|
6
6
|
});
|
|
7
7
|
function assertNoInfiniteHttpRedirect(urlRedirectTarget, urlLogical) {
|
|
8
|
-
if (
|
|
8
|
+
if (!urlRedirectTarget.startsWith('/')) {
|
|
9
9
|
// We assume that urlRedirectTarget points to an origin that is external (not the same origin), and we can therefore assume that the app doesn't define an infinite loop (in itself).
|
|
10
10
|
// - There isn't a reliable way to check whether the redirect points to an external origin or the same origin. For same origins, we assume/hope the user to pass the URL without origin.
|
|
11
11
|
// ```js
|
|
@@ -14,7 +14,6 @@ function assertNoInfiniteHttpRedirect(urlRedirectTarget, urlLogical) {
|
|
|
14
14
|
// ```
|
|
15
15
|
return;
|
|
16
16
|
}
|
|
17
|
-
assert(urlRedirectTarget.startsWith('/'));
|
|
18
17
|
assert(urlLogical.startsWith('/'));
|
|
19
18
|
const graph = copy(globalObject.redirectGraph);
|
|
20
19
|
graph[urlRedirectTarget] ?? (graph[urlRedirectTarget] = new Set());
|
|
@@ -60,7 +60,7 @@ declare function prerenderPage(pageContext: PageContextInitEnhanced & PageFiles
|
|
|
60
60
|
_urlHandler: ((url: string) => string) | null;
|
|
61
61
|
isClientSideNavigation: boolean;
|
|
62
62
|
} & {
|
|
63
|
-
urlParsed: import("
|
|
63
|
+
urlParsed: import("../utils.js").UrlPublic;
|
|
64
64
|
urlPathname: string;
|
|
65
65
|
url: string;
|
|
66
66
|
} & {
|
|
@@ -111,7 +111,7 @@ declare function prerenderPage(pageContext: PageContextInitEnhanced & PageFiles
|
|
|
111
111
|
_urlHandler: ((url: string) => string) | null;
|
|
112
112
|
isClientSideNavigation: boolean;
|
|
113
113
|
} & {
|
|
114
|
-
urlParsed: import("
|
|
114
|
+
urlParsed: import("../utils.js").UrlPublic;
|
|
115
115
|
urlPathname: string;
|
|
116
116
|
url: string;
|
|
117
117
|
} & {
|
|
@@ -163,7 +163,7 @@ declare function prerender404Page(renderContext: RenderContext, pageContextInit_
|
|
|
163
163
|
_urlHandler: ((url: string) => string) | null;
|
|
164
164
|
isClientSideNavigation: boolean;
|
|
165
165
|
} & {
|
|
166
|
-
urlParsed: import("
|
|
166
|
+
urlParsed: import("../utils.js").UrlPublic;
|
|
167
167
|
urlPathname: string;
|
|
168
168
|
url: string;
|
|
169
169
|
} & {
|
|
@@ -214,7 +214,7 @@ declare function prerender404Page(renderContext: RenderContext, pageContextInit_
|
|
|
214
214
|
_urlHandler: ((url: string) => string) | null;
|
|
215
215
|
isClientSideNavigation: boolean;
|
|
216
216
|
} & {
|
|
217
|
-
urlParsed: import("
|
|
217
|
+
urlParsed: import("../utils.js").UrlPublic;
|
|
218
218
|
urlPathname: string;
|
|
219
219
|
url: string;
|
|
220
220
|
} & {
|
|
@@ -274,7 +274,7 @@ declare function getPageContextInitEnhanced(pageContextInit: {
|
|
|
274
274
|
_urlHandler: ((url: string) => string) | null;
|
|
275
275
|
isClientSideNavigation: boolean;
|
|
276
276
|
} & {
|
|
277
|
-
urlParsed: import("
|
|
277
|
+
urlParsed: import("../utils.js").UrlPublic;
|
|
278
278
|
urlPathname: string;
|
|
279
279
|
url: string;
|
|
280
280
|
} & {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
export { resolveRedirects };
|
|
2
2
|
// For ./resolveRedirects.spec.ts
|
|
3
3
|
export { resolveRouteStringRedirect };
|
|
4
|
-
import { assertIsNotBrowser } from '
|
|
5
|
-
import { assert, assertUsage,
|
|
6
|
-
import { resolveUrlPathname } from '
|
|
7
|
-
import { assertRouteString, resolveRouteString } from '
|
|
4
|
+
import { assertIsNotBrowser } from '../../../utils/assertIsNotBrowser.js';
|
|
5
|
+
import { assert, assertUsage, assertUsageUrlRedirectTarget, isUrlRedirectTarget } from '../../../shared/utils.js';
|
|
6
|
+
import { resolveUrlPathname } from '../../../shared/route/resolveUrlPathname.js';
|
|
7
|
+
import { assertRouteString, resolveRouteString } from '../../../shared/route/resolveRouteString.js';
|
|
8
8
|
import pc from '@brillout/picocolors';
|
|
9
9
|
assertIsNotBrowser(); // Don't bloat the client
|
|
10
|
-
// TODO/
|
|
10
|
+
// TODO/next-major-release: update
|
|
11
11
|
const configSrc = '[vite.config.js > vike({ redirects })]';
|
|
12
12
|
function resolveRedirects(redirects, urlPathname) {
|
|
13
13
|
for (const [urlSource, urlTarget] of Object.entries(redirects)) {
|
|
@@ -19,10 +19,8 @@ function resolveRedirects(redirects, urlPathname) {
|
|
|
19
19
|
}
|
|
20
20
|
function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
21
21
|
assertRouteString(urlSource, `${configSrc} Invalid`);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
isUriWithProtocol(urlTarget) ||
|
|
25
|
-
urlTarget === '*', `${configSrc} Invalid redirection target URL ${pc.cyan(urlTarget)}: the target URL should start with ${pc.cyan('/')}, a valid protocol (${pc.cyan('https:')}, ${pc.cyan('http:')}, ${pc.cyan('mailto:')}, ${pc.cyan('ipfs:')}, ${pc.cyan('magnet:')}, ...), or be ${pc.cyan('*')}`);
|
|
22
|
+
// Is allowing any protocol a safety issue? https://github.com/vikejs/vike/pull/1292#issuecomment-1828043917
|
|
23
|
+
assertUsageUrlRedirectTarget(urlTarget, `${configSrc} The URL redirection target`, true);
|
|
26
24
|
assertParams(urlSource, urlTarget);
|
|
27
25
|
const match = resolveRouteString(urlSource, urlPathname);
|
|
28
26
|
if (!match)
|
|
@@ -30,7 +28,7 @@ function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
|
30
28
|
const urlResolved = resolveUrlPathname(urlTarget, match.routeParams);
|
|
31
29
|
if (urlResolved === urlPathname)
|
|
32
30
|
return null;
|
|
33
|
-
assert(
|
|
31
|
+
assert(isUrlRedirectTarget(urlResolved));
|
|
34
32
|
return urlResolved;
|
|
35
33
|
}
|
|
36
34
|
function assertParams(urlSource, urlTarget) {
|
|
@@ -38,7 +36,7 @@ function assertParams(urlSource, urlTarget) {
|
|
|
38
36
|
routeSegments.forEach((routeSegment) => {
|
|
39
37
|
if (routeSegment.startsWith('@') || routeSegment.startsWith('*')) {
|
|
40
38
|
const segments = urlSource.split('/');
|
|
41
|
-
assertUsage(segments.includes(routeSegment), `${configSrc} The redirection source URL ${pc.
|
|
39
|
+
assertUsage(segments.includes(routeSegment), `${configSrc} The redirection source URL ${pc.string(urlSource)} is missing the URL parameter ${pc.string(routeSegment)} used by the redirection target URL ${pc.string(urlTarget)}`);
|
|
42
40
|
}
|
|
43
41
|
});
|
|
44
42
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { renderPage };
|
|
2
2
|
export { renderPage_addWrapper };
|
|
3
3
|
import { HttpResponse } from './renderPage/createHttpResponseObject.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { PageContextServer } from '../../types/index.js';
|
|
5
5
|
declare let renderPage_wrapper: <PageContext>(_httpRequestId: number, ret: () => Promise<PageContext>) => Promise<{
|
|
6
6
|
pageContextReturn: Awaited<PageContext>;
|
|
7
7
|
}>;
|
|
@@ -13,4 +13,4 @@ declare function renderPage<PageContextUserAdded extends {}, PageContextInit ext
|
|
|
13
13
|
urlOriginal: string;
|
|
14
14
|
}>(pageContextInit: PageContextInit): Promise<PageContextInit & {
|
|
15
15
|
httpResponse: HttpResponse | null;
|
|
16
|
-
} & Partial<
|
|
16
|
+
} & Partial<PageContextServer & PageContextUserAdded>>;
|
|
@@ -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,
|
|
5
|
+
import { assert, hasProp, objectAssign, isUrl, parseUrl, assertEnv, assertWarning, getGlobalObject, checkType, assertUsage, normalizeUrlPathname, removeBaseServer, modifyUrlPathname, prependBase, removeUrlOrigin, addUrlOrigin, createUrlFromComponents, isUri } from './utils.js';
|
|
6
6
|
import { assertNoInfiniteAbortLoop, getPageContextFromAllRewrites, isAbortError, logAbortErrorHandled } from '../../shared/route/abort.js';
|
|
7
7
|
import { getGlobalContext, initGlobalContext } from './globalContext.js';
|
|
8
8
|
import { handlePageContextRequestUrl } from './renderPage/handlePageContextRequestUrl.js';
|
|
@@ -17,7 +17,7 @@ import { serializePageContextAbort, serializePageContextClientSide } from './htm
|
|
|
17
17
|
import { getErrorPageId } from '../../shared/error-page.js';
|
|
18
18
|
import { handleErrorWithoutErrorPage } from './renderPage/handleErrorWithoutErrorPage.js';
|
|
19
19
|
import { loadUserFilesServerSide } from './renderPage/loadUserFilesServerSide.js';
|
|
20
|
-
import { resolveRedirects } from '
|
|
20
|
+
import { resolveRedirects } from './renderPage/resolveRedirects.js';
|
|
21
21
|
const globalObject = getGlobalObject('runtime/renderPage.ts', {
|
|
22
22
|
httpRequestsCount: 0,
|
|
23
23
|
pendingRequestsCount: 0
|
|
@@ -326,12 +326,9 @@ function getRequestId() {
|
|
|
326
326
|
return httpRequestId;
|
|
327
327
|
}
|
|
328
328
|
function isIgnoredUrl(urlOriginal) {
|
|
329
|
-
const
|
|
330
|
-
assertWarning(!
|
|
331
|
-
return (urlOriginal.endsWith('/__vite_ping') ||
|
|
332
|
-
urlOriginal.endsWith('/favicon.ico') ||
|
|
333
|
-
!isParsable(urlOriginal) ||
|
|
334
|
-
isViteClientRequest);
|
|
329
|
+
const isViteRequest = urlOriginal.endsWith('/@vite/client') || urlOriginal.startsWith('/@fs/');
|
|
330
|
+
assertWarning(!isViteRequest, `The vike middleware renderPage() was called with the URL ${urlOriginal} which is unexpected because the HTTP request should have already been handled by Vite's development middleware. Make sure to 1. install Vite's development middleware and 2. add Vite's middleware *before* Vike's middleware, see https://vike.dev/renderPage`, { onlyOnce: true });
|
|
331
|
+
return (urlOriginal.endsWith('/__vite_ping') || urlOriginal.endsWith('/favicon.ico') || !isUrl(urlOriginal) || isViteRequest);
|
|
335
332
|
}
|
|
336
333
|
function normalizeUrl(pageContextInit, httpRequestId) {
|
|
337
334
|
const { trailingSlash, disableUrlNormalization, baseServer } = getGlobalContext();
|
|
@@ -359,9 +356,9 @@ function getPermanentRedirect(pageContextInit, httpRequestId) {
|
|
|
359
356
|
const urlTarget = resolveRedirects(redirects, urlPathname);
|
|
360
357
|
if (urlTarget === null)
|
|
361
358
|
return null;
|
|
362
|
-
if (!
|
|
359
|
+
if (!isUrl(urlTarget)) {
|
|
363
360
|
// E.g. `urlTarget === 'mailto:some@example.com'`
|
|
364
|
-
assert(
|
|
361
|
+
assert(isUri(urlTarget));
|
|
365
362
|
urlTargetExternal = urlTarget;
|
|
366
363
|
return null;
|
|
367
364
|
}
|
|
@@ -4,32 +4,10 @@ export type { PageContextUrlInternal };
|
|
|
4
4
|
export type { PageContextUrlClient };
|
|
5
5
|
export type { PageContextUrlServer };
|
|
6
6
|
export type { PageContextUrlSource };
|
|
7
|
-
|
|
8
|
-
type Url = {
|
|
9
|
-
/** The URL origin, e.g. `https://example.com` of `https://example.com/product/42?details=yes#reviews` */
|
|
10
|
-
origin: null | string;
|
|
11
|
-
/** The URL pathname, e.g. `/product/42` of `https://example.com/product/42?details=yes#reviews` */
|
|
12
|
-
pathname: string;
|
|
13
|
-
/** URL pathname including the Base URL, e.g. `/some-base-url/product/42` of `https://example.com/some-base-url/product/42` (whereas `pageContext.urlParsed.pathname` is `/product/42`) */
|
|
14
|
-
pathnameOriginal: string;
|
|
15
|
-
/** The URL search parameters, e.g. `{ details: 'yes' }` for `https://example.com/product/42?details=yes#reviews` */
|
|
16
|
-
search: Record<string, string>;
|
|
17
|
-
/** The URL search parameters array, e.g. `{ fruit: ['apple', 'orange'] }` for `https://example.com?fruit=apple&fruit=orange` **/
|
|
18
|
-
searchAll: Record<string, string[]>;
|
|
19
|
-
/** The URL search parameterer string, e.g. `?details=yes` of `https://example.com/product/42?details=yes#reviews` */
|
|
20
|
-
searchOriginal: null | string;
|
|
21
|
-
/** The URL hash, e.g. `reviews` of `https://example.com/product/42?details=yes#reviews` */
|
|
22
|
-
hash: string;
|
|
23
|
-
/** The URL hash string, e.g. `#reviews` of `https://example.com/product/42?details=yes#reviews` */
|
|
24
|
-
hashOriginal: null | string;
|
|
25
|
-
/** @deprecated */
|
|
26
|
-
hashString: null | string;
|
|
27
|
-
/** @deprecated */
|
|
28
|
-
searchString: null | string;
|
|
29
|
-
};
|
|
7
|
+
import { type UrlPublic } from './utils.js';
|
|
30
8
|
type PageContextUrlComputed = {
|
|
31
9
|
/** Parsed information about the current URL */
|
|
32
|
-
urlParsed:
|
|
10
|
+
urlParsed: UrlPublic;
|
|
33
11
|
/** The URL pathname, e.g. `/product/42` of `https://example.com/product/42?details=yes#reviews` */
|
|
34
12
|
urlPathname: string;
|
|
35
13
|
/** @deprecated */
|
|
@@ -28,11 +28,6 @@ function getPageContextUrlComputed(pageContext) {
|
|
|
28
28
|
return pageContextUrlComputed;
|
|
29
29
|
}
|
|
30
30
|
function getUrlParsed(pageContext) {
|
|
31
|
-
// We need a url handler function because the onBeforeRoute() hook may set pageContext.urlLogical (typically for i18n)
|
|
32
|
-
let urlHandler = pageContext._urlHandler;
|
|
33
|
-
if (!urlHandler) {
|
|
34
|
-
urlHandler = (url) => url;
|
|
35
|
-
}
|
|
36
31
|
// Example of i18n app using `throw render()`:
|
|
37
32
|
// 1. User goes to '/fr-FR/admin'.
|
|
38
33
|
// 2. The first onBeforeRoute() call accesses pageContext.urlPathname (its value is '/fr-FR/admin': the pathname of pageContext.urlOriginal, since both pageContext.urlLogical and pageContext._urlRewrite are undefined) and sets pageContext.urlLogical to '/admin'.
|
|
@@ -41,23 +36,36 @@ function getUrlParsed(pageContext) {
|
|
|
41
36
|
// 5. The second onBeforeRoute() call accesses pageContext.urlPathname (its value is '/fr-FR/login': the pathname of pageContext._urlRewrite, since pageContext.urlLogical is undefined) and sets pageContext.urlLogical to '/login'.
|
|
42
37
|
// 6. The value of pageContext.urlPathname is now '/login': the pathname of `pageContext.urlLogical`. (While pageContext.urlOriginal is still '/fr-FR/admin'.)
|
|
43
38
|
// Reproduction: https://github.com/vikejs/vike/discussions/1436#discussioncomment-8142023
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
// Determine logical URL
|
|
40
|
+
let urlResolved;
|
|
41
|
+
let baseToBeRemoved;
|
|
42
|
+
if (pageContext.urlLogical) {
|
|
43
|
+
// Set by onBeforeRoute()
|
|
44
|
+
urlResolved = pageContext.urlLogical;
|
|
45
|
+
baseToBeRemoved = false;
|
|
46
|
+
}
|
|
47
|
+
else if (pageContext._urlRewrite) {
|
|
47
48
|
// Set by `throw render()`
|
|
48
|
-
pageContext._urlRewrite
|
|
49
|
+
urlResolved = pageContext._urlRewrite;
|
|
50
|
+
baseToBeRemoved = false;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
49
53
|
// Set by renderPage()
|
|
50
|
-
pageContext.urlOriginal;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
console.log('pageContext.urlLogical', pageContext.urlLogical)
|
|
54
|
-
console.log('pageContext._urlRewrite', pageContext._urlRewrite)
|
|
55
|
-
console.log('pageContext.urlOriginal', pageContext.urlOriginal)
|
|
56
|
-
console.log()
|
|
57
|
-
//*/
|
|
58
|
-
const baseServer = pageContext._baseServer;
|
|
54
|
+
urlResolved = pageContext.urlOriginal;
|
|
55
|
+
baseToBeRemoved = true;
|
|
56
|
+
}
|
|
59
57
|
assert(urlResolved && typeof urlResolved === 'string');
|
|
60
|
-
|
|
58
|
+
// Remove .pageContext.json
|
|
59
|
+
let urlHandler = pageContext._urlHandler;
|
|
60
|
+
if (!urlHandler)
|
|
61
|
+
urlHandler = (url) => url;
|
|
62
|
+
urlResolved = urlHandler(urlResolved);
|
|
63
|
+
// Remove Base URL.
|
|
64
|
+
// - We assume there isn't any Base URL to the URLs set by the user at `throw render()` and onBeforeRoute()
|
|
65
|
+
// - This makes sense because the Base URL is merely a setting: ideally the user should write code that doesn't know anything about it (so that the user can remove/add/change Base URL without having to modify any code).
|
|
66
|
+
// - pageContext.urlOriginal is the URL of the HTTP request and thus contains the Base URL.
|
|
67
|
+
const baseServer = !baseToBeRemoved ? '/' : pageContext._baseServer;
|
|
68
|
+
// Parse URL
|
|
61
69
|
return parseUrl(urlResolved, baseServer);
|
|
62
70
|
}
|
|
63
71
|
function urlPathnameGetter() {
|
|
@@ -72,47 +80,45 @@ function urlGetter() {
|
|
|
72
80
|
return urlPathnameGetter.call(this);
|
|
73
81
|
}
|
|
74
82
|
function urlParsedGetter() {
|
|
75
|
-
const
|
|
76
|
-
|
|
83
|
+
const {
|
|
84
|
+
// remove hasBaseServer as it isn't part of UrlPublic
|
|
85
|
+
hasBaseServer: _, ...urlParsed } = getUrlParsed(this);
|
|
77
86
|
const hashIsAvailable = isBrowser();
|
|
78
87
|
const warnHashNotAvailable = (prop) => {
|
|
79
88
|
assertWarning(hashIsAvailable, `pageContext.urlParsed.${prop} isn't available on the server-side (HTTP requests don't include the URL hash)`, { onlyOnce: true, showStackTrace: true });
|
|
80
89
|
};
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
pathname,
|
|
84
|
-
pathnameOriginal,
|
|
85
|
-
search,
|
|
86
|
-
searchAll,
|
|
87
|
-
searchOriginal,
|
|
90
|
+
const urlParsedEnhanced = {
|
|
91
|
+
...urlParsed,
|
|
88
92
|
get hash() {
|
|
89
93
|
warnHashNotAvailable('hash');
|
|
90
|
-
return hash;
|
|
94
|
+
return urlParsed.hash;
|
|
91
95
|
},
|
|
92
96
|
get hashOriginal() {
|
|
93
97
|
warnHashNotAvailable('hashOriginal');
|
|
94
|
-
return hashOriginal;
|
|
98
|
+
return urlParsed.hashOriginal;
|
|
95
99
|
},
|
|
100
|
+
// TODO/next-major-release: remove
|
|
96
101
|
get hashString() {
|
|
97
102
|
assertWarning(false, 'pageContext.urlParsed.hashString has been renamed to pageContext.urlParsed.hashOriginal', {
|
|
98
103
|
onlyOnce: true,
|
|
99
104
|
showStackTrace: true
|
|
100
105
|
});
|
|
101
106
|
warnHashNotAvailable('hashString');
|
|
102
|
-
return hashOriginal;
|
|
107
|
+
return urlParsed.hashOriginal;
|
|
103
108
|
},
|
|
109
|
+
// TODO/next-major-release: remove
|
|
104
110
|
get searchString() {
|
|
105
111
|
assertWarning(false, 'pageContext.urlParsed.searchString has been renamed to pageContext.urlParsed.searchOriginal', { onlyOnce: true, showStackTrace: true });
|
|
106
|
-
return searchOriginal;
|
|
112
|
+
return urlParsed.searchOriginal;
|
|
107
113
|
}
|
|
108
114
|
};
|
|
109
|
-
changeEnumerable(
|
|
110
|
-
changeEnumerable(
|
|
115
|
+
changeEnumerable(urlParsedEnhanced, 'hashString', false);
|
|
116
|
+
changeEnumerable(urlParsedEnhanced, 'searchString', false);
|
|
111
117
|
if (!hashIsAvailable) {
|
|
112
|
-
changeEnumerable(
|
|
113
|
-
changeEnumerable(
|
|
118
|
+
changeEnumerable(urlParsedEnhanced, 'hash', false);
|
|
119
|
+
changeEnumerable(urlParsedEnhanced, 'hashOriginal', false);
|
|
114
120
|
}
|
|
115
|
-
return
|
|
121
|
+
return urlParsedEnhanced;
|
|
116
122
|
}
|
|
117
123
|
function assertPageContextUrl(pageContext) {
|
|
118
124
|
assert(typeof pageContext.urlOriginal === 'string');
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { modifyUrl };
|
|
2
|
+
/**
|
|
3
|
+
* Modify a URL.
|
|
4
|
+
*
|
|
5
|
+
* Example: changing the URL pathname for internationalization.
|
|
6
|
+
*
|
|
7
|
+
* https://vike.dev/modifyUrl
|
|
8
|
+
*/
|
|
9
|
+
declare function modifyUrl(url: string, modify: {
|
|
10
|
+
pathname?: string;
|
|
11
|
+
hostname?: string;
|
|
12
|
+
port?: number;
|
|
13
|
+
protocol?: string;
|
|
14
|
+
}): string;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export { modifyUrl };
|
|
2
|
+
import { createUrlFromComponents, parseUrl } from './utils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Modify a URL.
|
|
5
|
+
*
|
|
6
|
+
* Example: changing the URL pathname for internationalization.
|
|
7
|
+
*
|
|
8
|
+
* https://vike.dev/modifyUrl
|
|
9
|
+
*/
|
|
10
|
+
function modifyUrl(url, modify) {
|
|
11
|
+
const urlParsed = parseUrl(url, '/');
|
|
12
|
+
// Pathname
|
|
13
|
+
const pathname = modify.pathname ?? urlParsed.pathname;
|
|
14
|
+
// Origin
|
|
15
|
+
const originParts = [
|
|
16
|
+
modify.protocol ?? urlParsed.protocol ?? '',
|
|
17
|
+
modify.hostname ?? urlParsed.hostname ?? ''
|
|
18
|
+
];
|
|
19
|
+
const port = modify.port ?? urlParsed.port;
|
|
20
|
+
if (port || port === 0) {
|
|
21
|
+
originParts.push(`:${port}`);
|
|
22
|
+
}
|
|
23
|
+
const origin = originParts.join('');
|
|
24
|
+
const urlModified = createUrlFromComponents(origin, pathname,
|
|
25
|
+
// Should we also support modifying search and hash?
|
|
26
|
+
urlParsed.searchOriginal, urlParsed.hashOriginal);
|
|
27
|
+
return urlModified;
|
|
28
|
+
}
|