vike 0.4.180 → 0.4.181-commit-ddcbf7d
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/plugin/plugins/envVars.js +7 -12
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +3 -0
- package/dist/cjs/node/plugin/utils.js +1 -0
- 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/node/runtime/utils.js +1 -0
- 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/shared/route/utils.js +0 -1
- package/dist/cjs/shared/utils.js +0 -1
- package/dist/cjs/utils/PROJECT_VERSION.js +4 -0
- package/dist/cjs/utils/parseUrl.js +168 -87
- package/dist/cjs/utils/projectInfo.js +4 -6
- 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 +23 -21
- package/dist/esm/client/client-routing-runtime/skipLink.js +11 -22
- package/dist/esm/client/client-routing-runtime/utils.d.ts +2 -3
- package/dist/esm/client/client-routing-runtime/utils.js +2 -3
- package/dist/esm/client/server-routing-runtime/utils.d.ts +0 -1
- package/dist/esm/client/server-routing-runtime/utils.js +0 -1
- package/dist/esm/node/plugin/plugins/envVars.d.ts +0 -2
- package/dist/esm/node/plugin/plugins/envVars.js +6 -12
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +3 -0
- package/dist/esm/node/plugin/utils.d.ts +1 -0
- package/dist/esm/node/plugin/utils.js +1 -0
- 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/node/runtime/utils.d.ts +1 -0
- package/dist/esm/node/runtime/utils.js +1 -0
- 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/shared/route/utils.d.ts +0 -1
- package/dist/esm/shared/route/utils.js +0 -1
- package/dist/esm/shared/utils.d.ts +0 -1
- package/dist/esm/shared/utils.js +0 -1
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/utils/PROJECT_VERSION.d.ts +1 -0
- package/dist/esm/utils/PROJECT_VERSION.js +1 -0
- 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 -5
- package/dist/esm/utils/projectInfo.js +2 -4
- 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 +18 -3
- 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
|
@@ -6,35 +6,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
7
|
};
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.
|
|
9
|
+
exports.createUrlFromComponents = exports.assertUrlComponents = exports.isBaseServer = exports.isUrlExternal = exports.isUrlRedirectTarget = exports.isUri = exports.isUrl = exports.assertUsageUrlRedirectTarget = exports.assertUsageUrlPathnameAbsolute = exports.assertUsageUrlPathname = exports.parseUrl = void 0;
|
|
10
10
|
const slice_js_1 = require("./slice.js");
|
|
11
11
|
const assert_js_1 = require("./assert.js");
|
|
12
12
|
const picocolors_1 = __importDefault(require("@brillout/picocolors"));
|
|
13
|
-
function isParsable(url) {
|
|
14
|
-
// `parseUrl()` works with these URLs
|
|
15
|
-
return (isUrlWithProtocol(url) ||
|
|
16
|
-
url.startsWith('/') ||
|
|
17
|
-
url.startsWith('.') ||
|
|
18
|
-
url.startsWith('?') ||
|
|
19
|
-
url.startsWith('#') ||
|
|
20
|
-
url === '');
|
|
21
|
-
}
|
|
22
|
-
exports.isParsable = isParsable;
|
|
23
|
-
function assertUsageUrl(url, errPrefix) {
|
|
24
|
-
(0, assert_js_1.assert)(errPrefix.includes(' but '));
|
|
25
|
-
(0, assert_js_1.assertUsage)(typeof url === 'string', `${errPrefix} should be a string`);
|
|
26
|
-
if (isParsable(url))
|
|
27
|
-
return;
|
|
28
|
-
if (!url.startsWith('/') && !url.includes(':')) {
|
|
29
|
-
(0, assert_js_1.assertUsage)(false, `${errPrefix} is ${picocolors_1.default.cyan(url)} and it should be /${picocolors_1.default.cyan(url)} instead (URL pathnames should start with a leading slash)`);
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
(0, assert_js_1.assertUsage)(false, `${errPrefix} isn't a valid URL`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
exports.assertUsageUrl = assertUsageUrl;
|
|
36
13
|
function parseUrl(url, baseServer) {
|
|
37
|
-
(0, assert_js_1.assert)(
|
|
14
|
+
(0, assert_js_1.assert)(isUrl(url), url);
|
|
38
15
|
(0, assert_js_1.assert)(baseServer.startsWith('/'));
|
|
39
16
|
// Hash
|
|
40
17
|
const [urlWithoutHash, ...hashList] = url.split('#');
|
|
@@ -54,18 +31,24 @@ function parseUrl(url, baseServer) {
|
|
|
54
31
|
searchAll[key] = [...(searchAll.hasOwnProperty(key) ? searchAll[key] : []), val];
|
|
55
32
|
});
|
|
56
33
|
// Origin + pathname
|
|
57
|
-
|
|
58
|
-
(0, assert_js_1.assert)(origin === null || origin === decodeSafe(origin)); // AFAICT decoding the origin is useless
|
|
59
|
-
(0, assert_js_1.assert)(pathnameResolved.startsWith('/'));
|
|
60
|
-
(0, assert_js_1.assert)(origin === null || url.startsWith(origin));
|
|
61
|
-
// `pathnameOriginal`
|
|
34
|
+
let { protocol, origin, pathnameAbsoluteWithBase } = getPathnameAbsoluteWithBase(urlWithoutHashNorSearch, baseServer);
|
|
62
35
|
const pathnameOriginal = urlWithoutHashNorSearch.slice((origin || '').length);
|
|
63
36
|
assertUrlComponents(url, origin, pathnameOriginal, searchOriginal, hashOriginal);
|
|
64
37
|
// Base URL
|
|
65
|
-
let { pathname, hasBaseServer } =
|
|
38
|
+
let { pathname, hasBaseServer } = removeBaseServer(pathnameAbsoluteWithBase, baseServer);
|
|
39
|
+
// pageContext.urlParsed.href
|
|
40
|
+
const href = createUrlFromComponents(origin, pathname, searchOriginal, hashOriginal);
|
|
41
|
+
// pageContext.urlParsed.{hostname, port}
|
|
42
|
+
const host = !origin ? null : origin.slice(protocol.length);
|
|
43
|
+
const { hostname, port } = parseHost(host, url);
|
|
44
|
+
// decode after setting href
|
|
66
45
|
pathname = decodePathname(pathname);
|
|
67
46
|
(0, assert_js_1.assert)(pathname.startsWith('/'));
|
|
68
47
|
return {
|
|
48
|
+
href,
|
|
49
|
+
protocol,
|
|
50
|
+
hostname,
|
|
51
|
+
port,
|
|
69
52
|
origin,
|
|
70
53
|
pathname,
|
|
71
54
|
pathnameOriginal: pathnameOriginal,
|
|
@@ -97,20 +80,20 @@ function decodePathname(urlPathname) {
|
|
|
97
80
|
.join('/');
|
|
98
81
|
return urlPathname;
|
|
99
82
|
}
|
|
100
|
-
function
|
|
83
|
+
function getPathnameAbsoluteWithBase(url, baseServer) {
|
|
101
84
|
// Search and hash already extracted
|
|
102
85
|
(0, assert_js_1.assert)(!url.includes('?') && !url.includes('#'));
|
|
103
86
|
// url has origin
|
|
104
87
|
{
|
|
105
|
-
const { origin, pathname } = parseOrigin(url);
|
|
88
|
+
const { protocol, origin, pathname } = parseOrigin(url);
|
|
106
89
|
if (origin) {
|
|
107
|
-
return { origin, pathname };
|
|
90
|
+
return { protocol, origin, pathnameAbsoluteWithBase: pathname };
|
|
108
91
|
}
|
|
109
92
|
(0, assert_js_1.assert)(pathname === url);
|
|
110
93
|
}
|
|
111
94
|
// url doesn't have origin
|
|
112
95
|
if (url.startsWith('/')) {
|
|
113
|
-
return { origin: null,
|
|
96
|
+
return { protocol: null, origin: null, pathnameAbsoluteWithBase: url };
|
|
114
97
|
}
|
|
115
98
|
else {
|
|
116
99
|
// url is a relative path
|
|
@@ -125,21 +108,70 @@ function getPathname(url, baseServer) {
|
|
|
125
108
|
else {
|
|
126
109
|
base = baseServer;
|
|
127
110
|
}
|
|
128
|
-
const
|
|
129
|
-
return { origin: null,
|
|
111
|
+
const pathnameAbsoluteWithBase = resolveUrlPathnameRelative(url, base);
|
|
112
|
+
return { protocol: null, origin: null, pathnameAbsoluteWithBase: pathnameAbsoluteWithBase };
|
|
130
113
|
}
|
|
131
114
|
}
|
|
132
115
|
function parseOrigin(url) {
|
|
133
116
|
if (!isUrlWithProtocol(url)) {
|
|
134
|
-
|
|
135
|
-
return { pathname: url, origin: null };
|
|
117
|
+
return { pathname: url, origin: null, protocol: null };
|
|
136
118
|
}
|
|
137
119
|
else {
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
|
|
120
|
+
const { protocol, uriWithoutProtocol } = parseProtocol(url);
|
|
121
|
+
(0, assert_js_1.assert)(protocol);
|
|
122
|
+
const [host, ...rest] = uriWithoutProtocol.split('/');
|
|
123
|
+
const origin = protocol + host;
|
|
124
|
+
const pathname = '/' + rest.join('/');
|
|
125
|
+
return { pathname, origin, protocol };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function parseHost(host, url) {
|
|
129
|
+
const ret = { hostname: null, port: null };
|
|
130
|
+
if (!host)
|
|
131
|
+
return ret;
|
|
132
|
+
// hostname
|
|
133
|
+
const [hostname, ...rest] = host.split(':');
|
|
134
|
+
ret.hostname = hostname;
|
|
135
|
+
// port
|
|
136
|
+
if (rest.length > 0) {
|
|
137
|
+
(0, assert_js_1.assert)(rest.length === 1, url);
|
|
138
|
+
const portStr = rest[0];
|
|
139
|
+
const port = parseInt(portStr, 10);
|
|
140
|
+
(0, assert_js_1.assert)(port || port === 0, url);
|
|
141
|
+
ret.port = port;
|
|
142
142
|
}
|
|
143
|
+
return ret;
|
|
144
|
+
}
|
|
145
|
+
function parseProtocol(uri) {
|
|
146
|
+
const SEP = ':';
|
|
147
|
+
const [before, ...after] = uri.split(SEP);
|
|
148
|
+
if (after.length === 0 ||
|
|
149
|
+
// https://github.com/vikejs/vike/commit/886a99ff21e86a8ca699a25cee7edc184aa058e4#r143308934
|
|
150
|
+
// https://en.wikipedia.org/wiki/List_of_URI_schemes
|
|
151
|
+
// https://www.rfc-editor.org/rfc/rfc7595
|
|
152
|
+
!/^[a-z][a-z0-9\+\-]*$/i.test(before)) {
|
|
153
|
+
return { protocol: null, uriWithoutProtocol: uri };
|
|
154
|
+
}
|
|
155
|
+
let protocol = before + SEP;
|
|
156
|
+
let uriWithoutProtocol = after.join(SEP);
|
|
157
|
+
const SEP2 = '//';
|
|
158
|
+
if (uriWithoutProtocol.startsWith(SEP2)) {
|
|
159
|
+
protocol = protocol + SEP2;
|
|
160
|
+
uriWithoutProtocol = uriWithoutProtocol.slice(SEP2.length);
|
|
161
|
+
}
|
|
162
|
+
return { protocol, uriWithoutProtocol };
|
|
163
|
+
}
|
|
164
|
+
function isUrlProtocol(protocol) {
|
|
165
|
+
// Is there an altenrative to having a blacklist?
|
|
166
|
+
// - If the blacklist becomes too big, maybe use a whitelist instead ['tauri://', 'file://', 'capacitor://', 'http://', 'https://']
|
|
167
|
+
const blacklist = [
|
|
168
|
+
// https://docs.ipfs.tech/how-to/address-ipfs-on-web
|
|
169
|
+
'ipfs://',
|
|
170
|
+
'ipns://'
|
|
171
|
+
];
|
|
172
|
+
if (blacklist.includes(protocol))
|
|
173
|
+
return false;
|
|
174
|
+
return protocol.endsWith('://');
|
|
143
175
|
}
|
|
144
176
|
// Adapted from https://stackoverflow.com/questions/14780350/convert-relative-path-to-absolute-using-javascript/14780463#14780463
|
|
145
177
|
function resolveUrlPathnameRelative(pathnameRelative, base) {
|
|
@@ -170,34 +202,15 @@ function resolveUrlPathnameRelative(pathnameRelative, base) {
|
|
|
170
202
|
pathnameAbsolute = '/' + pathnameAbsolute;
|
|
171
203
|
return pathnameAbsolute;
|
|
172
204
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
assertUsage(
|
|
176
|
-
!baseServer.startsWith('http'),
|
|
177
|
-
usageErrorMessagePrefix +
|
|
178
|
-
'`base` is not allowed to start with `http`. Consider using `baseAssets` instead, see https://vike.dev/base-url'
|
|
179
|
-
)
|
|
180
|
-
assertUsage(
|
|
181
|
-
baseServer.startsWith('/'),
|
|
182
|
-
usageErrorMessagePrefix + 'Wrong `base` value `' + baseServer + '`; `base` should start with `/`.'
|
|
183
|
-
)
|
|
184
|
-
assert(isBaseServer(baseServer))
|
|
185
|
-
}
|
|
186
|
-
*/
|
|
187
|
-
function assertPathname(urlPathname) {
|
|
188
|
-
(0, assert_js_1.assert)(urlPathname.startsWith('/'));
|
|
189
|
-
(0, assert_js_1.assert)(!urlPathname.includes('?'));
|
|
190
|
-
(0, assert_js_1.assert)(!urlPathname.includes('#'));
|
|
191
|
-
}
|
|
192
|
-
function analyzeBaseServer(urlPathnameWithBase, baseServer) {
|
|
193
|
-
assertPathname(urlPathnameWithBase);
|
|
205
|
+
function removeBaseServer(pathnameAbsoluteWithBase, baseServer) {
|
|
206
|
+
(0, assert_js_1.assert)(pathnameAbsoluteWithBase.startsWith('/'));
|
|
194
207
|
(0, assert_js_1.assert)(isBaseServer(baseServer));
|
|
195
208
|
// Mutable
|
|
196
|
-
let urlPathname =
|
|
209
|
+
let urlPathname = pathnameAbsoluteWithBase;
|
|
197
210
|
(0, assert_js_1.assert)(urlPathname.startsWith('/'));
|
|
198
211
|
(0, assert_js_1.assert)(baseServer.startsWith('/'));
|
|
199
212
|
if (baseServer === '/') {
|
|
200
|
-
const pathname =
|
|
213
|
+
const pathname = pathnameAbsoluteWithBase;
|
|
201
214
|
return { pathname, hasBaseServer: true };
|
|
202
215
|
}
|
|
203
216
|
// Support `url === '/some-base-url' && baseServer === '/some-base-url/'`
|
|
@@ -207,7 +220,7 @@ function analyzeBaseServer(urlPathnameWithBase, baseServer) {
|
|
|
207
220
|
(0, assert_js_1.assert)(urlPathname === baseServerNormalized);
|
|
208
221
|
}
|
|
209
222
|
if (!urlPathname.startsWith(baseServerNormalized)) {
|
|
210
|
-
const pathname =
|
|
223
|
+
const pathname = pathnameAbsoluteWithBase;
|
|
211
224
|
return { pathname, hasBaseServer: false };
|
|
212
225
|
}
|
|
213
226
|
(0, assert_js_1.assert)(urlPathname.startsWith('/') || urlPathname.startsWith('http'));
|
|
@@ -222,30 +235,98 @@ function isBaseServer(baseServer) {
|
|
|
222
235
|
return baseServer.startsWith('/');
|
|
223
236
|
}
|
|
224
237
|
exports.isBaseServer = isBaseServer;
|
|
225
|
-
function assertUrlComponents(url, origin,
|
|
226
|
-
const urlRecreated = createUrlFromComponents(origin,
|
|
238
|
+
function assertUrlComponents(url, origin, pathnameOriginal, searchOriginal, hashOriginal) {
|
|
239
|
+
const urlRecreated = createUrlFromComponents(origin, pathnameOriginal, searchOriginal, hashOriginal);
|
|
227
240
|
(0, assert_js_1.assert)(url === urlRecreated);
|
|
228
241
|
}
|
|
229
242
|
exports.assertUrlComponents = assertUrlComponents;
|
|
230
|
-
function createUrlFromComponents(origin, pathname,
|
|
231
|
-
const urlRecreated = `${origin || ''}${pathname}${
|
|
243
|
+
function createUrlFromComponents(origin, pathname, search, hash) {
|
|
244
|
+
const urlRecreated = `${origin || ''}${pathname}${search || ''}${hash || ''}`;
|
|
232
245
|
return urlRecreated;
|
|
233
246
|
}
|
|
234
247
|
exports.createUrlFromComponents = createUrlFromComponents;
|
|
235
|
-
function
|
|
236
|
-
//
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
function isUrl(url) {
|
|
249
|
+
// parseUrl() works with these URLs
|
|
250
|
+
return isUrlWithProtocol(url) || url.startsWith('/') || isUrlPathnameRelative(url);
|
|
251
|
+
}
|
|
252
|
+
exports.isUrl = isUrl;
|
|
253
|
+
function isUrlRedirectTarget(url) {
|
|
254
|
+
return url.startsWith('/') || isUri(url) || isUrlWithProtocol(url);
|
|
255
|
+
}
|
|
256
|
+
exports.isUrlRedirectTarget = isUrlRedirectTarget;
|
|
257
|
+
function isUrlPathnameRelative(url) {
|
|
258
|
+
return ['.', '?', '#'].some((c) => url.startsWith(c)) || url === '';
|
|
259
|
+
}
|
|
260
|
+
function isUrlExternal(url) {
|
|
261
|
+
return !url.startsWith('/') && !isUrlPathnameRelative(url);
|
|
262
|
+
}
|
|
263
|
+
exports.isUrlExternal = isUrlExternal;
|
|
264
|
+
/*
|
|
265
|
+
URL with protocol.
|
|
266
|
+
|
|
267
|
+
http://example.com
|
|
268
|
+
https://exmaple.com
|
|
269
|
+
tauri://localhost
|
|
270
|
+
file://example.com
|
|
271
|
+
capacitor://localhost/assets/chunks/chunk-DJBYDrsP.js
|
|
272
|
+
|
|
273
|
+
[Tauri](https://github.com/vikejs/vike/issues/808)
|
|
274
|
+
[Electron (`file://`)](https://github.com/vikejs/vike/issues/1557)
|
|
275
|
+
[Capacitor](https://github.com/vikejs/vike/issues/1706)
|
|
276
|
+
*/
|
|
277
|
+
function isUrlWithProtocol(url) {
|
|
278
|
+
const { protocol } = parseProtocol(url);
|
|
279
|
+
return !!protocol && isUrlProtocol(protocol);
|
|
280
|
+
}
|
|
281
|
+
/*
|
|
282
|
+
URIs that aren't URLs.
|
|
283
|
+
|
|
284
|
+
mailto:john@example.com
|
|
285
|
+
|
|
286
|
+
ipfs://bafybeiemxf5abjwjbikoz4mc3a3dla6ual3jsgpdr4cjr3oz3evfyavhwq/wiki/Vincent_van_Gogh.html
|
|
287
|
+
|
|
288
|
+
magnet:?xt=urn:btih:3a15e1ac49683d91b20c2ffc252ea612a6c01bd7&dn=The.Empire.Strikes.Back.1980.Remastered.1080p.BluRay.DDP.7.1.x265-EDGE2020.mkv&xl=3225443573&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://tracker.torrent.eu.org:451&tr=udp://open.stealth.si:80/announce&tr=udp://tracker.openbittorrent.com:6969&tr=udp://tracker.tiny-vps.com:6969/announce&tr=udp://open.demonii.com:1337
|
|
289
|
+
|
|
290
|
+
We need to treat URIs differently than URLs.
|
|
291
|
+
- For example, we cannot parse URIs (their structure is unknown e.g. a `magnet:` URI is completely different than a `http://` URL).
|
|
292
|
+
- The protocols tauri:// file:// capacitor:// follow the same structure as http:// and https:// URLs.
|
|
293
|
+
- Thus we can parse them like http:// and https:// URLs.
|
|
294
|
+
*/
|
|
295
|
+
function isUri(uri) {
|
|
296
|
+
const { protocol } = parseProtocol(uri);
|
|
297
|
+
return !!protocol && !isUrlProtocol(uri);
|
|
298
|
+
}
|
|
299
|
+
exports.isUri = isUri;
|
|
300
|
+
function assertUsageUrlPathname(url, errPrefix) {
|
|
301
|
+
assertUsageUrl(url, errPrefix, { allowRelative: true });
|
|
302
|
+
}
|
|
303
|
+
exports.assertUsageUrlPathname = assertUsageUrlPathname;
|
|
304
|
+
function assertUsageUrlPathnameAbsolute(url, errPrefix) {
|
|
305
|
+
assertUsageUrl(url, errPrefix);
|
|
306
|
+
}
|
|
307
|
+
exports.assertUsageUrlPathnameAbsolute = assertUsageUrlPathnameAbsolute;
|
|
308
|
+
function assertUsageUrlRedirectTarget(url, errPrefix, isUnresolved) {
|
|
309
|
+
assertUsageUrl(url, errPrefix, { isRedirectTarget: isUnresolved ? 'unresolved' : true });
|
|
310
|
+
}
|
|
311
|
+
exports.assertUsageUrlRedirectTarget = assertUsageUrlRedirectTarget;
|
|
312
|
+
function assertUsageUrl(url, errPrefix, { allowRelative, isRedirectTarget } = {}) {
|
|
313
|
+
if (url.startsWith('/'))
|
|
314
|
+
return;
|
|
315
|
+
let errMsg = `${errPrefix} is ${picocolors_1.default.string(url)} but it should start with ${picocolors_1.default.string('/')}`;
|
|
316
|
+
if (isRedirectTarget) {
|
|
317
|
+
if (isUrlRedirectTarget(url))
|
|
318
|
+
return;
|
|
319
|
+
errMsg += ` or a protocol (${picocolors_1.default.string('http://')}, ${picocolors_1.default.string('mailto:')}, ...)`;
|
|
320
|
+
if (isRedirectTarget === 'unresolved') {
|
|
321
|
+
if (url === '*')
|
|
322
|
+
return;
|
|
323
|
+
errMsg += `, or be ${picocolors_1.default.string('*')}`;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (allowRelative) {
|
|
327
|
+
if (isUrlPathnameRelative(url))
|
|
328
|
+
return;
|
|
329
|
+
errMsg += ', or be a relative URL';
|
|
330
|
+
}
|
|
331
|
+
(0, assert_js_1.assertUsage)(false, errMsg);
|
|
251
332
|
}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
exports.
|
|
6
|
-
const projectInfo = {
|
|
3
|
+
exports.projectInfo = void 0;
|
|
4
|
+
const PROJECT_VERSION_js_1 = require("./PROJECT_VERSION.js");
|
|
5
|
+
exports.projectInfo = {
|
|
7
6
|
projectName: 'Vike',
|
|
8
|
-
projectVersion: PROJECT_VERSION
|
|
7
|
+
projectVersion: PROJECT_VERSION_js_1.PROJECT_VERSION
|
|
9
8
|
};
|
|
10
|
-
exports.projectInfo = projectInfo;
|
|
@@ -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';
|
|
@@ -20,12 +20,14 @@ import { getErrorPageId } from '../../shared/error-page.js';
|
|
|
20
20
|
const globalObject = getGlobalObject('renderPageClientSide.ts', { renderCounter: 0 });
|
|
21
21
|
async function renderPageClientSide(renderArgs) {
|
|
22
22
|
const { scrollTarget, urlOriginal = getCurrentUrl(), overwriteLastHistoryEntry = false, isBackwardNavigation, pageContextsFromRewrite = [], redirectCount = 0, isUserLandPushStateNavigation, isClientSideNavigation = true } = renderArgs;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const { isRenderOutdated, setHydrationCanBeAborted, isFirstRender } = getIsRenderOutdated();
|
|
24
|
+
// Note that pageContext.isHydration isn't equivalent to isFirstRender
|
|
25
|
+
// - Thus pageContext.isHydration isn't equivalent to !pageContext.isClientSideNavigation
|
|
26
|
+
// - `pageContext.isHydration === !isFirstRender && !isErrorPage`
|
|
27
|
+
assert(isClientSideNavigation === !isFirstRender);
|
|
26
28
|
assertNoInfiniteAbortLoop(pageContextsFromRewrite.length, redirectCount);
|
|
27
29
|
if (globalObject.clientRoutingIsDisabled) {
|
|
28
|
-
|
|
30
|
+
redirectHard(urlOriginal);
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
33
|
await renderPageNominal();
|
|
@@ -64,7 +66,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
64
66
|
}
|
|
65
67
|
// Route
|
|
66
68
|
let pageContextRouted;
|
|
67
|
-
if (
|
|
69
|
+
if (isFirstRender) {
|
|
68
70
|
const pageContextSerialized = getPageContextFromHooks_serialized();
|
|
69
71
|
pageContextRouted = pageContextSerialized;
|
|
70
72
|
}
|
|
@@ -89,7 +91,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
89
91
|
return;
|
|
90
92
|
}
|
|
91
93
|
if (!isClientRoutable) {
|
|
92
|
-
|
|
94
|
+
redirectHard(urlOriginal);
|
|
93
95
|
return;
|
|
94
96
|
}
|
|
95
97
|
assert(hasProp(pageContextFromRoute, '_pageId', 'string')); // Help TS
|
|
@@ -108,7 +110,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
108
110
|
objectAssign(pageContext, await loadUserFilesClientSide(pageContext._pageId, pageContext._pageFilesAll, pageContext._pageConfigs));
|
|
109
111
|
}
|
|
110
112
|
catch (err) {
|
|
111
|
-
if (handleErrorFetchingStaticAssets(err, pageContext,
|
|
113
|
+
if (handleErrorFetchingStaticAssets(err, pageContext, isFirstRender)) {
|
|
112
114
|
return;
|
|
113
115
|
}
|
|
114
116
|
else {
|
|
@@ -130,7 +132,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
130
132
|
if (isRenderOutdated())
|
|
131
133
|
return;
|
|
132
134
|
// Get pageContext from hooks (fetched from server, and/or directly called on the client-side)
|
|
133
|
-
if (
|
|
135
|
+
if (isFirstRender) {
|
|
134
136
|
assert(hasProp(pageContext, '_hasPageContextFromServer', 'true'));
|
|
135
137
|
let pageContextAugmented;
|
|
136
138
|
try {
|
|
@@ -183,7 +185,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
183
185
|
/* When we can't render the error page, we prefer showing a blank page over letting the server-side try because otherwise:
|
|
184
186
|
- We risk running into an infinite loop of reloads which would overload the server.
|
|
185
187
|
- An infinite reloading page is a even worse UX than a blank page.
|
|
186
|
-
|
|
188
|
+
redirectHard(urlOriginal)
|
|
187
189
|
*/
|
|
188
190
|
console.error(err);
|
|
189
191
|
}
|
|
@@ -228,9 +230,9 @@ async function renderPageClientSide(renderArgs) {
|
|
|
228
230
|
// throw redirect('/some-url')
|
|
229
231
|
if (pageContextAbort._urlRedirect) {
|
|
230
232
|
const urlRedirect = pageContextAbort._urlRedirect.url;
|
|
231
|
-
if (urlRedirect.startsWith('
|
|
233
|
+
if (!urlRedirect.startsWith('/')) {
|
|
232
234
|
// External redirection
|
|
233
|
-
|
|
235
|
+
redirectHard(urlRedirect);
|
|
234
236
|
return;
|
|
235
237
|
}
|
|
236
238
|
else {
|
|
@@ -267,7 +269,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
267
269
|
objectAssign(pageContext, await loadUserFilesClientSide(pageContext._pageId, pageContext._pageFilesAll, pageContext._pageConfigs));
|
|
268
270
|
}
|
|
269
271
|
catch (err) {
|
|
270
|
-
if (handleErrorFetchingStaticAssets(err, pageContext,
|
|
272
|
+
if (handleErrorFetchingStaticAssets(err, pageContext, isFirstRender)) {
|
|
271
273
|
return;
|
|
272
274
|
}
|
|
273
275
|
else {
|
|
@@ -341,7 +343,7 @@ async function renderPageClientSide(renderArgs) {
|
|
|
341
343
|
*/
|
|
342
344
|
addLinkPrefetchHandlers(pageContext);
|
|
343
345
|
// onHydrationEnd()
|
|
344
|
-
if (
|
|
346
|
+
if (isFirstRender && !onRenderClientError) {
|
|
345
347
|
assertHook(pageContext, 'onHydrationEnd');
|
|
346
348
|
const hook = getHook(pageContext, 'onHydrationEnd');
|
|
347
349
|
if (hook) {
|
|
@@ -395,11 +397,11 @@ function changeUrl(url, overwriteLastHistoryEntry) {
|
|
|
395
397
|
pushHistory(url, overwriteLastHistoryEntry);
|
|
396
398
|
updateState();
|
|
397
399
|
}
|
|
398
|
-
function handleErrorFetchingStaticAssets(err, pageContext,
|
|
400
|
+
function handleErrorFetchingStaticAssets(err, pageContext, isFirstRender) {
|
|
399
401
|
if (!isErrorFetchingStaticAssets(err)) {
|
|
400
402
|
return false;
|
|
401
403
|
}
|
|
402
|
-
if (
|
|
404
|
+
if (isFirstRender) {
|
|
403
405
|
disableClientRouting(err, false);
|
|
404
406
|
// This may happen if the frontend was newly deployed during hydration.
|
|
405
407
|
// Ideally: re-try a couple of times by reloading the page (not entirely trivial to implement since `localStorage` is needed.)
|
|
@@ -408,7 +410,7 @@ function handleErrorFetchingStaticAssets(err, pageContext, isHydrationRender) {
|
|
|
408
410
|
else {
|
|
409
411
|
disableClientRouting(err, true);
|
|
410
412
|
}
|
|
411
|
-
|
|
413
|
+
redirectHard(pageContext.urlOriginal);
|
|
412
414
|
return true;
|
|
413
415
|
}
|
|
414
416
|
function disableClientRouting(err, log) {
|
|
@@ -438,10 +440,10 @@ function getIsRenderOutdated() {
|
|
|
438
440
|
};
|
|
439
441
|
/** Whether the rendering should be aborted because a new rendering has started. We should call this after each `await`. */
|
|
440
442
|
const isRenderOutdated = (isRenderCleanup) => {
|
|
441
|
-
// Never abort
|
|
443
|
+
// Never abort first render if `hydrationCanBeAborted` isn't `true`
|
|
442
444
|
{
|
|
443
|
-
const
|
|
444
|
-
if (
|
|
445
|
+
const isFirstRender = renderNumber === 1;
|
|
446
|
+
if (isFirstRender && !hydrationCanBeAborted && !isRenderCleanup) {
|
|
445
447
|
return false;
|
|
446
448
|
}
|
|
447
449
|
}
|
|
@@ -451,7 +453,7 @@ function getIsRenderOutdated() {
|
|
|
451
453
|
return {
|
|
452
454
|
isRenderOutdated,
|
|
453
455
|
setHydrationCanBeAborted,
|
|
454
|
-
|
|
456
|
+
isFirstRender: renderNumber === 1
|
|
455
457
|
};
|
|
456
458
|
}
|
|
457
459
|
function getRenderCount() {
|
|
@@ -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) {
|