vike 0.4.149 → 0.4.150-commit-d0822a3
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/index.js +0 -2
- package/dist/cjs/node/plugin/plugins/autoFullBuild.js +3 -2
- package/dist/cjs/node/plugin/plugins/buildConfig.js +17 -36
- package/dist/cjs/node/plugin/plugins/commonConfig/assertResolveAlias.js +3 -0
- package/dist/cjs/node/plugin/plugins/commonConfig.js +1 -1
- package/dist/cjs/node/plugin/plugins/config/resolveExtensions.js +1 -1
- package/dist/cjs/node/plugin/plugins/config/stemUtils.js +1 -1
- package/dist/cjs/node/plugin/plugins/devConfig/determineFsAllowList.js +1 -1
- package/dist/cjs/node/plugin/plugins/importBuild/getVikeManifest.js +38 -0
- package/dist/cjs/node/plugin/plugins/importBuild/index.js +57 -19
- package/dist/cjs/node/plugin/plugins/importUserCode/index.js +3 -1
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +7 -0
- package/dist/cjs/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +1 -1
- package/dist/cjs/node/plugin/utils.js +1 -0
- package/dist/cjs/node/runtime/html/serializePageContextClientSide.js +2 -1
- package/dist/cjs/node/runtime/html/stream.js +57 -17
- package/dist/cjs/node/runtime/index-deprecated.js +3 -2
- package/dist/cjs/node/runtime/index.js +3 -2
- package/dist/cjs/node/runtime/renderPage/executeOnBeforeRenderAndDataHooks.js +33 -0
- package/dist/cjs/node/runtime/renderPage/getHttpResponseBody.js +2 -2
- package/dist/cjs/node/runtime/renderPage/getPageAssets/retrieveAssetsDev.js +13 -5
- package/dist/cjs/node/runtime/renderPage/getPageAssets/sortPageAssetsForEarlyHintsHeader.js +6 -0
- package/dist/cjs/node/runtime/renderPage/getPageAssets.js +1 -1
- package/dist/cjs/node/runtime/renderPage/inferMediaType.js +38 -0
- package/dist/cjs/node/runtime/renderPage/renderPageAlreadyRouted.js +4 -4
- package/dist/cjs/shared/page-configs/assertExports.js +11 -4
- package/dist/cjs/shared/route/resolveRedirects.js +2 -10
- package/dist/cjs/shared/route/resolveUrlPathname.js +48 -0
- package/dist/cjs/utils/debug.js +29 -15
- package/dist/cjs/utils/getDependencyPackageJson.js +1 -1
- package/dist/cjs/utils/getFilePathAbsolute.js +1 -1
- package/dist/cjs/utils/getOutDirs.js +11 -1
- package/dist/cjs/utils/injectRollupInputs.js +29 -0
- package/dist/cjs/utils/isPlainObject.js +1 -1
- package/dist/cjs/utils/projectInfo.js +1 -1
- package/dist/cjs/utils/requireResolve.js +1 -1
- package/dist/esm/client/client-routing-runtime/getPageContextFromHooks.js +105 -66
- package/dist/esm/client/client-routing-runtime/renderPageClientSide.js +1 -1
- package/dist/esm/node/plugin/index.js +0 -2
- package/dist/esm/node/plugin/plugins/autoFullBuild.js +3 -2
- package/dist/esm/node/plugin/plugins/buildConfig.js +17 -36
- package/dist/esm/node/plugin/plugins/commonConfig/assertResolveAlias.js +3 -0
- package/dist/esm/node/plugin/plugins/commonConfig.js +1 -1
- package/dist/esm/node/plugin/plugins/config/resolveExtensions.js +1 -1
- package/dist/esm/node/plugin/plugins/config/stemUtils.js +1 -1
- package/dist/esm/node/plugin/plugins/devConfig/determineFsAllowList.js +1 -1
- package/dist/esm/node/plugin/plugins/importBuild/getVikeManifest.d.ts +5 -0
- package/dist/esm/node/plugin/plugins/importBuild/getVikeManifest.js +32 -0
- package/dist/esm/node/plugin/plugins/importBuild/index.js +59 -21
- package/dist/esm/node/plugin/plugins/importUserCode/index.js +3 -1
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/debug.d.ts +1 -1
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js +7 -0
- package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js +1 -1
- package/dist/esm/node/plugin/utils.d.ts +1 -0
- package/dist/esm/node/plugin/utils.js +1 -0
- package/dist/esm/node/runtime/html/serializePageContextClientSide.js +2 -1
- package/dist/esm/node/runtime/html/stream.js +57 -17
- package/dist/esm/node/runtime/index-deprecated.js +3 -2
- package/dist/esm/node/runtime/index.js +3 -2
- package/dist/esm/node/runtime/renderPage/{executeOnBeforeRenderHook.d.ts → executeOnBeforeRenderAndDataHooks.d.ts} +2 -2
- package/dist/esm/node/runtime/renderPage/executeOnBeforeRenderAndDataHooks.js +30 -0
- package/dist/esm/node/runtime/renderPage/getHttpResponseBody.js +2 -2
- package/dist/esm/node/runtime/renderPage/getPageAssets/retrieveAssetsDev.js +13 -5
- package/dist/esm/node/runtime/renderPage/getPageAssets/sortPageAssetsForEarlyHintsHeader.js +6 -0
- package/dist/esm/node/runtime/renderPage/getPageAssets.js +1 -1
- package/dist/esm/node/runtime/renderPage/inferMediaType.d.ts +2 -2
- package/dist/esm/node/runtime/renderPage/inferMediaType.js +38 -0
- package/dist/esm/node/runtime/renderPage/renderPageAlreadyRouted.js +4 -4
- package/dist/esm/shared/VikeNamespace.d.ts +2 -1
- package/dist/esm/shared/page-configs/Config.d.ts +22 -5
- package/dist/esm/shared/page-configs/assertExports.js +11 -4
- package/dist/esm/shared/route/resolveRedirects.js +2 -10
- package/dist/esm/shared/route/resolveUrlPathname.d.ts +12 -0
- package/dist/esm/shared/route/resolveUrlPathname.js +45 -0
- package/dist/esm/shared/types.d.ts +5 -0
- package/dist/esm/types/index.d.ts +1 -1
- package/dist/esm/utils/debug.d.ts +2 -2
- package/dist/esm/utils/debug.js +29 -15
- package/dist/esm/utils/debugGlob.d.ts +1 -1
- package/dist/esm/utils/getDependencyPackageJson.js +1 -1
- package/dist/esm/utils/getFilePathAbsolute.js +1 -1
- package/dist/esm/utils/getOutDirs.js +11 -1
- package/dist/esm/utils/injectRollupInputs.d.ts +7 -0
- package/dist/esm/utils/injectRollupInputs.js +26 -0
- package/dist/esm/utils/isPlainObject.js +1 -1
- package/dist/esm/utils/projectInfo.d.ts +2 -2
- package/dist/esm/utils/projectInfo.js +1 -1
- package/dist/esm/utils/requireResolve.js +1 -1
- package/package.json +10 -3
- package/dist/cjs/node/plugin/plugins/manifest.js +0 -59
- package/dist/cjs/node/runtime/renderPage/executeOnBeforeRenderHook.js +0 -23
- package/dist/esm/node/plugin/plugins/manifest.d.ts +0 -3
- package/dist/esm/node/plugin/plugins/manifest.js +0 -53
- package/dist/esm/node/runtime/renderPage/executeOnBeforeRenderHook.js +0 -20
|
@@ -36,6 +36,9 @@ const configDefinitionsBuiltIn = {
|
|
|
36
36
|
guard: {
|
|
37
37
|
env: { server: true, client: 'if-client-routing' }
|
|
38
38
|
},
|
|
39
|
+
data: {
|
|
40
|
+
env: { server: true }
|
|
41
|
+
},
|
|
39
42
|
iKnowThePerformanceRisksOfAsyncRouteFunctions: {
|
|
40
43
|
env: { server: true, client: 'if-client-routing', eager: true }
|
|
41
44
|
},
|
|
@@ -76,6 +79,10 @@ const configDefinitionsBuiltIn = {
|
|
|
76
79
|
env: { client: true },
|
|
77
80
|
_computed: (configValueSources) => !isConfigSet(configValueSources, 'onBeforeRender') ? null : getConfigEnv(configValueSources, 'onBeforeRender')
|
|
78
81
|
},
|
|
82
|
+
dataEnv: {
|
|
83
|
+
env: { client: true },
|
|
84
|
+
_computed: (configValueSources) => !isConfigSet(configValueSources, 'data') ? null : getConfigEnv(configValueSources, 'data')
|
|
85
|
+
},
|
|
79
86
|
hooksTimeout: {
|
|
80
87
|
env: { server: true, client: true }
|
|
81
88
|
}
|
package/dist/esm/node/plugin/plugins/importUserCode/v1-design/getVikeConfig/crawlPlusFiles.js
CHANGED
|
@@ -120,5 +120,5 @@ async function isUsingGit(userRootDir) {
|
|
|
120
120
|
async function runCmd(cmd, cwd) {
|
|
121
121
|
const res = await execA(cmd, { cwd });
|
|
122
122
|
assert(res.stderr === '');
|
|
123
|
-
return res.stdout.toString().
|
|
123
|
+
return res.stdout.toString().split('\n').filter(Boolean);
|
|
124
124
|
}
|
|
@@ -16,7 +16,8 @@ const PASS_TO_CLIENT = [
|
|
|
16
16
|
'_abortCaller',
|
|
17
17
|
*/
|
|
18
18
|
'_pageContextInitHasClientData',
|
|
19
|
-
'_pageId'
|
|
19
|
+
'_pageId',
|
|
20
|
+
'data' // for data() hook
|
|
20
21
|
];
|
|
21
22
|
const PASS_TO_CLIENT_ERROR_PAGE = ['pageProps', 'is404', '_isError'];
|
|
22
23
|
function serializePageContextClientSide(pageContext) {
|
|
@@ -205,7 +205,9 @@ function pipeToStreamWritableNode(htmlRender, writable) {
|
|
|
205
205
|
async function processStream(streamOriginal, { injectStringAtBegin, injectStringAtEnd, onErrorWhileStreaming, enableEagerStreaming }) {
|
|
206
206
|
const buffer = [];
|
|
207
207
|
let streamOriginalHasStartedEmitting = false;
|
|
208
|
-
let
|
|
208
|
+
let streamOriginalEnded = false;
|
|
209
|
+
let streamClosed = false;
|
|
210
|
+
let onEndWasCalled = false;
|
|
209
211
|
let isReadyToWrite = false;
|
|
210
212
|
let wrapperCreated = false;
|
|
211
213
|
let shouldFlushStream = false;
|
|
@@ -229,6 +231,14 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
|
|
|
229
231
|
writeStream(injectionBegin); // Adds injectionBegin to buffer
|
|
230
232
|
flushStream(); // Sets shouldFlushStream to true
|
|
231
233
|
}
|
|
234
|
+
// We call onStreamEvent() also when the stream ends in order to properly handle the situation when the stream didn't emit any data
|
|
235
|
+
const onStreamDataOrEnd = (cb) => {
|
|
236
|
+
assert(streamOriginalEnded === false);
|
|
237
|
+
streamOriginalHasStartedEmitting = true;
|
|
238
|
+
cb();
|
|
239
|
+
if (wrapperCreated)
|
|
240
|
+
resolvePromise();
|
|
241
|
+
};
|
|
232
242
|
const { streamWrapper, streamWrapperOperations } = await createStreamWrapper({
|
|
233
243
|
streamOriginal,
|
|
234
244
|
onReadyToWrite() {
|
|
@@ -246,19 +256,21 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
|
|
|
246
256
|
}
|
|
247
257
|
},
|
|
248
258
|
onData(chunk) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
if (wrapperCreated)
|
|
253
|
-
resolvePromise();
|
|
259
|
+
onStreamDataOrEnd(() => {
|
|
260
|
+
writeStream(chunk);
|
|
261
|
+
});
|
|
254
262
|
},
|
|
255
|
-
async onEnd(
|
|
263
|
+
async onEnd(
|
|
264
|
+
// Should we use this `isCancel`? Maybe we can skip `injectStringAtEnd()`?
|
|
265
|
+
isCancel) {
|
|
256
266
|
try {
|
|
267
|
+
assert(!onEndWasCalled);
|
|
268
|
+
onEndWasCalled = true;
|
|
257
269
|
debug('stream end');
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
270
|
+
// We call onStreamEvent() also here in case the stream didn't emit any data
|
|
271
|
+
onStreamDataOrEnd(() => {
|
|
272
|
+
streamOriginalEnded = true;
|
|
273
|
+
});
|
|
262
274
|
if (injectStringAtEnd) {
|
|
263
275
|
const injectEnd = await injectStringAtEnd();
|
|
264
276
|
writeStream(injectEnd);
|
|
@@ -266,10 +278,12 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
|
|
|
266
278
|
await promiseReadyToWrite; // E.g. if the user calls the pipe wrapper after the original writable has ended
|
|
267
279
|
assert(isReady());
|
|
268
280
|
flushBuffer();
|
|
281
|
+
streamClosed = true;
|
|
269
282
|
debug('stream ended');
|
|
270
283
|
}
|
|
271
284
|
catch (err) {
|
|
272
|
-
//
|
|
285
|
+
// Ideally, we should catch and gracefully handle user land errors, as any error thrown here kills the server. (I assume that the fact it kills the server is a Node.js bug?)
|
|
286
|
+
// Show "[vike][Bug] You stumbled upon a bug in Vike's source code" to user while printing original error
|
|
273
287
|
if (!isBug(err)) {
|
|
274
288
|
console.error(err);
|
|
275
289
|
assert(false);
|
|
@@ -293,6 +307,7 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
|
|
|
293
307
|
function flushBuffer() {
|
|
294
308
|
if (!isReady())
|
|
295
309
|
return;
|
|
310
|
+
assert(!streamClosed);
|
|
296
311
|
buffer.forEach((chunk) => {
|
|
297
312
|
streamWrapperOperations.writeChunk(chunk);
|
|
298
313
|
});
|
|
@@ -489,6 +504,17 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
489
504
|
if (isStreamReadableWeb(streamOriginal)) {
|
|
490
505
|
debug('onRenderHtml() hook returned Web Readable');
|
|
491
506
|
const readableOriginal = streamOriginal;
|
|
507
|
+
let controllerProxyIsClosed = false;
|
|
508
|
+
let isClosed = false;
|
|
509
|
+
let isCancel = false;
|
|
510
|
+
const closeStream = async () => {
|
|
511
|
+
if (isClosed)
|
|
512
|
+
return;
|
|
513
|
+
isClosed = true;
|
|
514
|
+
await onEnd(isCancel);
|
|
515
|
+
controllerProxy.close();
|
|
516
|
+
controllerProxyIsClosed = true;
|
|
517
|
+
};
|
|
492
518
|
let controllerProxy;
|
|
493
519
|
assertReadableStreamConstructor();
|
|
494
520
|
const readableProxy = new ReadableStream({
|
|
@@ -502,16 +528,30 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
502
528
|
controllerProxy.close();
|
|
503
529
|
},
|
|
504
530
|
async onEnd() {
|
|
505
|
-
await
|
|
506
|
-
controllerProxy.close();
|
|
531
|
+
await closeStream();
|
|
507
532
|
}
|
|
508
533
|
});
|
|
534
|
+
},
|
|
535
|
+
async cancel(...args) {
|
|
536
|
+
isCancel = true;
|
|
537
|
+
await readableOriginal.cancel(...args);
|
|
538
|
+
// If readableOriginal has implemented readableOriginal.cancel() then the onEnd() callback and therfore closeStream() may already have been called at this point
|
|
539
|
+
await closeStream();
|
|
509
540
|
}
|
|
510
541
|
});
|
|
511
542
|
const writeChunk = (chunk) => {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
543
|
+
if (
|
|
544
|
+
// If readableOriginal doesn't implement readableOriginal.cancel() then it may still emit data after we close the stream. We therefore need to check whether we closed `controllerProxy`.
|
|
545
|
+
!controllerProxyIsClosed) {
|
|
546
|
+
controllerProxy.enqueue(encodeForWebStream(chunk));
|
|
547
|
+
if (debug.isEnabled) {
|
|
548
|
+
debug('data written (Web Readable)', String(chunk));
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
if (debug.isEnabled) {
|
|
553
|
+
debug('data emitted but not written (Web Readable)', String(chunk));
|
|
554
|
+
}
|
|
515
555
|
}
|
|
516
556
|
};
|
|
517
557
|
// Readables don't have the notion of flushing
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// TODO/v1-release: replace this with:
|
|
2
2
|
// assertUsage(false, "`import { something } from 'vike'` doesn't exist: instead import from 'vike/server', 'vike/client', 'vike/plugin', ...")
|
|
3
|
+
import { isBrowser } from '../../utils/isBrowser.js';
|
|
4
|
+
import { assertUsage } from '../../utils/assert.js';
|
|
5
|
+
assertUsage(!isBrowser(), "It's forbidden to `import { something } from 'vike'` on the client-side: the module 'vike' is a server-only module.", { showStackTrace: true });
|
|
3
6
|
export * from './index-common.js';
|
|
4
7
|
export * from '../../types/index-dreprecated.js';
|
|
5
8
|
import { assertWarning } from './utils.js';
|
|
@@ -36,5 +39,3 @@ assertWarning(false, [
|
|
|
36
39
|
pc.green(" import type { something } from 'vike/types'"),
|
|
37
40
|
"Make sure to import renderPage(), escapeInject, html, dangerouslySkipEscape(), pipeWebStream(), pipeNodeStream(), pipeStream(), stampPipe() from 'vike/server'. (Or inspect the error stack below to find the import causing this warning.)"
|
|
38
41
|
].join('\n'), { showStackTrace: true, onlyOnce: true });
|
|
39
|
-
import { isBrowser, assertUsage } from './utils.js';
|
|
40
|
-
assertUsage(!isBrowser(), "It's forbidden to `import { something } from 'vike'` in code loaded in the browser: the module 'vike' is a server-only module.", { showStackTrace: true });
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isBrowser } from '../../utils/isBrowser.js';
|
|
2
|
+
import { assertUsage } from '../../utils/assert.js';
|
|
3
|
+
assertUsage(!isBrowser(), "It's forbidden to `import { something } from 'vike/server'` on the client-side: the module 'vike/server' is a server-only module.", { showStackTrace: true });
|
|
1
4
|
export * from './index-common.js';
|
|
2
|
-
import { isBrowser, assertUsage } from './utils.js';
|
|
3
|
-
assertUsage(!isBrowser(), "It's forbidden to `import { something } from 'vike/server'` in code loaded on the client-side: the module 'vike/server' is a server-only module.", { showStackTrace: true });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { executeOnBeforeRenderAndDataHooks };
|
|
2
2
|
import { type PageContextExports } from '../../../shared/getPageFiles.js';
|
|
3
3
|
import { type PageContextForUserConsumptionServerSide } from './preparePageContextForUserConsumptionServerSide.js';
|
|
4
|
-
declare function
|
|
4
|
+
declare function executeOnBeforeRenderAndDataHooks(pageContext: {
|
|
5
5
|
_pageId: string;
|
|
6
6
|
_pageContextAlreadyProvidedByOnPrerenderHook?: true;
|
|
7
7
|
} & PageContextExports & PageContextForUserConsumptionServerSide): Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export { executeOnBeforeRenderAndDataHooks };
|
|
2
|
+
import { getHook } from '../../../shared/hooks/getHook.js';
|
|
3
|
+
import { preparePageContextForUserConsumptionServerSide } from './preparePageContextForUserConsumptionServerSide.js';
|
|
4
|
+
import { executeHook } from '../utils.js';
|
|
5
|
+
import { assertOnBeforeRenderHookReturn } from '../../../shared/assertOnBeforeRenderHookReturn.js';
|
|
6
|
+
async function executeOnBeforeRenderAndDataHooks(pageContext) {
|
|
7
|
+
if (pageContext._pageContextAlreadyProvidedByOnPrerenderHook) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const dataHook = getHook(pageContext, 'data');
|
|
11
|
+
const onBeforeRenderHook = getHook(pageContext, 'onBeforeRender');
|
|
12
|
+
if (!dataHook && !onBeforeRenderHook) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
preparePageContextForUserConsumptionServerSide(pageContext);
|
|
16
|
+
if (dataHook) {
|
|
17
|
+
const hookResult = await executeHook(() => dataHook.hookFn(pageContext), dataHook);
|
|
18
|
+
// Note: hookResult can be anything (e.g. an object) and is to be assigned to pageContext.data
|
|
19
|
+
const pageContextFromHook = {
|
|
20
|
+
data: hookResult
|
|
21
|
+
};
|
|
22
|
+
Object.assign(pageContext, pageContextFromHook);
|
|
23
|
+
}
|
|
24
|
+
if (onBeforeRenderHook) {
|
|
25
|
+
const hookResult = await executeHook(() => onBeforeRenderHook.hookFn(pageContext), onBeforeRenderHook);
|
|
26
|
+
assertOnBeforeRenderHookReturn(hookResult, onBeforeRenderHook.hookFilePath);
|
|
27
|
+
const pageContextFromHook = hookResult?.pageContext;
|
|
28
|
+
Object.assign(pageContext, pageContextFromHook);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -71,7 +71,7 @@ function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
|
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
else {
|
|
74
|
-
assert(
|
|
74
|
+
assert(isStreamReadableNode(htmlRender) || isStreamPipeNode(htmlRender));
|
|
75
75
|
assertUsage(false, getErrMsgMixingStreamTypes('Web Writable'));
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -81,7 +81,7 @@ function getHttpResponseBodyStreamHandlers(htmlRender, renderHook) {
|
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
83
|
else {
|
|
84
|
-
assert(
|
|
84
|
+
assert(isStreamReadableWeb(htmlRender) || isStreamPipeWeb(htmlRender));
|
|
85
85
|
assertUsage(false, getErrMsgMixingStreamTypes('Node.js Writable'));
|
|
86
86
|
}
|
|
87
87
|
}
|
|
@@ -37,13 +37,21 @@ function collectCss(mod, styleUrls, visitedModules, importer) {
|
|
|
37
37
|
if (mod.url.startsWith('/')) {
|
|
38
38
|
styleUrls.add(mod.url);
|
|
39
39
|
}
|
|
40
|
+
else if (mod.url.startsWith('\0')) {
|
|
41
|
+
// Virtual modules
|
|
42
|
+
// - https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention
|
|
43
|
+
// - I believe some Vite plugins don't respect the \0 virtual module convention. What should we do then?
|
|
44
|
+
// - https://github.com/vikejs/vike/issues/1327
|
|
45
|
+
// - https://github.com/vikejs/vike/commit/3f7b9916dddc84e29e2c20d2b0df7211b6f1acbd
|
|
46
|
+
styleUrls.add(`/@id/${mod.url.substring(1)}`);
|
|
47
|
+
}
|
|
40
48
|
else {
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
// - Reproduction: https://github.com/vikejs/vike/issues/479
|
|
44
|
-
// - Possible workaround: `<script>import 'virtual-module.css'</script>`
|
|
45
|
-
// logModule(mod)
|
|
49
|
+
// Is this useful? Maybe for virtual modules that don't respect the \0 virtual module convention?
|
|
50
|
+
styleUrls.add(`/@id/${mod.url}`);
|
|
46
51
|
}
|
|
52
|
+
/* Debug:
|
|
53
|
+
logModule(mod)
|
|
54
|
+
//*/
|
|
47
55
|
}
|
|
48
56
|
mod.importedModules.forEach((dep) => {
|
|
49
57
|
collectCss(dep, styleUrls, visitedModules, mod);
|
|
@@ -20,6 +20,12 @@ function sortPageAssetsForEarlyHintsHeader(pageAssets) {
|
|
|
20
20
|
if (assetType === 'image')
|
|
21
21
|
return priority;
|
|
22
22
|
priority--;
|
|
23
|
+
if (assetType === 'video')
|
|
24
|
+
return priority;
|
|
25
|
+
priority--;
|
|
26
|
+
if (assetType === 'audio')
|
|
27
|
+
return priority;
|
|
28
|
+
priority--;
|
|
23
29
|
// Others
|
|
24
30
|
if (assetType !== 'script')
|
|
25
31
|
return priority;
|
|
@@ -82,7 +82,7 @@ async function resolveClientEntriesDev(clientEntry, viteDevServer, configVike) {
|
|
|
82
82
|
const { createRequire } = (await import_('module')).default;
|
|
83
83
|
const { dirname } = (await import_('path')).default;
|
|
84
84
|
const { fileURLToPath } = (await import_('url')).default;
|
|
85
|
-
// @ts-ignore
|
|
85
|
+
// @ts-ignore Shimmed by dist-cjs-fixup.js for CJS build.
|
|
86
86
|
const importMetaUrl = import.meta.url;
|
|
87
87
|
const require_ = createRequire(importMetaUrl);
|
|
88
88
|
const __dirname_ = dirname(fileURLToPath(importMetaUrl));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { inferMediaType };
|
|
2
2
|
export type { MediaType };
|
|
3
3
|
type MediaType = null | {
|
|
4
|
-
assetType: 'image' | 'script' | 'font' | 'style';
|
|
5
|
-
mediaType: 'text/javascript' | 'text/css' | 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif' | 'image/svg+xml' | 'font/ttf' | 'font/woff' | 'font/woff2';
|
|
4
|
+
assetType: 'image' | 'script' | 'font' | 'style' | 'audio' | 'video' | 'document' | 'fetch' | 'track' | 'worker' | 'embed' | 'object';
|
|
5
|
+
mediaType: 'text/javascript' | 'text/css' | 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif' | 'image/svg+xml' | 'font/ttf' | 'font/woff' | 'font/woff2' | 'video/mp4' | 'video/webm' | 'video/ogg' | 'video/mpeg' | 'video/x-msvideo' | 'video/quicktime' | 'audio/mpeg' | 'audio/wav' | 'audio/ogg' | 'audio/aac' | 'audio/midi' | 'audio/flac';
|
|
6
6
|
};
|
|
7
7
|
declare function inferMediaType(href: string): MediaType;
|
|
@@ -34,5 +34,43 @@ function inferMediaType(href) {
|
|
|
34
34
|
if (href.endsWith('.woff2')) {
|
|
35
35
|
return { assetType: 'font', mediaType: 'font/woff2' };
|
|
36
36
|
}
|
|
37
|
+
// Videos
|
|
38
|
+
if (href.endsWith('.mp4')) {
|
|
39
|
+
return { assetType: 'video', mediaType: 'video/mp4' };
|
|
40
|
+
}
|
|
41
|
+
if (href.endsWith('.webm')) {
|
|
42
|
+
return { assetType: 'video', mediaType: 'video/webm' };
|
|
43
|
+
}
|
|
44
|
+
if (href.endsWith('.ogv')) {
|
|
45
|
+
return { assetType: 'video', mediaType: 'video/ogg' };
|
|
46
|
+
}
|
|
47
|
+
if (href.endsWith('.mpeg') || href.endsWith('.mpg')) {
|
|
48
|
+
return { assetType: 'video', mediaType: 'video/mpeg' };
|
|
49
|
+
}
|
|
50
|
+
if (href.endsWith('.avi')) {
|
|
51
|
+
return { assetType: 'video', mediaType: 'video/x-msvideo' };
|
|
52
|
+
}
|
|
53
|
+
if (href.endsWith('.mov') || href.endsWith('.qt')) {
|
|
54
|
+
return { assetType: 'video', mediaType: 'video/quicktime' };
|
|
55
|
+
}
|
|
56
|
+
// Audios
|
|
57
|
+
if (href.endsWith('.mp3')) {
|
|
58
|
+
return { assetType: 'audio', mediaType: 'audio/mpeg' };
|
|
59
|
+
}
|
|
60
|
+
if (href.endsWith('.wav')) {
|
|
61
|
+
return { assetType: 'audio', mediaType: 'audio/wav' };
|
|
62
|
+
}
|
|
63
|
+
if (href.endsWith('.ogg')) {
|
|
64
|
+
return { assetType: 'audio', mediaType: 'audio/ogg' };
|
|
65
|
+
}
|
|
66
|
+
if (href.endsWith('.m4a')) {
|
|
67
|
+
return { assetType: 'audio', mediaType: 'audio/aac' };
|
|
68
|
+
}
|
|
69
|
+
if (href.endsWith('midi') || href.endsWith('.mid')) {
|
|
70
|
+
return { assetType: 'audio', mediaType: 'audio/midi' };
|
|
71
|
+
}
|
|
72
|
+
if (href.endsWith('.flac')) {
|
|
73
|
+
return { assetType: 'audio', mediaType: 'audio/flac' };
|
|
74
|
+
}
|
|
37
75
|
return null;
|
|
38
76
|
}
|
|
@@ -13,7 +13,7 @@ import { getGlobalContext } from '../globalContext.js';
|
|
|
13
13
|
import { createHttpResponseObject, createHttpResponsePageContextJson } from './createHttpResponseObject.js';
|
|
14
14
|
import { loadPageFilesServerSide } from './loadPageFilesServerSide.js';
|
|
15
15
|
import { executeOnRenderHtmlHook } from './executeOnRenderHtmlHook.js';
|
|
16
|
-
import {
|
|
16
|
+
import { executeOnBeforeRenderAndDataHooks } from './executeOnBeforeRenderAndDataHooks.js';
|
|
17
17
|
import { logRuntimeError } from './loggerRuntime.js';
|
|
18
18
|
import { isNewError } from './isNewError.js';
|
|
19
19
|
import { preparePageContextForUserConsumptionServerSide } from './preparePageContextForUserConsumptionServerSide.js';
|
|
@@ -33,11 +33,11 @@ async function renderPageAlreadyRouted(pageContext) {
|
|
|
33
33
|
await executeGuardHook(pageContext, (pageContext) => preparePageContextForUserConsumptionServerSide(pageContext));
|
|
34
34
|
}
|
|
35
35
|
if (!isError) {
|
|
36
|
-
await
|
|
36
|
+
await executeOnBeforeRenderAndDataHooks(pageContext);
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
39
39
|
try {
|
|
40
|
-
await
|
|
40
|
+
await executeOnBeforeRenderAndDataHooks(pageContext);
|
|
41
41
|
}
|
|
42
42
|
catch (err) {
|
|
43
43
|
if (isNewError(err, pageContext.errorWhileRendering)) {
|
|
@@ -75,7 +75,7 @@ async function prerenderPage(pageContext) {
|
|
|
75
75
|
* - It isn't trivial to implement, as it requires to duplicate / factor out the isAbortError() handling
|
|
76
76
|
await executeGuardHook(pageContext, (pageContext) => preparePageContextForUserConsumptionServerSide(pageContext))
|
|
77
77
|
*/
|
|
78
|
-
await
|
|
78
|
+
await executeOnBeforeRenderAndDataHooks(pageContext);
|
|
79
79
|
const { htmlRender, renderHook } = await executeOnRenderHtmlHook(pageContext);
|
|
80
80
|
assertUsage(htmlRender !== null, `Cannot pre-render ${pc.cyan(pageContext.urlOriginal)} because the ${renderHook.hookName}() hook defined by ${renderHook.hookFilePath} didn't return an HTML string.`);
|
|
81
81
|
assert(pageContext.isClientSideNavigation === false);
|
|
@@ -15,9 +15,10 @@ declare global {
|
|
|
15
15
|
/** Extend and/or refine the `PageContext` type (`import type { PageContext } from 'vike/types'`).
|
|
16
16
|
*
|
|
17
17
|
* For example:
|
|
18
|
-
* - You can define the type of fetched data, e.g. `PageContext['movies']`.
|
|
19
18
|
* - You can refine the type of `PageContext['Page']`.
|
|
19
|
+
* - You can define the type of custom `pageContext` values such as `pageContext.user`, see https://vike.dev/pageContext#custom
|
|
20
20
|
*
|
|
21
|
+
* https://vike.dev/pageContext#typescript
|
|
21
22
|
*/
|
|
22
23
|
interface PageContext {
|
|
23
24
|
}
|
|
@@ -5,6 +5,8 @@ export type { ConfigMeta };
|
|
|
5
5
|
export type { HookName };
|
|
6
6
|
export type { HookNamePage };
|
|
7
7
|
export type { HookNameGlobal };
|
|
8
|
+
export type { DataAsync };
|
|
9
|
+
export type { DataSync };
|
|
8
10
|
export type { GuardAsync };
|
|
9
11
|
export type { GuardSync };
|
|
10
12
|
export type { OnBeforePrerenderStartAsync };
|
|
@@ -35,11 +37,21 @@ import type { Vike, VikePackages } from '../VikeNamespace.js';
|
|
|
35
37
|
import type { HooksTimeoutProvidedByUser } from '../hooks/getHook.js';
|
|
36
38
|
import type { PageContextClient, PageContextServer } from '../types.js';
|
|
37
39
|
type HookName = HookNamePage | HookNameGlobal | HookNameOldDesign;
|
|
38
|
-
type HookNamePage = 'onHydrationEnd' | 'onBeforePrerenderStart' | 'onBeforeRender' | 'onPageTransitionStart' | 'onPageTransitionEnd' | 'onRenderHtml' | 'onRenderClient' | 'guard';
|
|
40
|
+
type HookNamePage = 'onHydrationEnd' | 'onBeforePrerenderStart' | 'onBeforeRender' | 'onPageTransitionStart' | 'onPageTransitionEnd' | 'onRenderHtml' | 'onRenderClient' | 'guard' | 'data';
|
|
39
41
|
type HookNameGlobal = 'onBeforePrerender' | 'onBeforeRoute' | 'onPrerenderStart';
|
|
40
42
|
type HookNameOldDesign = 'render' | 'prerender';
|
|
41
|
-
type ConfigNameBuiltIn = Exclude<keyof Config, keyof ConfigVikeUserProvided | 'onBeforeRoute' | 'onPrerenderStart'> | 'prerender' | 'isClientSideRenderable' | 'onBeforeRenderEnv' | 'hooksTimeout';
|
|
43
|
+
type ConfigNameBuiltIn = Exclude<keyof Config, keyof ConfigVikeUserProvided | 'onBeforeRoute' | 'onPrerenderStart'> | 'prerender' | 'isClientSideRenderable' | 'onBeforeRenderEnv' | 'dataEnv' | 'hooksTimeout';
|
|
42
44
|
type Config = ConfigBuiltIn & Vike.Config & (VikePackages.ConfigVikeReact | VikePackages.ConfigVikeVue | VikePackages.ConfigVikeSolid | VikePackages.ConfigVikeSvelte);
|
|
45
|
+
/** Hook for fetching data.
|
|
46
|
+
*
|
|
47
|
+
* https://vike.dev/data
|
|
48
|
+
*/
|
|
49
|
+
type DataAsync<Data> = (pageContext: PageContextServer) => Promise<Data>;
|
|
50
|
+
/** Hook for fetching data.
|
|
51
|
+
*
|
|
52
|
+
* https://vike.dev/data
|
|
53
|
+
*/
|
|
54
|
+
type DataSync<Data> = (pageContext: PageContextServer) => Data;
|
|
43
55
|
/** Protect page(s), e.g. forbid unauthorized access.
|
|
44
56
|
*
|
|
45
57
|
* https://vike.dev/guard
|
|
@@ -66,14 +78,14 @@ type OnBeforePrerenderStartSync = () => (string | {
|
|
|
66
78
|
url: string;
|
|
67
79
|
pageContext: Partial<Vike.PageContext>;
|
|
68
80
|
})[];
|
|
69
|
-
/** Hook called before the page is rendered
|
|
81
|
+
/** Hook called before the page is rendered.
|
|
70
82
|
*
|
|
71
83
|
* https://vike.dev/onBeforeRender
|
|
72
84
|
*/
|
|
73
85
|
type OnBeforeRenderAsync = (pageContext: PageContextServer) => Promise<{
|
|
74
86
|
pageContext: Partial<Vike.PageContext>;
|
|
75
87
|
} | void>;
|
|
76
|
-
/** Hook called before the page is rendered
|
|
88
|
+
/** Hook called before the page is rendered.
|
|
77
89
|
*
|
|
78
90
|
* https://vike.dev/onBeforeRender
|
|
79
91
|
*/
|
|
@@ -234,11 +246,16 @@ type ConfigBuiltIn = {
|
|
|
234
246
|
* https://vike.dev/extends
|
|
235
247
|
*/
|
|
236
248
|
extends?: Config | Config[] | ImportString | ImportString[];
|
|
237
|
-
/** Hook called before the page is rendered
|
|
249
|
+
/** Hook called before the page is rendered.
|
|
238
250
|
*
|
|
239
251
|
* https://vike.dev/onBeforeRender
|
|
240
252
|
*/
|
|
241
253
|
onBeforeRender?: OnBeforeRenderAsync | OnBeforeRenderSync | ImportString | null;
|
|
254
|
+
/** Hook for fetching data.
|
|
255
|
+
*
|
|
256
|
+
* https://vike.dev/data
|
|
257
|
+
*/
|
|
258
|
+
data?: DataAsync<unknown> | DataSync<unknown> | ImportString | null;
|
|
242
259
|
/** Determines what pageContext properties are sent to the client-side.
|
|
243
260
|
*
|
|
244
261
|
* https://vike.dev/passToClient
|
|
@@ -28,13 +28,20 @@ function assertExports(fileExports, filePathToShowToUser, configName) {
|
|
|
28
28
|
if (exportsRelevant.length === 1) {
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const exportDefault = pc.cyan('export default');
|
|
32
|
+
const exportConfigName = pc.cyan(`export { ${configName} }`);
|
|
33
|
+
if (exportsRelevant.length === 0) {
|
|
34
|
+
let errMsg = `${filePathToShowToUser} doesn't export any value, but it should have a ${exportDefault}`;
|
|
34
35
|
if (configName)
|
|
35
|
-
errMsg += ` or ${
|
|
36
|
+
errMsg += ` or ${exportConfigName}`;
|
|
36
37
|
assertUsage(false, errMsg);
|
|
37
38
|
}
|
|
39
|
+
else {
|
|
40
|
+
assert(exportsRelevant.length === 2);
|
|
41
|
+
assertWarning(false, `${filePathToShowToUser} remove ${exportConfigName} or ${exportDefault}`, {
|
|
42
|
+
onlyOnce: true
|
|
43
|
+
});
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
46
|
else {
|
|
40
47
|
// !configName => isConfigFile
|
|
@@ -4,6 +4,7 @@ export { resolveRouteStringRedirect };
|
|
|
4
4
|
import { assertIsNotBrowser } from '../../utils/assertIsNotBrowser.js';
|
|
5
5
|
import { isUriWithProtocol } from '../../utils/parseUrl-extras.js';
|
|
6
6
|
import { assert, assertUsage } from '../utils.js';
|
|
7
|
+
import { resolveUrlPathname } from './resolveUrlPathname.js';
|
|
7
8
|
import { assertRouteString, resolveRouteString } from './resolveRouteString.js';
|
|
8
9
|
import pc from '@brillout/picocolors';
|
|
9
10
|
assertIsNotBrowser(); // Don't bloat the client
|
|
@@ -27,16 +28,7 @@ function resolveRouteStringRedirect(urlSource, urlTarget, urlPathname) {
|
|
|
27
28
|
const match = resolveRouteString(urlSource, urlPathname);
|
|
28
29
|
if (!match)
|
|
29
30
|
return null;
|
|
30
|
-
|
|
31
|
-
Object.entries(match.routeParams).forEach(([key, val]) => {
|
|
32
|
-
if (key !== '*') {
|
|
33
|
-
key = `@${key}`;
|
|
34
|
-
}
|
|
35
|
-
urlResolved = urlResolved.replaceAll(key, val);
|
|
36
|
-
});
|
|
37
|
-
if (!urlResolved.startsWith('mailto:')) {
|
|
38
|
-
assertUsage(!urlResolved.includes('@'), 'URL should not contain "@" unless it is a mailto link.');
|
|
39
|
-
}
|
|
31
|
+
const urlResolved = resolveUrlPathname(urlTarget, match.routeParams);
|
|
40
32
|
if (urlResolved === urlPathname)
|
|
41
33
|
return null;
|
|
42
34
|
assert(urlResolved.startsWith('/') || isUriWithProtocol(urlResolved));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { resolveUrlPathname };
|
|
2
|
+
/** Given a `routeString` and `routeParams`, resolve `urlPathname`.
|
|
3
|
+
*
|
|
4
|
+
* Basically, the correct implementation of following:
|
|
5
|
+
* ```js
|
|
6
|
+
* let urlPathname = routeString
|
|
7
|
+
* Object.entries(routeParams).forEach(([key, val]) => {
|
|
8
|
+
* urlPathname = urlPathname.replaceAll(key, val)
|
|
9
|
+
* })
|
|
10
|
+
* ```
|
|
11
|
+
*/
|
|
12
|
+
declare function resolveUrlPathname(routeString: string, routeParams: Record<string, string>): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export { resolveUrlPathname };
|
|
2
|
+
import { assertIsNotBrowser } from '../../utils/assertIsNotBrowser.js';
|
|
3
|
+
import { assert, assertUsage } from '../utils.js';
|
|
4
|
+
assertIsNotBrowser(); // Don't bloat the client
|
|
5
|
+
/** Given a `routeString` and `routeParams`, resolve `urlPathname`.
|
|
6
|
+
*
|
|
7
|
+
* Basically, the correct implementation of following:
|
|
8
|
+
* ```js
|
|
9
|
+
* let urlPathname = routeString
|
|
10
|
+
* Object.entries(routeParams).forEach(([key, val]) => {
|
|
11
|
+
* urlPathname = urlPathname.replaceAll(key, val)
|
|
12
|
+
* })
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
function resolveUrlPathname(routeString, routeParams) {
|
|
16
|
+
let parts = [{ val: routeString, type: 'ROUTE_STRING' }];
|
|
17
|
+
Object.entries(routeParams).forEach(([key, val]) => {
|
|
18
|
+
if (key.startsWith('*')) {
|
|
19
|
+
assert(key === '*' || /\d+/.test(key.slice(1)));
|
|
20
|
+
assertUsage(key === '*', "Resolving URL with multiple globs isn't implemented yet");
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
key = `@${key}`;
|
|
24
|
+
}
|
|
25
|
+
parts = parts
|
|
26
|
+
.map((part) => {
|
|
27
|
+
if (part.type === 'URL') {
|
|
28
|
+
return part;
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
return part.val
|
|
32
|
+
.split(key)
|
|
33
|
+
.map((rest, i) => {
|
|
34
|
+
const partURL = { val, type: 'URL' };
|
|
35
|
+
const partRouteString = { val: rest, type: 'ROUTE_STRING' };
|
|
36
|
+
return i === 0 ? [partRouteString] : [partURL, partRouteString];
|
|
37
|
+
})
|
|
38
|
+
.flat();
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
.flat();
|
|
42
|
+
});
|
|
43
|
+
const urlPathname = parts.map((p) => p.val).join('');
|
|
44
|
+
return urlPathname;
|
|
45
|
+
}
|
|
@@ -35,6 +35,11 @@ type PageContextBuiltInCommon<Page = [never]> = {
|
|
|
35
35
|
* https://vike.dev/route-string
|
|
36
36
|
*/
|
|
37
37
|
routeParams: Record<string, string>;
|
|
38
|
+
/** The page's data which was fetched using the data() hook.
|
|
39
|
+
*
|
|
40
|
+
* https://vike.dev/data
|
|
41
|
+
*/
|
|
42
|
+
data?: unknown;
|
|
38
43
|
/** The page's configuration values.
|
|
39
44
|
*
|
|
40
45
|
* https://vike.dev/config
|
|
@@ -6,7 +6,7 @@ export type { PageContextClientWithServerRouting } from '../shared/types.js';
|
|
|
6
6
|
export type { PageContextBuiltInServer } from '../shared/types.js';
|
|
7
7
|
export type { PageContextBuiltInClientWithClientRouting } from '../shared/types.js';
|
|
8
8
|
export type { PageContextBuiltInClientWithServerRouting } from '../shared/types.js';
|
|
9
|
-
export type { Config, ConfigMeta as Meta, GuardAsync, GuardSync, OnBeforePrerenderStartAsync, OnBeforePrerenderStartSync, OnBeforeRenderAsync, OnBeforeRenderSync, OnBeforeRouteAsync, OnBeforeRouteSync, OnHydrationEndAsync, OnHydrationEndSync, OnPageTransitionEndAsync, OnPageTransitionEndSync, OnPageTransitionStartAsync, OnPageTransitionStartSync, OnPrerenderStartAsync, OnPrerenderStartSync, OnRenderClientAsync, OnRenderClientSync, OnRenderHtmlAsync, OnRenderHtmlSync, RouteAsync, RouteSync } from '../shared/page-configs/Config.js';
|
|
9
|
+
export type { Config, ConfigMeta as Meta, DataAsync, DataSync, GuardAsync, GuardSync, OnBeforePrerenderStartAsync, OnBeforePrerenderStartSync, OnBeforeRenderAsync, OnBeforeRenderSync, OnBeforeRouteAsync, OnBeforeRouteSync, OnHydrationEndAsync, OnHydrationEndSync, OnPageTransitionEndAsync, OnPageTransitionEndSync, OnPageTransitionStartAsync, OnPageTransitionStartSync, OnPrerenderStartAsync, OnPrerenderStartSync, OnRenderClientAsync, OnRenderClientSync, OnRenderHtmlAsync, OnRenderHtmlSync, RouteAsync, RouteSync } from '../shared/page-configs/Config.js';
|
|
10
10
|
export type { ConfigEnv } from '../shared/page-configs/PageConfig.js';
|
|
11
11
|
export type { ConfigDefinition, ConfigEffect } from '../node/plugin/plugins/importUserCode/v1-design/getVikeConfig/configDefinitionsBuiltIn.js';
|
|
12
12
|
export type { ConfigEntries } from '../shared/getPageFiles/getExports.js';
|