vike 0.4.144-commit-f7ab002 → 0.4.144-commit-de18325
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/__internal/index.js +6 -2
- package/dist/cjs/node/plugin/plugins/commonConfig.js +0 -3
- package/dist/cjs/node/plugin/plugins/devConfig/index.js +1 -0
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +58 -40
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +1 -0
- package/dist/cjs/node/plugin/plugins/previewConfig.js +5 -0
- package/dist/cjs/node/prerender/runPrerender.js +10 -11
- package/dist/cjs/node/prerender/utils.js +1 -1
- package/dist/cjs/node/runtime/html/serializePageContextClientSide.js +1 -0
- package/dist/cjs/node/runtime/renderPage/debugPageFiles.js +5 -5
- package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +1 -1
- package/dist/cjs/node/runtime/renderPage.js +3 -3
- package/dist/cjs/node/runtime/utils.js +1 -1
- package/dist/cjs/shared/addUrlComputedProps.js +24 -12
- package/dist/cjs/shared/route/executeOnBeforeRouteHook.js +41 -15
- package/dist/cjs/shared/route/index.js +22 -32
- package/dist/cjs/shared/route/resolveRouteFunction.js +1 -1
- package/dist/cjs/shared/utils.js +1 -1
- package/dist/cjs/utils/{hasPropertyGetter.js → isPropertyGetter.js} +3 -3
- package/dist/cjs/utils/projectInfo.js +1 -1
- package/dist/esm/__internal/index.d.ts +6 -3
- package/dist/esm/__internal/index.js +8 -3
- package/dist/esm/client/client-routing-runtime/createPageContext.d.ts +2 -3
- package/dist/esm/client/client-routing-runtime/createPageContext.js +3 -3
- package/dist/esm/client/client-routing-runtime/entry.js +2 -2
- package/dist/esm/client/client-routing-runtime/getPageContext.d.ts +0 -1
- package/dist/esm/client/client-routing-runtime/getPageContext.js +6 -9
- package/dist/esm/client/client-routing-runtime/history.d.ts +3 -1
- package/dist/esm/client/client-routing-runtime/history.js +26 -8
- package/dist/esm/client/client-routing-runtime/installClientRouter.d.ts +21 -0
- package/dist/esm/client/client-routing-runtime/{useClientRouter.js → installClientRouter.js} +248 -242
- package/dist/esm/client/client-routing-runtime/isClientSideRoutable.d.ts +8 -0
- package/dist/esm/client/client-routing-runtime/isClientSideRoutable.js +15 -0
- package/dist/esm/client/client-routing-runtime/navigate.d.ts +0 -2
- package/dist/esm/client/client-routing-runtime/navigate.js +10 -8
- package/dist/esm/client/client-routing-runtime/prefetch.js +54 -28
- package/dist/esm/client/client-routing-runtime/skipLink.d.ts +0 -1
- package/dist/esm/client/client-routing-runtime/skipLink.js +1 -2
- package/dist/esm/client/server-routing-runtime/getPageContext.js +1 -1
- package/dist/esm/client/shared/executeOnRenderClientHook.js +6 -5
- package/dist/esm/client/shared/getPageContextProxyForUser.js +13 -7
- package/dist/esm/client/shared/loadPageFilesClientSide.d.ts +8 -3
- package/dist/esm/client/shared/loadPageFilesClientSide.js +5 -5
- package/dist/esm/node/plugin/plugins/commonConfig.js +0 -3
- package/dist/esm/node/plugin/plugins/devConfig/index.js +1 -0
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig.js +58 -40
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVirtualFilePageConfigs.js +1 -0
- package/dist/esm/node/plugin/plugins/previewConfig.js +5 -0
- package/dist/esm/node/prerender/runPrerender.js +11 -12
- package/dist/esm/node/prerender/utils.d.ts +1 -1
- package/dist/esm/node/prerender/utils.js +1 -1
- package/dist/esm/node/runtime/html/serializePageContextClientSide.js +1 -0
- package/dist/esm/node/runtime/renderPage/debugPageFiles.d.ts +5 -5
- package/dist/esm/node/runtime/renderPage/debugPageFiles.js +5 -5
- package/dist/esm/node/runtime/renderPage/loadPageFilesServerSide.d.ts +2 -2
- package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +1 -1
- package/dist/esm/node/runtime/renderPage.js +3 -3
- package/dist/esm/node/runtime/utils.d.ts +1 -1
- package/dist/esm/node/runtime/utils.js +1 -1
- package/dist/esm/shared/addUrlComputedProps.d.ts +1 -0
- package/dist/esm/shared/addUrlComputedProps.js +25 -13
- package/dist/esm/shared/route/executeOnBeforeRouteHook.d.ts +5 -8
- package/dist/esm/shared/route/executeOnBeforeRouteHook.js +41 -15
- package/dist/esm/shared/route/index.d.ts +12 -10
- package/dist/esm/shared/route/index.js +23 -33
- package/dist/esm/shared/route/resolveRouteFunction.js +1 -1
- package/dist/esm/shared/utils.d.ts +1 -1
- package/dist/esm/shared/utils.js +1 -1
- package/dist/esm/utils/isPropertyGetter.d.ts +1 -0
- package/dist/esm/utils/{hasPropertyGetter.js → isPropertyGetter.js} +1 -1
- package/dist/esm/utils/projectInfo.d.ts +1 -1
- package/dist/esm/utils/projectInfo.js +1 -1
- package/package.json +1 -1
- package/dist/esm/client/client-routing-runtime/getPageId.d.ts +0 -10
- package/dist/esm/client/client-routing-runtime/getPageId.js +0 -17
- package/dist/esm/client/client-routing-runtime/skipLink/isClientSideRoutable.d.ts +0 -2
- package/dist/esm/client/client-routing-runtime/skipLink/isClientSideRoutable.js +0 -15
- package/dist/esm/client/client-routing-runtime/useClientRouter.d.ts +0 -6
- package/dist/esm/utils/hasPropertyGetter.d.ts +0 -1
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
export { prefetch };
|
|
2
2
|
export { addLinkPrefetchHandlers };
|
|
3
|
-
import { assert, assertClientRouting, assertUsage, checkIfClientRouting } from './utils.js';
|
|
3
|
+
import { assert, assertClientRouting, assertUsage, assertWarning, checkIfClientRouting, getGlobalObject, objectAssign } from './utils.js';
|
|
4
4
|
import { isErrorFetchingStaticAssets, loadPageFilesClientSide } from '../shared/loadPageFilesClientSide.js';
|
|
5
|
-
import {
|
|
6
|
-
import { getPageId } from './getPageId.js';
|
|
5
|
+
import { skipLink } from './skipLink.js';
|
|
7
6
|
import { getPrefetchSettings } from './prefetch/getPrefetchSettings.js';
|
|
8
7
|
import { isAlreadyPrefetched, markAsAlreadyPrefetched } from './prefetch/alreadyPrefetched.js';
|
|
9
|
-
import { disableClientRouting } from './
|
|
8
|
+
import { disableClientRouting } from './installClientRouter.js';
|
|
10
9
|
import { isExternalLink } from './isExternalLink.js';
|
|
10
|
+
import { isClientSideRoutable } from './isClientSideRoutable.js';
|
|
11
|
+
import { createPageContext } from './createPageContext.js';
|
|
12
|
+
import { route } from '../../shared/route/index.js';
|
|
11
13
|
assertClientRouting();
|
|
12
|
-
const
|
|
14
|
+
const globalObject = getGlobalObject('prefetch.ts', { linkPrefetchHandlerAdded: new Map() });
|
|
15
|
+
async function prefetchAssets(pageId, pageContext) {
|
|
16
|
+
try {
|
|
17
|
+
await loadPageFilesClientSide(pageId, pageContext);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
if (isErrorFetchingStaticAssets(err)) {
|
|
21
|
+
disableClientRouting(err, true);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
throw err;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
13
28
|
/**
|
|
14
29
|
* Programmatically prefetch client assets.
|
|
15
30
|
*
|
|
@@ -21,33 +36,38 @@ async function prefetch(url) {
|
|
|
21
36
|
assertUsage(checkIfClientRouting(), 'prefetch() only works with Client Routing, see https://vike.dev/prefetch', {
|
|
22
37
|
showStackTrace: true
|
|
23
38
|
});
|
|
24
|
-
|
|
39
|
+
const errPrefix = `Cannot prefetch URL ${url} because it`;
|
|
40
|
+
assertUsage(!isExternalLink(url), `${errPrefix} lives on another domain`, { showStackTrace: true });
|
|
25
41
|
if (isAlreadyPrefetched(url))
|
|
26
42
|
return;
|
|
27
43
|
markAsAlreadyPrefetched(url);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
if (isErrorFetchingStaticAssets(err)) {
|
|
35
|
-
disableClientRouting(err, true);
|
|
36
|
-
}
|
|
37
|
-
else {
|
|
38
|
-
throw err;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
44
|
+
const pageContext = await createPageContext(url);
|
|
45
|
+
let pageContextFromRoute;
|
|
46
|
+
try {
|
|
47
|
+
pageContextFromRoute = await route(pageContext);
|
|
41
48
|
}
|
|
49
|
+
catch {
|
|
50
|
+
// If a route() hook has a bug or `throw render()` / `throw redirect()`
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const pageId = pageContextFromRoute._pageId;
|
|
54
|
+
if (!pageId) {
|
|
55
|
+
assertWarning(false, `${errPrefix} doesn't match the route of any of your pages`, {
|
|
56
|
+
showStackTrace: true,
|
|
57
|
+
onlyOnce: false
|
|
58
|
+
});
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
await prefetchAssets(pageId, pageContext);
|
|
42
62
|
}
|
|
43
63
|
function addLinkPrefetchHandlers(pageContext) {
|
|
44
64
|
// Current URL is already prefetched
|
|
45
65
|
markAsAlreadyPrefetched(pageContext.urlPathname);
|
|
46
66
|
const linkTags = [...document.getElementsByTagName('A')];
|
|
47
67
|
linkTags.forEach((linkTag) => {
|
|
48
|
-
if (linkPrefetchHandlerAdded.has(linkTag))
|
|
68
|
+
if (globalObject.linkPrefetchHandlerAdded.has(linkTag))
|
|
49
69
|
return;
|
|
50
|
-
linkPrefetchHandlerAdded.set(linkTag, true);
|
|
70
|
+
globalObject.linkPrefetchHandlerAdded.set(linkTag, true);
|
|
51
71
|
const url = linkTag.getAttribute('href');
|
|
52
72
|
if (skipLink(linkTag))
|
|
53
73
|
return;
|
|
@@ -59,17 +79,17 @@ function addLinkPrefetchHandlers(pageContext) {
|
|
|
59
79
|
return;
|
|
60
80
|
if (prefetchStaticAssets === 'hover') {
|
|
61
81
|
linkTag.addEventListener('mouseover', () => {
|
|
62
|
-
|
|
82
|
+
prefetchIfPossible(url);
|
|
63
83
|
});
|
|
64
84
|
linkTag.addEventListener('touchstart', () => {
|
|
65
|
-
|
|
85
|
+
prefetchIfPossible(url);
|
|
66
86
|
}, { passive: true });
|
|
67
87
|
}
|
|
68
88
|
if (prefetchStaticAssets === 'viewport') {
|
|
69
89
|
const observer = new IntersectionObserver((entries) => {
|
|
70
90
|
entries.forEach((entry) => {
|
|
71
91
|
if (entry.isIntersecting) {
|
|
72
|
-
|
|
92
|
+
prefetchIfPossible(url);
|
|
73
93
|
observer.disconnect();
|
|
74
94
|
}
|
|
75
95
|
});
|
|
@@ -78,14 +98,20 @@ function addLinkPrefetchHandlers(pageContext) {
|
|
|
78
98
|
}
|
|
79
99
|
});
|
|
80
100
|
}
|
|
81
|
-
async function
|
|
101
|
+
async function prefetchIfPossible(url) {
|
|
102
|
+
const pageContext = await createPageContext(url);
|
|
103
|
+
let pageContextFromRoute;
|
|
82
104
|
try {
|
|
83
|
-
|
|
84
|
-
return;
|
|
105
|
+
pageContextFromRoute = await route(pageContext);
|
|
85
106
|
}
|
|
86
107
|
catch {
|
|
87
108
|
// If a route() hook has a bug or `throw render()` / `throw redirect()`
|
|
88
109
|
return;
|
|
89
110
|
}
|
|
90
|
-
|
|
111
|
+
objectAssign(pageContext, pageContextFromRoute);
|
|
112
|
+
if (!pageContext._pageId)
|
|
113
|
+
return;
|
|
114
|
+
if (!(await isClientSideRoutable(pageContext)))
|
|
115
|
+
return;
|
|
116
|
+
await prefetchAssets(pageContext._pageId, pageContext);
|
|
91
117
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
export { skipLink };
|
|
2
|
-
export { isClientSideRoutable } from './skipLink/isClientSideRoutable.js';
|
|
3
2
|
import { getBaseServer } from './getBaseServer.js';
|
|
4
3
|
import { isExternalLink } from './isExternalLink.js';
|
|
5
4
|
import { assert, parseUrl, isBaseServer, isParsable } from './utils.js';
|
|
6
|
-
import { isDisableAutomaticLinkInterception } from './
|
|
5
|
+
import { isDisableAutomaticLinkInterception } from './installClientRouter.js';
|
|
7
6
|
function skipLink(linkTag) {
|
|
8
7
|
const url = linkTag.getAttribute('href');
|
|
9
8
|
if (url === null)
|
|
@@ -26,7 +26,7 @@ async function loadPageFiles(pageId) {
|
|
|
26
26
|
_pageFilesAll: pageFilesAll,
|
|
27
27
|
_pageConfigs: pageConfigs
|
|
28
28
|
});
|
|
29
|
-
objectAssign(pageContextAddendum, await loadPageFilesClientSide(
|
|
29
|
+
objectAssign(pageContextAddendum, await loadPageFilesClientSide(pageId, pageContextAddendum));
|
|
30
30
|
pageFilesAll
|
|
31
31
|
.filter((p) => p.fileType !== '.page.server')
|
|
32
32
|
.forEach((p) => {
|
|
@@ -19,10 +19,11 @@ async function executeOnRenderClientHook(pageContext, isClientRouting) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
if (!hook) {
|
|
22
|
-
const
|
|
22
|
+
const urlToShowToUser = getUrlToShowToUser(pageContext);
|
|
23
|
+
assert(urlToShowToUser);
|
|
23
24
|
if (pageContext._pageConfigs.length > 0) {
|
|
24
25
|
// V1 design
|
|
25
|
-
assertUsage(false, `No onRenderClient() hook defined for URL '${
|
|
26
|
+
assertUsage(false, `No onRenderClient() hook defined for URL '${urlToShowToUser}', but it's needed, see https://vike.dev/onRenderClient`);
|
|
26
27
|
}
|
|
27
28
|
else {
|
|
28
29
|
// TODO/v1-release: remove
|
|
@@ -30,11 +31,11 @@ async function executeOnRenderClientHook(pageContext, isClientRouting) {
|
|
|
30
31
|
const pageClientsFilesLoaded = pageContext._pageFilesLoaded.filter((p) => p.fileType === '.page.client');
|
|
31
32
|
let errMsg;
|
|
32
33
|
if (pageClientsFilesLoaded.length === 0) {
|
|
33
|
-
errMsg = 'No file `*.page.client.*` found for URL ' +
|
|
34
|
+
errMsg = 'No file `*.page.client.*` found for URL ' + urlToShowToUser;
|
|
34
35
|
}
|
|
35
36
|
else {
|
|
36
37
|
errMsg =
|
|
37
|
-
'One of the following files should export a
|
|
38
|
+
'One of the following files should export a render() hook: ' +
|
|
38
39
|
pageClientsFilesLoaded.map((p) => p.filePath).join(' ');
|
|
39
40
|
}
|
|
40
41
|
assertUsage(false, errMsg);
|
|
@@ -47,7 +48,7 @@ async function executeOnRenderClientHook(pageContext, isClientRouting) {
|
|
|
47
48
|
const hookResult = await executeHook(() => renderHook(pageContextForUserConsumption), hookName, hook.hookFilePath);
|
|
48
49
|
assertUsage(hookResult === undefined, `The ${hookName}() hook defined by ${hook.hookFilePath} isn't allowed to return a value`);
|
|
49
50
|
}
|
|
50
|
-
function
|
|
51
|
+
function getUrlToShowToUser(pageContext) {
|
|
51
52
|
let url;
|
|
52
53
|
// try/catch to avoid passToClient assertUsage() (although: this may not be needed anymore, since we're now accessing pageContext and not pageContextForUserConsumption)
|
|
53
54
|
try {
|
|
@@ -14,14 +14,14 @@ function getPageContextProxyForUser(pageContext) {
|
|
|
14
14
|
const val = pageContext[prop];
|
|
15
15
|
const propName = JSON.stringify(prop);
|
|
16
16
|
assertUsage(val !== notSerializable, `pageContext[${propName}] couldn't be serialized and, therefore, is missing on the client-side. Check the server logs for more information.`);
|
|
17
|
-
|
|
17
|
+
assertIsDefined(pageContext, prop);
|
|
18
18
|
return val;
|
|
19
19
|
}
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
|
-
function
|
|
23
|
-
// We disable
|
|
24
|
-
// - Vue tries to read its old value first. This triggers a `
|
|
22
|
+
function assertIsDefined(pageContext, prop) {
|
|
23
|
+
// We disable assertIsDefined() for the next attempt to read `prop`, because of how Vue's reactivity work. When changing a reactive object:
|
|
24
|
+
// - Vue tries to read its old value first. This triggers a `assertIsDefined()` failure if e.g. `pageContextOldReactive.routeParams = pageContextNew.routeParams` and `pageContextOldReactive` has no `routeParams`.
|
|
25
25
|
// - Vue seems to read __v_raw before reading the property
|
|
26
26
|
if (globalObject.prev === prop || globalObject.prev === '__v_raw')
|
|
27
27
|
return;
|
|
@@ -30,17 +30,23 @@ function assertPassToClient(pageContext, prop, errMsg) {
|
|
|
30
30
|
return;
|
|
31
31
|
if (isExpected(prop))
|
|
32
32
|
return;
|
|
33
|
+
const propName = JSON.stringify(prop);
|
|
34
|
+
/* This handling would be the clearest but, unfortunately, it's fundamentally problematic:
|
|
35
|
+
* - It would force the pageContext value consumer to be synchronized with the pageContext value provider. For example, if vike-react wants to conditionally do something dependening on wehther some optional pageContext value was provided by some optional vike-react-* integration package.
|
|
36
|
+
* - If a pageContext value is set by an optional hook, then it's expected that the value is undefined if the hook doesn't exist.
|
|
37
|
+
const errMsg = `pageContext[${propName}] is \`undefined\` on the client-side. If it's defined on the server-side then add ${propName} to passToClient (https://vike.dev/passToClient), otherwise make sure your client-side hooks always define it (e.g. set it to \`null\` instead of \`undefined\`).`
|
|
38
|
+
assertUsage(false, errMsg)
|
|
39
|
+
*/
|
|
33
40
|
if (pageContext._hasPageContextFromServer && !pageContext._hasPageContextFromClient) {
|
|
34
41
|
// We can safely assume that the property is missing in passToClient, because the server-side defines all passToClient properties even if they have an undefined value:
|
|
35
42
|
// ```
|
|
36
43
|
// <script id="vike_pageContext" type="application/json">{"_pageId":"/pages/admin","user":"!undefined","pageProps":"!undefined","title":"!undefined","abortReason":"!undefined","_urlRewrite":null}</script>
|
|
37
44
|
// ```
|
|
38
45
|
// Note how properties have "!undefined" values => we can tell whether an undefined pageContext value exists in passToClient.
|
|
39
|
-
assertUsage(false,
|
|
46
|
+
assertUsage(false, `pageContext[${propName}] isn't available on the client-side because ${propName} is missing in passToClient, see https://vike.dev/passToClient`);
|
|
40
47
|
}
|
|
41
48
|
else {
|
|
42
|
-
// Do nothing, not even a warning.
|
|
43
|
-
// Because we don't know whether the user expects the pageContext value to be undefined. (E.g. a client-side onBeforeRender() hook conditionally setting a pageContext value.)
|
|
49
|
+
// Do nothing, not even a warning, because we don't know whether the user expects that the pageContext value can be undefined. (E.g. a pageContext value that is defined by an optional hook.)
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
const IGNORE_LIST = [
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { type PageFile, type PageContextExports } from '../../shared/getPageFiles.js';
|
|
2
|
-
import type { PageConfigRuntime } from '../../shared/page-configs/PageConfig.js';
|
|
3
1
|
export { loadPageFilesClientSide };
|
|
4
2
|
export { isErrorFetchingStaticAssets };
|
|
5
|
-
|
|
3
|
+
export type { PageContextPageFiles };
|
|
4
|
+
import { type PageFile, type PageContextExports } from '../../shared/getPageFiles.js';
|
|
5
|
+
import type { PageConfigRuntime } from '../../shared/page-configs/PageConfig.js';
|
|
6
|
+
type PageContextPageFiles = {
|
|
7
|
+
_pageFilesAll: PageFile[];
|
|
8
|
+
_pageConfigs: PageConfigRuntime[];
|
|
9
|
+
};
|
|
10
|
+
declare function loadPageFilesClientSide(pageId: string, pageContext: PageContextPageFiles): Promise<PageContextExports & {
|
|
6
11
|
_pageFilesLoaded: PageFile[];
|
|
7
12
|
}>;
|
|
8
13
|
declare function isErrorFetchingStaticAssets(err: unknown): boolean;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
export { loadPageFilesClientSide };
|
|
2
|
+
export { isErrorFetchingStaticAssets };
|
|
1
3
|
import { getPageFilesClientSide, getExports } from '../../shared/getPageFiles.js';
|
|
2
4
|
import { findPageConfig } from '../../shared/page-configs/findPageConfig.js';
|
|
3
5
|
import { loadConfigValues } from '../../shared/page-configs/loadConfigValues.js';
|
|
4
|
-
export { loadPageFilesClientSide };
|
|
5
|
-
export { isErrorFetchingStaticAssets };
|
|
6
6
|
const stamp = '__whileFetchingAssets';
|
|
7
|
-
async function loadPageFilesClientSide(
|
|
8
|
-
const pageFilesClientSide = getPageFilesClientSide(
|
|
9
|
-
const pageConfig = findPageConfig(
|
|
7
|
+
async function loadPageFilesClientSide(pageId, pageContext) {
|
|
8
|
+
const pageFilesClientSide = getPageFilesClientSide(pageContext._pageFilesAll, pageId);
|
|
9
|
+
const pageConfig = findPageConfig(pageContext._pageConfigs, pageId);
|
|
10
10
|
let pageConfigLoaded;
|
|
11
11
|
// @ts-ignore Since dist/cjs/client/ is never used, we can ignore this error.
|
|
12
12
|
const isDev = import.meta.env.DEV;
|
|
@@ -105,11 +105,11 @@ async function loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions) {
|
|
|
105
105
|
configName
|
|
106
106
|
};
|
|
107
107
|
{
|
|
108
|
-
// We don't have access to custom config definitions yet
|
|
109
|
-
// -
|
|
110
|
-
// -
|
|
108
|
+
// We don't have access to the custom config definitions defined by the user yet.
|
|
109
|
+
// - If `configDef` is `undefined` => we load the file +{configName}.js later.
|
|
110
|
+
// - We already need to load +meta.js here (to get the custom config definitions defined by the user)
|
|
111
111
|
const configDef = getConfigDefinitionOptional(configDefinitionsBuiltIn, configName);
|
|
112
|
-
if (configDef
|
|
112
|
+
if (configDef && isConfigEnv(configDef, configName)) {
|
|
113
113
|
await loadValueFile(interfaceFile, configName, userRootDir);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -139,6 +139,22 @@ async function loadValueFile(interfaceValueFile, configName, userRootDir) {
|
|
|
139
139
|
interfaceValueFile.configMap[configName_] = { configValue };
|
|
140
140
|
});
|
|
141
141
|
}
|
|
142
|
+
async function loadImportedFile(filePath, userRootDir, importedFilesLoaded) {
|
|
143
|
+
const f = filePath.filePathAbsoluteFilesystem;
|
|
144
|
+
if (!importedFilesLoaded[f]) {
|
|
145
|
+
importedFilesLoaded[f] = transpileAndExecuteFile(filePath, true, userRootDir).then((r) => r.fileExports);
|
|
146
|
+
}
|
|
147
|
+
const fileExports = await importedFilesLoaded[f];
|
|
148
|
+
return fileExports;
|
|
149
|
+
}
|
|
150
|
+
function isConfigEnv(configDef, configName) {
|
|
151
|
+
if (configDef.cumulative)
|
|
152
|
+
return true;
|
|
153
|
+
if (configDef.env === 'config-only')
|
|
154
|
+
return true;
|
|
155
|
+
// TODO: replace with proper `env: { config: boolean }` implementation
|
|
156
|
+
return configName === 'clientRouting';
|
|
157
|
+
}
|
|
142
158
|
function getInterfaceFileFromConfigFile(configFile, isConfigExtend) {
|
|
143
159
|
const { fileExports, filePath, extendsFilePaths } = configFile;
|
|
144
160
|
const interfaceFile = {
|
|
@@ -199,7 +215,8 @@ async function loadVikeConfig_withErrorHandling(userRootDir, outDirRoot, isDev,
|
|
|
199
215
|
}
|
|
200
216
|
async function loadVikeConfig(userRootDir, outDirRoot, isDev, extensions) {
|
|
201
217
|
const interfaceFilesByLocationId = await loadInterfaceFiles(userRootDir, outDirRoot, isDev, extensions);
|
|
202
|
-
const
|
|
218
|
+
const importedFilesLoaded = {};
|
|
219
|
+
const { globalVikeConfig, pageConfigGlobal } = await getGlobalConfigs(interfaceFilesByLocationId, userRootDir, importedFilesLoaded);
|
|
203
220
|
const pageConfigs = await Promise.all(Object.entries(interfaceFilesByLocationId)
|
|
204
221
|
.filter(([_pageId, interfaceFiles]) => isDefiningPage(interfaceFiles))
|
|
205
222
|
.map(async ([locationId]) => {
|
|
@@ -213,24 +230,24 @@ async function loadVikeConfig(userRootDir, outDirRoot, isDev, extensions) {
|
|
|
213
230
|
if (isGlobalConfig(configName))
|
|
214
231
|
return;
|
|
215
232
|
const configDef = getConfigDefinition(configDefinitionsRelevant, configName, interfaceFile.filePath.filePathToShowToUser);
|
|
216
|
-
if (configDef
|
|
233
|
+
if (!isConfigEnv(configDef, configName))
|
|
217
234
|
return;
|
|
218
235
|
const isAlreadyLoaded = interfacefileIsAlreaydLoaded(interfaceFile);
|
|
219
236
|
if (isAlreadyLoaded)
|
|
220
237
|
return;
|
|
221
|
-
// Value files
|
|
238
|
+
// Value files of built-in configs should have already been loaded at loadInterfaceFiles()
|
|
222
239
|
assert(!(configName in configDefinitionsBuiltIn));
|
|
223
240
|
await loadValueFile(interfaceFile, configName, userRootDir);
|
|
224
241
|
}));
|
|
225
242
|
const configValueSources = {};
|
|
226
|
-
objectEntries(configDefinitionsRelevant)
|
|
243
|
+
await Promise.all(objectEntries(configDefinitionsRelevant)
|
|
227
244
|
.filter(([configName]) => !isGlobalConfig(configName))
|
|
228
|
-
.
|
|
229
|
-
const sources = resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir);
|
|
230
|
-
if (
|
|
245
|
+
.map(async ([configName, configDef]) => {
|
|
246
|
+
const sources = await resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir, importedFilesLoaded);
|
|
247
|
+
if (sources.length === 0)
|
|
231
248
|
return;
|
|
232
249
|
configValueSources[configName] = sources;
|
|
233
|
-
});
|
|
250
|
+
}));
|
|
234
251
|
const { routeFilesystem, isErrorPage } = determineRouteFilesystem(locationId, configValueSources);
|
|
235
252
|
applyEffectsAll(configValueSources, configDefinitionsRelevant);
|
|
236
253
|
const configValuesComputed = getComputed(configValueSources, configDefinitionsRelevant);
|
|
@@ -280,7 +297,7 @@ function getInterfaceFileList(interfaceFilesByLocationId) {
|
|
|
280
297
|
});
|
|
281
298
|
return interfaceFiles;
|
|
282
299
|
}
|
|
283
|
-
function getGlobalConfigs(interfaceFilesByLocationId, userRootDir) {
|
|
300
|
+
async function getGlobalConfigs(interfaceFilesByLocationId, userRootDir, importedFilesLoaded) {
|
|
284
301
|
const locationIds = Object.keys(interfaceFilesByLocationId);
|
|
285
302
|
const interfaceFilesGlobal = Object.fromEntries(Object.entries(interfaceFilesByLocationId).filter(([locationId]) => {
|
|
286
303
|
return isGlobalLocation(locationId, locationIds);
|
|
@@ -316,9 +333,9 @@ function getGlobalConfigs(interfaceFilesByLocationId, userRootDir) {
|
|
|
316
333
|
const pageConfigGlobal = {
|
|
317
334
|
configValueSources: {}
|
|
318
335
|
};
|
|
319
|
-
objectEntries(configDefinitionsBuiltInGlobal).
|
|
320
|
-
const sources = resolveConfigValueSources(configName, configDef, interfaceFilesGlobal, userRootDir);
|
|
321
|
-
const configValueSource = sources
|
|
336
|
+
await Promise.all(objectEntries(configDefinitionsBuiltInGlobal).map(async ([configName, configDef]) => {
|
|
337
|
+
const sources = await resolveConfigValueSources(configName, configDef, interfaceFilesGlobal, userRootDir, importedFilesLoaded);
|
|
338
|
+
const configValueSource = sources[0];
|
|
322
339
|
if (!configValueSource)
|
|
323
340
|
return;
|
|
324
341
|
if (configName === 'onBeforeRoute' || configName === 'onPrerenderStart') {
|
|
@@ -333,23 +350,21 @@ function getGlobalConfigs(interfaceFilesByLocationId, userRootDir) {
|
|
|
333
350
|
assertWarning(false, `Being able to define config ${pc.cyan(configName)} in ${filePathToShowToUser} is experimental and will likely be removed. Define the config ${pc.cyan(configName)} in Vike's Vite plugin options instead.`, { onlyOnce: true });
|
|
334
351
|
globalVikeConfig[configName] = configValueSource.value;
|
|
335
352
|
}
|
|
336
|
-
});
|
|
353
|
+
}));
|
|
337
354
|
return { pageConfigGlobal, globalVikeConfig };
|
|
338
355
|
}
|
|
339
|
-
function resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir) {
|
|
340
|
-
|
|
356
|
+
async function resolveConfigValueSources(configName, configDef, interfaceFilesRelevant, userRootDir, importedFilesLoaded) {
|
|
357
|
+
const sourcesInfo = [];
|
|
341
358
|
// interfaceFilesRelevant is sorted by sortAfterInheritanceOrder()
|
|
342
359
|
for (const interfaceFiles of Object.values(interfaceFilesRelevant)) {
|
|
343
360
|
const interfaceFilesDefiningConfig = interfaceFiles.filter((interfaceFile) => interfaceFile.configMap[configName]);
|
|
344
361
|
if (interfaceFilesDefiningConfig.length === 0)
|
|
345
362
|
continue;
|
|
346
|
-
sources = sources ?? [];
|
|
347
363
|
const visited = new WeakSet();
|
|
348
364
|
const add = (interfaceFile) => {
|
|
349
365
|
assert(!visited.has(interfaceFile));
|
|
350
366
|
visited.add(interfaceFile);
|
|
351
|
-
|
|
352
|
-
sources.push(configValueSource);
|
|
367
|
+
sourcesInfo.push([configName, interfaceFile, configDef, userRootDir, importedFilesLoaded]);
|
|
353
368
|
};
|
|
354
369
|
// Main resolution logic
|
|
355
370
|
{
|
|
@@ -373,7 +388,7 @@ function resolveConfigValueSources(configName, configDef, interfaceFilesRelevant
|
|
|
373
388
|
if (interfaceFileWinner) {
|
|
374
389
|
const interfaceFilesOverriden = [...interfaceValueFiles, ...interfaceConfigFiles].filter((f) => f !== interfaceFileWinner);
|
|
375
390
|
// A user-land conflict of interfaceFiles with the same locationId means that the user has superfluously defined the config twice; the user should remove such redundancy making things unnecessarily ambiguous
|
|
376
|
-
warnOverridenConfigValues(interfaceFileWinner, interfaceFilesOverriden, configName
|
|
391
|
+
warnOverridenConfigValues(interfaceFileWinner, interfaceFilesOverriden, configName);
|
|
377
392
|
[interfaceFileWinner, ...interfaceFilesOverriden].forEach((interfaceFile) => {
|
|
378
393
|
add(interfaceFile);
|
|
379
394
|
});
|
|
@@ -398,7 +413,7 @@ function resolveConfigValueSources(configName, configDef, interfaceFilesRelevant
|
|
|
398
413
|
assert(visited.has(interfaceFile));
|
|
399
414
|
});
|
|
400
415
|
}
|
|
401
|
-
|
|
416
|
+
const sources = await Promise.all(sourcesInfo.map(async (args) => await getConfigValueSource(...args)));
|
|
402
417
|
return sources;
|
|
403
418
|
}
|
|
404
419
|
function makeOrderDeterministic(interfaceFile1, interfaceFile2) {
|
|
@@ -409,22 +424,17 @@ function makeOrderDeterministic(interfaceFile1, interfaceFile2) {
|
|
|
409
424
|
return filePathRelativeToUserRootDir.length;
|
|
410
425
|
})(interfaceFile1, interfaceFile2);
|
|
411
426
|
}
|
|
412
|
-
function warnOverridenConfigValues(interfaceFileWinner, interfaceFilesOverriden, configName
|
|
427
|
+
function warnOverridenConfigValues(interfaceFileWinner, interfaceFilesOverriden, configName) {
|
|
413
428
|
interfaceFilesOverriden.forEach((interfaceFileLoser) => {
|
|
414
|
-
const
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
const configLoser_DefinedAt = getConfigDefinedAtString('Config', configName, configValueSourceLoser_);
|
|
418
|
-
// prettier-ignore
|
|
419
|
-
const configWinnerDefinedAt = getConfigDefinedAtString('config', configName, configValueSourceWinner);
|
|
420
|
-
const errMsg = `${configLoser_DefinedAt} is overriden by another ${configWinnerDefinedAt}, remove one of the two`;
|
|
421
|
-
assertWarning(false, errMsg, { onlyOnce: false });
|
|
429
|
+
const loserFilePath = interfaceFileLoser.filePath.filePathToShowToUser;
|
|
430
|
+
const winnerFilePath = interfaceFileWinner.filePath.filePathToShowToUser;
|
|
431
|
+
assertWarning(false, `Config ${configName} defined at ${loserFilePath} is always overwritten by ${configName} defined at ${winnerFilePath}, remove the superfluous ${configName} value defined at ${interfaceFileLoser}`, { onlyOnce: false });
|
|
422
432
|
});
|
|
423
433
|
}
|
|
424
434
|
function isInterfaceFileUserLand(interfaceFile) {
|
|
425
435
|
return (interfaceFile.isConfigFile && !interfaceFile.isConfigExtend) || interfaceFile.isValueFile;
|
|
426
436
|
}
|
|
427
|
-
function getConfigValueSource(configName, interfaceFile, configDef, userRootDir) {
|
|
437
|
+
async function getConfigValueSource(configName, interfaceFile, configDef, userRootDir, importedFilesLoaded) {
|
|
428
438
|
const conf = interfaceFile.configMap[configName];
|
|
429
439
|
assert(conf);
|
|
430
440
|
const configEnv = configDef.env;
|
|
@@ -470,6 +480,18 @@ function getConfigValueSource(configName, interfaceFile, configDef, userRootDir)
|
|
|
470
480
|
valueIsImportedAtRuntime: true,
|
|
471
481
|
definedAt: import_
|
|
472
482
|
};
|
|
483
|
+
// Load config value
|
|
484
|
+
if (isConfigEnv(configDef, configName)) {
|
|
485
|
+
if (import_.filePathAbsoluteFilesystem) {
|
|
486
|
+
assert(hasProp(import_, 'filePathAbsoluteFilesystem', 'string')); // Help TS
|
|
487
|
+
const fileExports = await loadImportedFile(import_, userRootDir, importedFilesLoaded);
|
|
488
|
+
configValueSource.value = fileExports[import_.fileExportName];
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
const configDefinedAt = getConfigDefinedAtString('Config', configName, configValueSource);
|
|
492
|
+
assertUsage(!configDef.cumulative, `${configDefinedAt} cannot be defined over an aliased import`);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
473
495
|
return configValueSource;
|
|
474
496
|
}
|
|
475
497
|
else {
|
|
@@ -1109,12 +1131,8 @@ function mergeCumulative(configName, configValueSources) {
|
|
|
1109
1131
|
let configValueSourcePrevious = null;
|
|
1110
1132
|
configValueSources.forEach((configValueSource) => {
|
|
1111
1133
|
const configDefinedAt = getConfigDefinedAtString('Config', configName, configValueSource);
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
assertUsage('value' in configValueSource, `${configDefinedAt} is only allowed to be defined in a +config.h.js file. (Because the values of ${configNameColored} are cumulative.)`);
|
|
1115
|
-
/* This is more confusing than adding value. For example, this explanation shouldn't be shown for the passToClient config.
|
|
1116
|
-
const explanation = `(Because the values of ${configNameColored} are cumulative and therefore merged together.)` as const
|
|
1117
|
-
*/
|
|
1134
|
+
// We could, in principle, also support cumulative for values that aren't loaded at config-time but it isn't completely trivial to implement.
|
|
1135
|
+
assert('value' in configValueSource);
|
|
1118
1136
|
// Make sure configValueSource.value is serializable
|
|
1119
1137
|
getConfigValueSerialized(configValueSource.value, configName, getDefinedAt(configValueSource));
|
|
1120
1138
|
const assertNoMixing = (isSet) => {
|
|
@@ -113,6 +113,7 @@ function getConfigValueSerialized(value, configName, definedAt) {
|
|
|
113
113
|
serializationErrMsg = err.messageCore;
|
|
114
114
|
}
|
|
115
115
|
else {
|
|
116
|
+
// When a property getter throws an error
|
|
116
117
|
console.error('Serialization error:');
|
|
117
118
|
console.error(err);
|
|
118
119
|
serializationErrMsg = 'see serialization error printed above';
|
|
@@ -13,6 +13,7 @@ function previewConfig() {
|
|
|
13
13
|
apply: 'serve',
|
|
14
14
|
config(config) {
|
|
15
15
|
return {
|
|
16
|
+
appType: 'custom',
|
|
16
17
|
build: {
|
|
17
18
|
outDir: resolveOutDir(config)
|
|
18
19
|
}
|
|
@@ -23,6 +24,10 @@ function previewConfig() {
|
|
|
23
24
|
configVike = await getConfigVike(config);
|
|
24
25
|
},
|
|
25
26
|
configurePreviewServer(server) {
|
|
27
|
+
/* - Couldn't make `appType: 'mpa'` work as of npm:@brillout/vite@5.0.0-beta.14.0426910c
|
|
28
|
+
- This ugly hack to set appType for preview won't be need once https://github.com/vitejs/vite/pull/14855 is merged.
|
|
29
|
+
config.appType = 'mpa'
|
|
30
|
+
*/
|
|
26
31
|
markEnvAsPreview();
|
|
27
32
|
return () => {
|
|
28
33
|
assertDist();
|
|
@@ -5,7 +5,7 @@ export { prerenderForceExit };
|
|
|
5
5
|
import '../runtime/page-files/setup.js';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { route } from '../../shared/route/index.js';
|
|
8
|
-
import { assert, assertUsage, assertWarning, hasProp, projectInfo, objectAssign, isObjectWithKeys, isCallable, getOutDirs,
|
|
8
|
+
import { assert, assertUsage, assertWarning, hasProp, projectInfo, objectAssign, isObjectWithKeys, isCallable, getOutDirs, isPropertyGetter, assertPosixPath, urlToFile, executeHook, isPlainObject, setNodeEnvToProduction } from './utils.js';
|
|
9
9
|
import { pLimit } from '../../utils/pLimit.js';
|
|
10
10
|
import { prerenderPage, prerender404Page, getRenderContext, getPageContextInitEnhanced } from '../runtime/renderPage/renderPageAlreadyRouted.js';
|
|
11
11
|
import pc from '@brillout/picocolors';
|
|
@@ -244,7 +244,7 @@ async function handlePagesWithStaticRoutes(prerenderContext, renderContext, doNo
|
|
|
244
244
|
_providedByHook: null,
|
|
245
245
|
routeParams,
|
|
246
246
|
_pageId: pageId,
|
|
247
|
-
|
|
247
|
+
_debugRouteMatches: [
|
|
248
248
|
{
|
|
249
249
|
pageId,
|
|
250
250
|
routeType: pageRoute.routeType,
|
|
@@ -343,7 +343,7 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
|
|
|
343
343
|
enumerable: false,
|
|
344
344
|
configurable: true
|
|
345
345
|
});
|
|
346
|
-
assert(
|
|
346
|
+
assert(isPropertyGetter(pageContext, 'url'));
|
|
347
347
|
assert(pageContext.urlOriginal);
|
|
348
348
|
pageContext._urlOriginalBeforeHook = pageContext.urlOriginal;
|
|
349
349
|
});
|
|
@@ -382,7 +382,7 @@ async function callOnPrerenderStartHook(prerenderContext, renderContext) {
|
|
|
382
382
|
prerenderContext.pageContexts = result.prerenderContext.pageContexts;
|
|
383
383
|
prerenderContext.pageContexts.forEach((pageContext) => {
|
|
384
384
|
// TODO/v1-release: remove
|
|
385
|
-
if (!
|
|
385
|
+
if (pageContext.url && !isPropertyGetter(pageContext, 'url')) {
|
|
386
386
|
assertWarning(false, msgPrefix +
|
|
387
387
|
' provided pageContext.url but it should provide pageContext.urlOriginal instead, see https://vike.dev/migration/0.4.23', { onlyOnce: true });
|
|
388
388
|
pageContext.urlOriginal = pageContext.url;
|
|
@@ -407,10 +407,9 @@ async function routeAndPrerender(prerenderContext, htmlFiles, prerenderPageIds,
|
|
|
407
407
|
await Promise.all(prerenderContext.pageContexts.map((pageContext) => concurrencyLimit(async () => {
|
|
408
408
|
const { urlOriginal } = pageContext;
|
|
409
409
|
assert(urlOriginal);
|
|
410
|
-
const
|
|
411
|
-
assert(hasProp(
|
|
412
|
-
|
|
413
|
-
if (routeResult.pageContextAddendum._pageId === null) {
|
|
410
|
+
const pageContextFromRoute = await route(pageContext);
|
|
411
|
+
assert(hasProp(pageContextFromRoute, '_pageId', 'null') || hasProp(pageContextFromRoute, '_pageId', 'string'));
|
|
412
|
+
if (pageContextFromRoute._pageId === null) {
|
|
414
413
|
let hookName;
|
|
415
414
|
let hookFilePath;
|
|
416
415
|
if (pageContext._providedByHook) {
|
|
@@ -423,17 +422,17 @@ async function routeAndPrerender(prerenderContext, htmlFiles, prerenderPageIds,
|
|
|
423
422
|
}
|
|
424
423
|
if (hookName) {
|
|
425
424
|
assert(hookFilePath);
|
|
426
|
-
assertUsage(false, `The ${hookName}() hook defined by ${hookFilePath} returns a URL ${pc.cyan(urlOriginal)} that doesn't match any of your
|
|
425
|
+
assertUsage(false, `The ${hookName}() hook defined by ${hookFilePath} returns a URL ${pc.cyan(urlOriginal)} that doesn't match the route of any of your pages. Make sure that the URLs returned by ${hookName}() always match the route of a page.`);
|
|
427
426
|
}
|
|
428
427
|
else {
|
|
429
428
|
// `prerenderHookFile` is `null` when the URL was deduced by the Filesytem Routing of `.page.js` files. The `onBeforeRoute()` can override Filesystem Routing; it is therefore expected that the deduced URL may not match any page.
|
|
430
|
-
assert(
|
|
429
|
+
assert(pageContextFromRoute._routingProvidedByOnBeforeRouteHook);
|
|
431
430
|
// Abort since the URL doesn't correspond to any page
|
|
432
431
|
return;
|
|
433
432
|
}
|
|
434
433
|
}
|
|
435
|
-
assert(
|
|
436
|
-
objectAssign(pageContext,
|
|
434
|
+
assert(pageContextFromRoute._pageId);
|
|
435
|
+
objectAssign(pageContext, pageContextFromRoute);
|
|
437
436
|
const { _pageId: pageId } = pageContext;
|
|
438
437
|
objectAssign(pageContext, await loadPageFilesServerSide(pageContext));
|
|
439
438
|
let usesClientRouter;
|
|
@@ -5,7 +5,7 @@ export * from '../../utils/objectAssign.js';
|
|
|
5
5
|
export * from '../../utils/isObjectWithKeys.js';
|
|
6
6
|
export * from '../../utils/isCallable.js';
|
|
7
7
|
export * from '../../utils/getOutDirs.js';
|
|
8
|
-
export * from '../../utils/
|
|
8
|
+
export * from '../../utils/isPropertyGetter.js';
|
|
9
9
|
export * from '../../utils/filesystemPathHandling.js';
|
|
10
10
|
export * from '../../utils/urlToFile.js';
|
|
11
11
|
export * from '../../shared/hooks/executeHook.js';
|
|
@@ -7,7 +7,7 @@ export * from '../../utils/objectAssign.js';
|
|
|
7
7
|
export * from '../../utils/isObjectWithKeys.js';
|
|
8
8
|
export * from '../../utils/isCallable.js';
|
|
9
9
|
export * from '../../utils/getOutDirs.js';
|
|
10
|
-
export * from '../../utils/
|
|
10
|
+
export * from '../../utils/isPropertyGetter.js';
|
|
11
11
|
export * from '../../utils/filesystemPathHandling.js';
|
|
12
12
|
export * from '../../utils/urlToFile.js';
|
|
13
13
|
export * from '../../shared/hooks/executeHook.js';
|