vike 0.4.267 → 0.4.268-commit-ca58695
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/RenderErrorPage.js +2 -2
- package/abort.js +2 -2
- package/dist/client/__internal/index.d.ts +3 -0
- package/dist/client/__internal/index.js +4 -0
- package/dist/client/runtime-client-routing/createPageContextClient.d.ts +5 -0
- package/dist/client/runtime-client-routing/getGlobalContextClientInternal.d.ts +5 -0
- package/dist/client/runtime-client-routing/getPageContextFromHooks.d.ts +28 -2
- package/dist/client/runtime-client-routing/getPageContextFromHooks.js +5 -5
- package/dist/client/runtime-client-routing/renderPageClient.d.ts +490 -10
- package/dist/client/runtime-client-routing/renderPageClient.js +149 -43
- package/dist/client/runtime-client-routing/streamedValues.d.ts +5 -0
- package/dist/client/runtime-client-routing/streamedValues.js +23 -0
- package/dist/client/runtime-server-routing/createPageContextClient.d.ts +5 -0
- package/dist/client/runtime-server-routing/entry.js +1 -1
- package/dist/client/runtime-server-routing/getGlobalContextClientInternal.d.ts +5 -0
- package/dist/client/shared/getGlobalContextClientInternalShared.d.ts +5 -0
- package/dist/client/shared/getGlobalContextClientInternalShared.js +2 -0
- package/dist/client/shared/getJsonSerializedInHtml.d.ts +2 -2
- package/dist/client/shared/getJsonSerializedInHtml.js +9 -6
- package/dist/client/shared/loadPageConfigsLazyClientSide.js +0 -4
- package/dist/client/shared/removeFoucBuster.js +14 -3
- package/dist/client/shared/streamedValues/asyncIterable.d.ts +4 -0
- package/dist/client/shared/streamedValues/asyncIterable.js +26 -0
- package/dist/client/shared/streamedValues/lines.d.ts +11 -0
- package/dist/client/shared/streamedValues/lines.js +19 -0
- package/dist/client/shared/streamedValues/promise.d.ts +4 -0
- package/dist/client/shared/streamedValues/promise.js +19 -0
- package/dist/client/shared/streamedValues/readableStream.d.ts +4 -0
- package/dist/client/shared/streamedValues/readableStream.js +44 -0
- package/dist/client/shared/streamedValues/registry.d.ts +21 -0
- package/dist/client/shared/streamedValues/registry.js +40 -0
- package/dist/client/shared/streamedValues.d.ts +7 -0
- package/dist/client/shared/streamedValues.js +82 -0
- package/dist/node/api/dev.js +15 -1
- package/dist/node/api/resolveViteConfigUser.js +2 -2
- package/dist/node/api/serverEntryDev.d.ts +10 -0
- package/dist/node/api/serverEntryDev.js +125 -0
- package/dist/node/createDevMiddleware.js +12 -0
- package/dist/node/prerender/resolvePrerenderConfig.d.ts +1 -1
- package/dist/node/prerender/resolvePrerenderConfig.js +4 -1
- package/dist/node/prerender/runPrerender.d.ts +18 -18
- package/dist/node/prerender/runPrerender.js +61 -16
- package/dist/node/vite/assertEnvVite.js +1 -1
- package/dist/node/vite/index.js +2 -0
- package/dist/node/vite/plugins/build/handleAssetsManifest.js +6 -2
- package/dist/node/vite/plugins/build/pluginBuildApp.js +25 -26
- package/dist/node/vite/plugins/build/pluginBuildConfig.d.ts +2 -2
- package/dist/node/vite/plugins/build/pluginBuildConfig.js +25 -17
- package/dist/node/vite/plugins/build/pluginDistFileNames.js +70 -50
- package/dist/node/vite/plugins/build/pluginEnvironmentEntries.d.ts +6 -0
- package/dist/node/vite/plugins/build/pluginEnvironmentEntries.js +71 -0
- package/dist/node/vite/plugins/build/pluginSuppressRollupWarning.js +19 -17
- package/dist/node/vite/plugins/pluginCommon.js +10 -7
- package/dist/node/vite/plugins/pluginDev/optimizeDeps.d.ts +2 -2
- package/dist/node/vite/plugins/pluginDev/optimizeDeps.js +6 -2
- package/dist/node/vite/plugins/pluginReplaceConstantsGlobalThis.js +6 -4
- package/dist/node/vite/plugins/pluginUniversalDeploy/getServerConfig.d.ts +3 -0
- package/dist/node/vite/plugins/pluginUniversalDeploy/getServerConfig.js +28 -2
- package/dist/node/vite/plugins/pluginUniversalDeploy/pluginServerEntryAlias.d.ts +1 -1
- package/dist/node/vite/plugins/pluginUniversalDeploy/pluginServerEntryAlias.js +22 -11
- package/dist/node/vite/plugins/pluginUniversalDeploy/pluginWrapServerFile.d.ts +4 -0
- package/dist/node/vite/plugins/pluginUniversalDeploy/pluginWrapServerFile.js +29 -0
- package/dist/node/vite/plugins/pluginUniversalDeploy.js +29 -5
- package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFileGlobalEntry.d.ts +2 -1
- package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFileGlobalEntry.js +29 -12
- package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFileGlobalEntryWithOldDesign.js +3 -2
- package/dist/node/vite/plugins/pluginVirtualFiles/generateVirtualFilePageEntry.js +7 -7
- package/dist/node/vite/plugins/pluginVirtualFiles/getConfigValueSourcesRelevant.d.ts +10 -6
- package/dist/node/vite/plugins/pluginVirtualFiles/getConfigValueSourcesRelevant.js +5 -11
- package/dist/node/vite/plugins/pluginVirtualFiles.js +20 -0
- package/dist/node/vite/shared/addSsrMiddleware.js +11 -27
- package/dist/node/vite/shared/findPageFiles.d.ts +1 -1
- package/dist/node/vite/shared/findPageFiles.js +1 -11
- package/dist/node/vite/shared/getAssetsDir.d.ts +3 -2
- package/dist/node/vite/shared/getAssetsDir.js +3 -3
- package/dist/node/vite/shared/isViteCli.d.ts +3 -3
- package/dist/node/vite/shared/isViteCli.js +80 -84
- package/dist/node/vite/shared/isViteServerSide.js +2 -7
- package/dist/node/vite/shared/resolveVikeConfigInternal/metaBuiltIn.d.ts +6 -4
- package/dist/node/vite/shared/resolveVikeConfigInternal/metaBuiltIn.js +17 -6
- package/dist/node/vite/shared/resolveVikeConfigInternal/transpileAndExecuteFile.js +9 -2
- package/dist/node/vite/shared/resolveVikeConfigInternal.d.ts +5 -1
- package/dist/node/vite/shared/resolveVikeConfigInternal.js +86 -13
- package/dist/server/__internal/fetch-deprecated.d.ts +2 -0
- package/dist/server/__internal/fetch-deprecated.js +6 -0
- package/dist/server/__internal/fetch.d.ts +9 -0
- package/dist/server/__internal/fetch.js +5 -0
- package/dist/server/__internal/index.d.ts +4 -0
- package/dist/server/__internal/index.js +8 -0
- package/dist/server/createPageRenderer.d.ts +2 -2
- package/dist/server/createPageRenderer.js +2 -2
- package/dist/server/runtime/createDevMiddleware.js +3 -1
- package/dist/server/runtime/globalContext.d.ts +69 -10
- package/dist/server/runtime/globalContext.js +35 -2
- package/dist/server/runtime/index.d.ts +1 -1
- package/dist/server/runtime/index.js +1 -1
- package/dist/server/runtime/renderPageServer/analyzePage.js +3 -3
- package/dist/server/runtime/renderPageServer/createHttpResponse.d.ts +20 -9
- package/dist/server/runtime/renderPageServer/createHttpResponse.js +34 -21
- package/dist/server/runtime/renderPageServer/createPageContextServer.d.ts +13 -23
- package/dist/server/runtime/renderPageServer/csp.d.ts +2 -1
- package/dist/server/runtime/renderPageServer/csp.js +2 -1
- package/dist/server/runtime/renderPageServer/execHookOnError.js +1 -1
- package/dist/server/runtime/renderPageServer/execHookOnRenderHtml.d.ts +9 -0
- package/dist/server/runtime/renderPageServer/execHookOnRenderHtml.js +21 -9
- package/dist/server/runtime/renderPageServer/getHttpResponseBody.d.ts +2 -2
- package/dist/server/runtime/renderPageServer/getHttpResponseBody.js +19 -12
- package/dist/server/runtime/renderPageServer/getPageContextJson.d.ts +8 -0
- package/dist/server/runtime/renderPageServer/getPageContextJson.js +47 -0
- package/dist/server/runtime/renderPageServer/handleErrorWithoutErrorPage.d.ts +2 -0
- package/dist/server/runtime/renderPageServer/handleErrorWithoutErrorPage.js +1 -1
- package/dist/server/runtime/renderPageServer/handlePageContextRequestUrl.js +2 -2
- package/dist/server/runtime/renderPageServer/headersResponse.d.ts +11 -2
- package/dist/server/runtime/renderPageServer/headersResponse.js +22 -2
- package/dist/server/runtime/renderPageServer/html/injectAssets/getHtmlTags.js +5 -4
- package/dist/server/runtime/renderPageServer/html/injectAssets.d.ts +3 -2
- package/dist/server/runtime/renderPageServer/html/injectAssets.js +7 -1
- package/dist/server/runtime/renderPageServer/html/renderHtml.js +4 -2
- package/dist/server/runtime/renderPageServer/html/serializeContext.d.ts +5 -1
- package/dist/server/runtime/renderPageServer/html/serializeContext.js +12 -9
- package/dist/server/runtime/renderPageServer/html/stream.d.ts +13 -6
- package/dist/server/runtime/renderPageServer/html/stream.js +135 -32
- package/dist/server/runtime/renderPageServer/html/streamedValuesHtml.d.ts +30 -0
- package/dist/server/runtime/renderPageServer/html/streamedValuesHtml.js +92 -0
- package/dist/server/runtime/renderPageServer/loadPageConfigsLazyServerSide.d.ts +10 -14
- package/dist/server/runtime/renderPageServer/loadPageConfigsLazyServerSide.js +5 -1
- package/dist/server/runtime/renderPageServer/loadPageContextEnvironments.d.ts +15 -0
- package/dist/server/runtime/renderPageServer/loadPageContextEnvironments.js +61 -0
- package/dist/server/runtime/renderPageServer/renderPageServerAfterRoute.d.ts +320 -55
- package/dist/server/runtime/renderPageServer/renderPageServerAfterRoute.js +21 -12
- package/dist/server/runtime/renderPageServer/streamedValues/asyncIterable.d.ts +4 -0
- package/dist/server/runtime/renderPageServer/streamedValues/asyncIterable.js +12 -0
- package/dist/server/runtime/renderPageServer/streamedValues/lines.d.ts +10 -0
- package/dist/server/runtime/renderPageServer/streamedValues/lines.js +49 -0
- package/dist/server/runtime/renderPageServer/streamedValues/promise.d.ts +4 -0
- package/dist/server/runtime/renderPageServer/streamedValues/promise.js +14 -0
- package/dist/server/runtime/renderPageServer/streamedValues/pump.d.ts +10 -0
- package/dist/server/runtime/renderPageServer/streamedValues/pump.js +67 -0
- package/dist/server/runtime/renderPageServer/streamedValues/readableStream.d.ts +4 -0
- package/dist/server/runtime/renderPageServer/streamedValues/readableStream.js +12 -0
- package/dist/server/runtime/renderPageServer/streamedValues/registry.d.ts +28 -0
- package/dist/server/runtime/renderPageServer/streamedValues/registry.js +33 -0
- package/dist/server/runtime/renderPageServer.d.ts +65 -18
- package/dist/server/runtime/renderPageServer.js +33 -62
- package/dist/server/runtime/universal-middleware/core.d.ts +25 -0
- package/dist/server/runtime/universal-middleware/core.js +167 -0
- package/dist/server/runtime/universal-middleware/deprecated-export.d.ts +3 -0
- package/dist/server/runtime/universal-middleware/deprecated-export.js +10 -0
- package/dist/server/runtime/universal-middleware/getMiddlewaresPipe.d.ts +15 -0
- package/dist/server/runtime/universal-middleware/getMiddlewaresPipe.js +51 -0
- package/dist/server/runtime/universal-middleware/vikeUniversalMiddleware.d.ts +9 -0
- package/dist/server/runtime/universal-middleware/vikeUniversalMiddleware.js +22 -0
- package/dist/shared-server-client/createGlobalContextShared.d.ts +8 -0
- package/dist/shared-server-client/createGlobalContextShared.js +2 -1
- package/dist/shared-server-client/getPageContextPublicShared.js +1 -3
- package/dist/shared-server-client/getPageFiles/parseVirtualFileExportsGlobalEntry.d.ts +8 -0
- package/dist/shared-server-client/getPageFiles/parseVirtualFileExportsGlobalEntry.js +17 -7
- package/dist/shared-server-client/hooks/execHook.d.ts +1 -1
- package/dist/shared-server-client/hooks/execHook.js +2 -2
- package/dist/shared-server-client/page-configs/serialize/serializeConfigValues.js +2 -0
- package/dist/shared-server-client/route/abort.d.ts +1 -1
- package/dist/shared-server-client/route/abort.js +4 -2
- package/dist/shared-server-client/streamedValues.d.ts +22 -0
- package/dist/shared-server-client/streamedValues.js +24 -0
- package/dist/shared-server-node/vike-environments.d.ts +4 -0
- package/dist/shared-server-node/vike-environments.js +10 -0
- package/dist/shared-server-node/virtualFileId.d.ts +7 -5
- package/dist/shared-server-node/virtualFileId.js +42 -42
- package/dist/types/Config.d.ts +11 -3
- package/dist/types/GlobalContext.d.ts +3 -3
- package/dist/types/PageConfig.d.ts +13 -5
- package/dist/types/PageContext.d.ts +18 -10
- package/dist/types/PageContext.js +1 -0
- package/dist/types/Server.d.ts +1 -1
- package/dist/types/VikeNamespace.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/utils/PROJECT_VERSION.d.ts +1 -1
- package/dist/utils/PROJECT_VERSION.js +1 -1
- package/dist/utils/assertViteVersion.d.ts +1 -3
- package/dist/utils/assertViteVersion.js +6 -9
- package/dist/utils/catchInfiniteLoop.js +33 -11
- package/dist/utils/deepEqual.d.ts +2 -1
- package/dist/utils/deepEqual.js +21 -6
- package/dist/utils/getContentTypeFromUrl.d.ts +2 -0
- package/dist/utils/getContentTypeFromUrl.js +39 -0
- package/dist/utils/injectRollupInputs.d.ts +2 -2
- package/dist/utils/injectRollupInputs.js +2 -2
- package/dist/utils/installUncaughtErrorHandlers.js +9 -0
- package/dist/utils/isDev.js +2 -7
- package/dist/utils/parseUrl-extras.js +4 -0
- package/fetch.js +2 -2
- package/modifyUrl.js +2 -2
- package/package.json +42 -26
- package/routing.js +2 -2
- package/universal-middleware.js +2 -2
- package/vike-server.d.ts +14 -0
- package/dist/node/vite/plugins/pluginUniversalDeploy/pluginUnwrapProdOptions.d.ts +0 -4
- package/dist/node/vite/plugins/pluginUniversalDeploy/pluginUnwrapProdOptions.js +0 -22
- package/dist/server/runtime/fetch.d.ts +0 -10
- package/dist/server/runtime/fetch.js +0 -5
- package/dist/server/runtime/universal-middleware.d.ts +0 -10
- package/dist/server/runtime/universal-middleware.js +0 -27
- package/dist/shared-server-client/addIs404ToPageProps.d.ts +0 -2
- package/dist/shared-server-client/addIs404ToPageProps.js +0 -17
|
@@ -9,6 +9,7 @@ import type { GlobalContextServerInternal } from '../../globalContext.js';
|
|
|
9
9
|
import type { PageContextCreatedServer } from '../createPageContextServer.js';
|
|
10
10
|
import type { PageContextBegin } from '../../renderPageServer.js';
|
|
11
11
|
import type { PageContextCspNonce } from '../csp.js';
|
|
12
|
+
import { type StreamedValue } from '../streamedValues/registry.js';
|
|
12
13
|
import '../../../assertEnvServer.js';
|
|
13
14
|
type PageContextSerialization = PageContextCreatedServer & {
|
|
14
15
|
pageId: string;
|
|
@@ -20,7 +21,10 @@ type PageContextSerialization = PageContextCreatedServer & {
|
|
|
20
21
|
_globalContext: GlobalContextServerInternal;
|
|
21
22
|
_isPageContextJsonRequest: null | PageContextBegin['_isPageContextJsonRequest'];
|
|
22
23
|
} & PageContextCspNonce;
|
|
23
|
-
declare function getPageContextClientSerialized(pageContext: PageContextSerialization, isHtmlJsonScript: boolean):
|
|
24
|
+
declare function getPageContextClientSerialized(pageContext: PageContextSerialization, isHtmlJsonScript: boolean): {
|
|
25
|
+
pageContextSerialized: string;
|
|
26
|
+
streamedValues: StreamedValue[];
|
|
27
|
+
};
|
|
24
28
|
declare function getGlobalContextClientSerialized(pageContext: PageContextSerialization, isHtmlJsonScript: boolean): string;
|
|
25
29
|
type PassToClient = string[];
|
|
26
30
|
type PassToClientPublic = (string | {
|
|
@@ -7,12 +7,12 @@ import { getPropAccessNotation } from '../../../../utils/getPropAccessNotation.j
|
|
|
7
7
|
import { assert, assertUsage, assertWarning } from '../../../../utils/assert.js';
|
|
8
8
|
import { hasProp } from '../../../../utils/hasProp.js';
|
|
9
9
|
import { isErrorPage } from '../../../../shared-server-client/error-page.js';
|
|
10
|
-
import { addIs404ToPageProps } from '../../../../shared-server-client/addIs404ToPageProps.js';
|
|
11
10
|
import pc from '@brillout/picocolors';
|
|
12
11
|
import { NOT_SERIALIZABLE } from '../../../../shared-server-client/NOT_SERIALIZABLE.js';
|
|
13
12
|
import { pageContextInitIsPassedToClient } from '../../../../shared-server-client/misc/pageContextInitIsPassedToClient.js';
|
|
14
13
|
import { isServerSideError } from '../../../../shared-server-client/misc/isServerSideError.js';
|
|
15
14
|
import { getPropKeys, getPropVal, setPropVal } from './propKeys.js';
|
|
15
|
+
import { getReplacer } from '../streamedValues/registry.js';
|
|
16
16
|
import { assertRouteParams } from '../../../../shared-server-client/route/resolveRouteFunction.js';
|
|
17
17
|
import '../../../assertEnvServer.js';
|
|
18
18
|
const passToClientBuiltInPageContext = [
|
|
@@ -30,6 +30,8 @@ const passToClientBuiltInPageContext = [
|
|
|
30
30
|
'data', // for data() hook
|
|
31
31
|
];
|
|
32
32
|
const pageToClientBuiltInPageContextError = ['pageProps', 'is404', isServerSideError];
|
|
33
|
+
// Streamed pageContext values (see shared-server-client/streamedValues.ts) are serialized as placeholders and returned:
|
|
34
|
+
// the caller sends them after the serialized pageContext.
|
|
33
35
|
function getPageContextClientSerialized(pageContext, isHtmlJsonScript) {
|
|
34
36
|
const passToClientPageContext = getPassToClientPageContext(pageContext);
|
|
35
37
|
const res = applyPassToClient(passToClientPageContext, pageContext);
|
|
@@ -38,8 +40,9 @@ function getPageContextClientSerialized(pageContext, isHtmlJsonScript) {
|
|
|
38
40
|
if (pageContextClientProps.some((prop) => getPropVal(pageContext._pageContextInit, prop))) {
|
|
39
41
|
pageContextClient[pageContextInitIsPassedToClient] = true;
|
|
40
42
|
}
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
+
const { replacer, streamedValues } = getReplacer(pageContext);
|
|
44
|
+
const pageContextSerialized = serializeObject(pageContextClient, passToClientPageContext, 'pageContext', isHtmlJsonScript, replacer);
|
|
45
|
+
return { pageContextSerialized, streamedValues };
|
|
43
46
|
}
|
|
44
47
|
function getGlobalContextClientSerialized(pageContext, isHtmlJsonScript) {
|
|
45
48
|
const passToClient = pageContext._passToClient;
|
|
@@ -49,10 +52,10 @@ function getGlobalContextClientSerialized(pageContext, isHtmlJsonScript) {
|
|
|
49
52
|
const globalContextClientSerialized = serializeObject(globalContextClient, passToClient, 'globalContext', isHtmlJsonScript);
|
|
50
53
|
return globalContextClientSerialized;
|
|
51
54
|
}
|
|
52
|
-
function serializeObject(obj, passToClient, objName, isHtmlJsonScript) {
|
|
55
|
+
function serializeObject(obj, passToClient, objName, isHtmlJsonScript, replacer) {
|
|
53
56
|
let serialized;
|
|
54
57
|
try {
|
|
55
|
-
serialized = serializeValue(obj, isHtmlJsonScript);
|
|
58
|
+
serialized = serializeValue(obj, isHtmlJsonScript, undefined, replacer);
|
|
56
59
|
}
|
|
57
60
|
catch (err) {
|
|
58
61
|
const h = (s) => pc.cyan(s);
|
|
@@ -65,7 +68,7 @@ function serializeObject(obj, passToClient, objName, isHtmlJsonScript) {
|
|
|
65
68
|
const { value } = res;
|
|
66
69
|
const varName = `${objName}${getPropKeys(prop).map(getPropAccessNotation).join('')}`;
|
|
67
70
|
try {
|
|
68
|
-
serializeValue(value, isHtmlJsonScript, varName);
|
|
71
|
+
serializeValue(value, isHtmlJsonScript, varName, replacer);
|
|
69
72
|
}
|
|
70
73
|
catch (err) {
|
|
71
74
|
propsNonSerializable.push(prop);
|
|
@@ -103,7 +106,7 @@ function serializeObject(obj, passToClient, objName, isHtmlJsonScript) {
|
|
|
103
106
|
obj[getPropKeys(prop)[0]] = NOT_SERIALIZABLE;
|
|
104
107
|
});
|
|
105
108
|
try {
|
|
106
|
-
serialized = serializeValue(obj, isHtmlJsonScript);
|
|
109
|
+
serialized = serializeValue(obj, isHtmlJsonScript, undefined, replacer);
|
|
107
110
|
}
|
|
108
111
|
catch (err) {
|
|
109
112
|
assert(false);
|
|
@@ -111,10 +114,11 @@ function serializeObject(obj, passToClient, objName, isHtmlJsonScript) {
|
|
|
111
114
|
}
|
|
112
115
|
return serialized;
|
|
113
116
|
}
|
|
114
|
-
function serializeValue(value, isHtmlJsonScript, varName) {
|
|
117
|
+
function serializeValue(value, isHtmlJsonScript, varName, replacer) {
|
|
115
118
|
return stringify(value, {
|
|
116
119
|
forbidReactElements: true,
|
|
117
120
|
valueName: varName,
|
|
121
|
+
replacer,
|
|
118
122
|
htmlScriptSafe: {
|
|
119
123
|
// Could be set to `isHtmlJsonScript` but we always use `htmlScriptSafe.escapeScripts` to be extra safe
|
|
120
124
|
escapeScripts: true,
|
|
@@ -127,7 +131,6 @@ function getPassToClientPageContext(pageContext) {
|
|
|
127
131
|
let passToClient = [...pageContext._passToClient, ...passToClientBuiltInPageContext];
|
|
128
132
|
if (isErrorPage(pageContext.pageId, pageContext._globalContext._pageConfigs)) {
|
|
129
133
|
assert(hasProp(pageContext, 'is404', 'boolean'));
|
|
130
|
-
addIs404ToPageProps(pageContext);
|
|
131
134
|
passToClient.push(...pageToClientBuiltInPageContextError);
|
|
132
135
|
}
|
|
133
136
|
passToClient = unique(passToClient);
|
|
@@ -16,6 +16,8 @@ export { isStreamReadableNode };
|
|
|
16
16
|
export { getStreamName };
|
|
17
17
|
export { inferStreamName };
|
|
18
18
|
export { streamReadableWebToString };
|
|
19
|
+
export { streamReadableWebToBytes };
|
|
20
|
+
export { awaitFirstChunk };
|
|
19
21
|
export { streamPipeNodeToString };
|
|
20
22
|
export { isStreamWritableWeb };
|
|
21
23
|
export { isStreamWritableNode };
|
|
@@ -46,17 +48,22 @@ declare function isStreamWritableWeb(thing: unknown): thing is StreamWritableWeb
|
|
|
46
48
|
declare function isStreamReadableNode(thing: unknown): thing is StreamReadableNode;
|
|
47
49
|
declare function isStreamWritableNode(thing: unknown): thing is StreamWritableNode;
|
|
48
50
|
declare function streamReadableWebToString(readableWeb: ReadableStream): Promise<string>;
|
|
51
|
+
declare function streamReadableWebToBytes(readableWeb: ReadableStream): Promise<Uint8Array>;
|
|
52
|
+
declare function awaitFirstChunk(stream: StreamReadableWeb, onErrorWhileStreaming: (err: unknown) => void): Promise<StreamReadableWeb>;
|
|
49
53
|
declare function streamPipeNodeToString(streamPipeNode: StreamPipeNode): Promise<string>;
|
|
50
|
-
declare function getStreamReadableNode(htmlRender: HtmlRender): Promise<null | StreamReadableNode>;
|
|
51
|
-
declare function getStreamReadableWeb(htmlRender: HtmlRender):
|
|
52
|
-
declare function pipeToStreamWritableWeb(htmlRender: HtmlRender, writable: StreamWritableWeb): boolean;
|
|
53
|
-
declare function pipeToStreamWritableNode(htmlRender: HtmlRender, writable: StreamWritableNode): boolean;
|
|
54
|
-
declare function processStream(streamOriginal: StreamProviderAny, { injectStringAtBegin, injectStringAfterFirstChunk, injectStringAtEnd, onErrorWhileStreaming, enableEagerStreaming, }: {
|
|
54
|
+
declare function getStreamReadableNode(htmlRender: HtmlRender | Uint8Array): Promise<null | StreamReadableNode>;
|
|
55
|
+
declare function getStreamReadableWeb(htmlRender: HtmlRender | Uint8Array): StreamReadableWeb;
|
|
56
|
+
declare function pipeToStreamWritableWeb(htmlRender: HtmlRender | Uint8Array, writable: StreamWritableWeb): boolean;
|
|
57
|
+
declare function pipeToStreamWritableNode(htmlRender: HtmlRender | Uint8Array, writable: StreamWritableNode): boolean;
|
|
58
|
+
declare function processStream(streamOriginal: StreamProviderAny, { injectStringAtBegin, injectStringAfterFirstChunk, injectStringAtEnd, onErrorWhileStreaming, enableEagerStreaming, onCancel, }: {
|
|
55
59
|
injectStringAtBegin?: () => Promise<string>;
|
|
56
60
|
injectStringAfterFirstChunk?: () => string | null;
|
|
57
|
-
|
|
61
|
+
/** `writeHtml()` writes HTML before the returned string (e.g. streamed pageContext values) */
|
|
62
|
+
injectStringAtEnd?: (writeHtml: (html: string) => void) => Promise<string>;
|
|
58
63
|
onErrorWhileStreaming: (err: unknown) => void;
|
|
59
64
|
enableEagerStreaming?: boolean;
|
|
65
|
+
/** The stream was cancelled (e.g. the user closed the tab) or failed */
|
|
66
|
+
onCancel: () => void;
|
|
60
67
|
}): Promise<StreamProviderNormalized>;
|
|
61
68
|
declare function isStream(something: unknown): something is StreamProviderAny;
|
|
62
69
|
declare const __streamPipeWeb = "__streamPipeWeb";
|
|
@@ -16,6 +16,8 @@ export { isStreamReadableNode };
|
|
|
16
16
|
export { getStreamName };
|
|
17
17
|
export { inferStreamName };
|
|
18
18
|
export { streamReadableWebToString };
|
|
19
|
+
export { streamReadableWebToBytes };
|
|
20
|
+
export { awaitFirstChunk };
|
|
19
21
|
export { streamPipeNodeToString };
|
|
20
22
|
export { isStreamWritableWeb };
|
|
21
23
|
export { isStreamWritableNode };
|
|
@@ -74,9 +76,60 @@ async function streamReadableWebToString(readableWeb) {
|
|
|
74
76
|
str += getClosingChunk();
|
|
75
77
|
return str;
|
|
76
78
|
}
|
|
79
|
+
async function streamReadableWebToBytes(readableWeb) {
|
|
80
|
+
const reader = readableWeb.getReader();
|
|
81
|
+
const chunks = [];
|
|
82
|
+
while (true) {
|
|
83
|
+
const { done, value } = await reader.read();
|
|
84
|
+
if (done)
|
|
85
|
+
break;
|
|
86
|
+
assertUsage(value instanceof Uint8Array, `The stream emitted a chunk that isn't a Uint8Array: ${String(value)}`);
|
|
87
|
+
chunks.push(value);
|
|
88
|
+
}
|
|
89
|
+
const bytes = new Uint8Array(chunks.reduce((len, chunk) => len + chunk.length, 0));
|
|
90
|
+
let offset = 0;
|
|
91
|
+
for (const chunk of chunks) {
|
|
92
|
+
bytes.set(chunk, offset);
|
|
93
|
+
offset += chunk.length;
|
|
94
|
+
}
|
|
95
|
+
return bytes;
|
|
96
|
+
}
|
|
97
|
+
// Resolves after the first chunk (rejects if the stream errors before), then reads on demand
|
|
98
|
+
async function awaitFirstChunk(stream, onErrorWhileStreaming) {
|
|
99
|
+
const reader = stream.getReader();
|
|
100
|
+
const firstChunk = await reader.read();
|
|
101
|
+
const streamStarted = new ReadableStream({
|
|
102
|
+
start(controller) {
|
|
103
|
+
if (firstChunk.done)
|
|
104
|
+
controller.close();
|
|
105
|
+
else
|
|
106
|
+
controller.enqueue(firstChunk.value);
|
|
107
|
+
},
|
|
108
|
+
async pull(controller) {
|
|
109
|
+
let chunk;
|
|
110
|
+
try {
|
|
111
|
+
chunk = await reader.read();
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
onErrorWhileStreaming(err);
|
|
115
|
+
controller.error(err);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (chunk.done)
|
|
119
|
+
controller.close();
|
|
120
|
+
else
|
|
121
|
+
controller.enqueue(chunk.value);
|
|
122
|
+
},
|
|
123
|
+
cancel(reason) {
|
|
124
|
+
return reader.cancel(reason);
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
return streamStarted;
|
|
128
|
+
}
|
|
77
129
|
async function stringToStreamReadableNode(str) {
|
|
78
130
|
const { Readable } = await loadStreamNodeModule();
|
|
79
|
-
|
|
131
|
+
// Readable.from() iterates a Uint8Array byte by byte
|
|
132
|
+
return Readable.from(typeof str === 'string' ? str : [str]);
|
|
80
133
|
}
|
|
81
134
|
async function streamReadableWebToStreamReadableNode(stream) {
|
|
82
135
|
const { Readable } = await loadStreamNodeModule();
|
|
@@ -156,16 +209,19 @@ function streamPipeWebToString(streamPipeWeb) {
|
|
|
156
209
|
return promise;
|
|
157
210
|
}
|
|
158
211
|
async function getStreamReadableNode(htmlRender) {
|
|
159
|
-
if (typeof htmlRender === 'string') {
|
|
212
|
+
if (typeof htmlRender === 'string' || htmlRender instanceof Uint8Array) {
|
|
160
213
|
return stringToStreamReadableNode(htmlRender);
|
|
161
214
|
}
|
|
162
215
|
if (isStreamReadableNode(htmlRender)) {
|
|
163
216
|
return htmlRender;
|
|
164
217
|
}
|
|
218
|
+
if (isStreamReadableWeb(htmlRender)) {
|
|
219
|
+
return streamReadableWebToStreamReadableNode(htmlRender);
|
|
220
|
+
}
|
|
165
221
|
return null;
|
|
166
222
|
}
|
|
167
223
|
function getStreamReadableWeb(htmlRender) {
|
|
168
|
-
if (typeof htmlRender === 'string') {
|
|
224
|
+
if (typeof htmlRender === 'string' || htmlRender instanceof Uint8Array) {
|
|
169
225
|
return stringToStreamReadableWeb(htmlRender);
|
|
170
226
|
}
|
|
171
227
|
if (isStreamReadableWeb(htmlRender)) {
|
|
@@ -178,16 +234,30 @@ function getStreamReadableWeb(htmlRender) {
|
|
|
178
234
|
streamPipeWeb(writable);
|
|
179
235
|
return readable;
|
|
180
236
|
}
|
|
181
|
-
|
|
237
|
+
if (isStreamReadableNode(htmlRender) || isStreamPipeNode(htmlRender)) {
|
|
238
|
+
// A Node.js stream implies that Node.js's `stream` module is available
|
|
239
|
+
const { readable, writable } = new TransformStream();
|
|
240
|
+
loadStreamNodeModule().then(({ Readable, PassThrough }) => {
|
|
241
|
+
const passThrough = new PassThrough();
|
|
242
|
+
pipeToStreamWritableNode(htmlRender, passThrough);
|
|
243
|
+
Readable.toWeb(passThrough)
|
|
244
|
+
.pipeTo(writable)
|
|
245
|
+
.catch(() => { });
|
|
246
|
+
});
|
|
247
|
+
return readable;
|
|
248
|
+
}
|
|
249
|
+
checkType(htmlRender);
|
|
250
|
+
assert(false);
|
|
182
251
|
}
|
|
183
252
|
function pipeToStreamWritableWeb(htmlRender, writable) {
|
|
184
|
-
if (typeof htmlRender === 'string') {
|
|
253
|
+
if (typeof htmlRender === 'string' || htmlRender instanceof Uint8Array) {
|
|
185
254
|
const streamPipeWeb = stringToStreamPipeWeb(htmlRender);
|
|
186
255
|
streamPipeWeb(writable);
|
|
187
256
|
return true;
|
|
188
257
|
}
|
|
189
258
|
if (isStreamReadableWeb(htmlRender)) {
|
|
190
|
-
|
|
259
|
+
// pipeTo() propagates a failure of either side to the other side
|
|
260
|
+
htmlRender.pipeTo(writable).catch(() => { });
|
|
191
261
|
return true;
|
|
192
262
|
}
|
|
193
263
|
if (isStreamPipeWeb(htmlRender)) {
|
|
@@ -203,23 +273,30 @@ function pipeToStreamWritableWeb(htmlRender, writable) {
|
|
|
203
273
|
assert(false);
|
|
204
274
|
}
|
|
205
275
|
function pipeToStreamWritableNode(htmlRender, writable) {
|
|
206
|
-
if (typeof htmlRender === 'string') {
|
|
276
|
+
if (typeof htmlRender === 'string' || htmlRender instanceof Uint8Array) {
|
|
207
277
|
const streamPipeNode = stringToStreamPipeNode(htmlRender);
|
|
208
278
|
streamPipeNode(writable);
|
|
209
279
|
return true;
|
|
210
280
|
}
|
|
211
|
-
if (isStreamReadableNode(htmlRender)) {
|
|
212
|
-
htmlRender.pipe(writable);
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
281
|
if (isStreamPipeNode(htmlRender)) {
|
|
216
282
|
const streamPipeNode = getStreamPipeNode(htmlRender);
|
|
217
283
|
assert(streamPipeNode);
|
|
218
284
|
streamPipeNode(writable);
|
|
219
285
|
return true;
|
|
220
286
|
}
|
|
221
|
-
if (isStreamReadableWeb(htmlRender)) {
|
|
222
|
-
|
|
287
|
+
if (isStreamReadableNode(htmlRender) || isStreamReadableWeb(htmlRender)) {
|
|
288
|
+
getStreamReadableNode(htmlRender).then(async (readable) => {
|
|
289
|
+
assert(readable);
|
|
290
|
+
const { pipeline } = await loadStreamNodeModule();
|
|
291
|
+
// pipeline() throws if the writable is already destroyed (e.g. the client left before the first chunk)
|
|
292
|
+
if (writable.destroyed)
|
|
293
|
+
return readable.destroy();
|
|
294
|
+
// Unlike pipe(), pipeline() destroys the readable if the writable closes early, and the writable if the readable errors or closes before its end
|
|
295
|
+
pipeline(readable, writable, () => { });
|
|
296
|
+
// E.g. compression() holds the writes until flush()
|
|
297
|
+
const w = writable;
|
|
298
|
+
readable.on('data', () => w.flush?.());
|
|
299
|
+
});
|
|
223
300
|
return true;
|
|
224
301
|
}
|
|
225
302
|
if (isStreamPipeWeb(htmlRender)) {
|
|
@@ -228,7 +305,7 @@ function pipeToStreamWritableNode(htmlRender, writable) {
|
|
|
228
305
|
checkType(htmlRender);
|
|
229
306
|
assert(false);
|
|
230
307
|
}
|
|
231
|
-
async function processStream(streamOriginal, { injectStringAtBegin, injectStringAfterFirstChunk, injectStringAtEnd, onErrorWhileStreaming, enableEagerStreaming, }) {
|
|
308
|
+
async function processStream(streamOriginal, { injectStringAtBegin, injectStringAfterFirstChunk, injectStringAtEnd, onErrorWhileStreaming, enableEagerStreaming, onCancel, }) {
|
|
232
309
|
const buffer = [];
|
|
233
310
|
let streamOriginalHasStartedEmitting = false;
|
|
234
311
|
let streamOriginalEnded = false;
|
|
@@ -275,6 +352,8 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
|
|
|
275
352
|
resolveReadyToWrite();
|
|
276
353
|
},
|
|
277
354
|
onError(err) {
|
|
355
|
+
// The HTML won't end: its streamed pageContext values won't be sent
|
|
356
|
+
onCancel();
|
|
278
357
|
if (!promiseHasResolved) {
|
|
279
358
|
reject(err);
|
|
280
359
|
}
|
|
@@ -303,7 +382,10 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
|
|
|
303
382
|
streamOriginalEnded = true;
|
|
304
383
|
});
|
|
305
384
|
if (injectStringAtEnd && !isCancel) {
|
|
306
|
-
const injectedChunk = await injectStringAtEnd()
|
|
385
|
+
const injectedChunk = await injectStringAtEnd((html) => {
|
|
386
|
+
writeStream(html);
|
|
387
|
+
flushStream();
|
|
388
|
+
});
|
|
307
389
|
writeStream(injectedChunk);
|
|
308
390
|
}
|
|
309
391
|
await promiseReadyToWrite; // E.g. if the user calls the pipe wrapper after the original writable has ended
|
|
@@ -326,6 +408,7 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
|
|
|
326
408
|
onFlush() {
|
|
327
409
|
flushStream();
|
|
328
410
|
},
|
|
411
|
+
onCancel,
|
|
329
412
|
});
|
|
330
413
|
wrapperCreated = true;
|
|
331
414
|
flushBuffer(); // In case onReadyToWrite() was already called (the flushBuffer() of onReadyToWrite() wasn't called because `wrapperCreated === false`)
|
|
@@ -388,7 +471,7 @@ async function processStream(streamOriginal, { injectStringAtBegin, injectString
|
|
|
388
471
|
return !enableEagerStreaming && !streamOriginalHasStartedEmitting;
|
|
389
472
|
}
|
|
390
473
|
}
|
|
391
|
-
async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onFlush, onReadyToWrite, }) {
|
|
474
|
+
async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onFlush, onReadyToWrite, onCancel, }) {
|
|
392
475
|
if (isStreamFromReactStreamingPackage(streamOriginal)) {
|
|
393
476
|
debug(`onRenderHtml() hook returned ${pc.cyan('react-streaming')} result`);
|
|
394
477
|
const stream = getStreamOfReactStreamingPackage(streamOriginal);
|
|
@@ -400,6 +483,16 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
400
483
|
const pipeProxy = (writable_) => {
|
|
401
484
|
writableOriginal = writable_;
|
|
402
485
|
debug('original Node.js Writable received');
|
|
486
|
+
// Let the source know when the response closes early (no-op once it has ended)
|
|
487
|
+
const onClose = () => {
|
|
488
|
+
if (!hasEnded)
|
|
489
|
+
onCancel();
|
|
490
|
+
writableProxy.destroy();
|
|
491
|
+
};
|
|
492
|
+
if (writableOriginal.destroyed)
|
|
493
|
+
onClose();
|
|
494
|
+
else
|
|
495
|
+
writableOriginal.on('close', onClose);
|
|
403
496
|
onReadyToWrite();
|
|
404
497
|
if (hasEnded) {
|
|
405
498
|
// onReadyToWrite() already wrote everything; we can close the stream right away
|
|
@@ -463,6 +556,11 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
463
556
|
const pipeProxy = (writableOriginal) => {
|
|
464
557
|
writerOriginal = writableOriginal.getWriter();
|
|
465
558
|
debug('original Web Writable received');
|
|
559
|
+
// Let the source know when the response closes early
|
|
560
|
+
writerOriginal.closed.catch((err) => {
|
|
561
|
+
onCancel();
|
|
562
|
+
readerProxy?.cancel(err);
|
|
563
|
+
});
|
|
466
564
|
(async () => {
|
|
467
565
|
// CloudFlare Workers does not implement `ready` property
|
|
468
566
|
// - https://github.com/vuejs/vue-next/issues/4287
|
|
@@ -480,7 +578,7 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
480
578
|
stampPipe(pipeProxy, 'web-stream');
|
|
481
579
|
const writeChunk = (chunk) => {
|
|
482
580
|
assert(writerOriginal);
|
|
483
|
-
writerOriginal.write(encodeForWebStream(chunk));
|
|
581
|
+
writerOriginal.write(encodeForWebStream(chunk)).catch(() => { });
|
|
484
582
|
debugWithChunk('data written (Web Writable)', chunk);
|
|
485
583
|
};
|
|
486
584
|
// Web Streams have compression built-in
|
|
@@ -491,10 +589,11 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
491
589
|
const endStream = () => {
|
|
492
590
|
hasEnded = true;
|
|
493
591
|
if (writerOriginal) {
|
|
494
|
-
writerOriginal.close();
|
|
592
|
+
writerOriginal.close().catch(() => { });
|
|
495
593
|
}
|
|
496
594
|
};
|
|
497
595
|
let writableProxy;
|
|
596
|
+
let readerProxy;
|
|
498
597
|
if (typeof ReadableStream !== 'function') {
|
|
499
598
|
writableProxy = new WritableStream({
|
|
500
599
|
write(chunk) {
|
|
@@ -513,7 +612,8 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
513
612
|
else {
|
|
514
613
|
const { readable, writable } = new TransformStream();
|
|
515
614
|
writableProxy = writable;
|
|
516
|
-
|
|
615
|
+
readerProxy = readable.getReader();
|
|
616
|
+
handleReadableWeb(readerProxy, {
|
|
517
617
|
onData,
|
|
518
618
|
onError(err) {
|
|
519
619
|
onError(err);
|
|
@@ -531,7 +631,7 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
531
631
|
}
|
|
532
632
|
if (isStreamReadableWeb(streamOriginal)) {
|
|
533
633
|
debug('onRenderHtml() hook returned Web Readable');
|
|
534
|
-
const
|
|
634
|
+
const readerOriginal = streamOriginal.getReader();
|
|
535
635
|
let isClosed = false;
|
|
536
636
|
let isCancel = false;
|
|
537
637
|
const closeStream = async () => {
|
|
@@ -548,7 +648,7 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
548
648
|
start(controller) {
|
|
549
649
|
controllerProxy = controller;
|
|
550
650
|
onReadyToWrite();
|
|
551
|
-
handleReadableWeb(
|
|
651
|
+
handleReadableWeb(readerOriginal, {
|
|
552
652
|
onData,
|
|
553
653
|
onError(err) {
|
|
554
654
|
onError(err);
|
|
@@ -559,18 +659,16 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
559
659
|
},
|
|
560
660
|
});
|
|
561
661
|
},
|
|
562
|
-
async cancel(
|
|
662
|
+
async cancel(reason) {
|
|
563
663
|
debug('stream cancelled');
|
|
564
664
|
isCancel = true;
|
|
565
|
-
|
|
566
|
-
//
|
|
567
|
-
await
|
|
665
|
+
onCancel();
|
|
666
|
+
// Ends handleReadableWeb() which then calls closeStream()
|
|
667
|
+
await readerOriginal.cancel(reason);
|
|
568
668
|
},
|
|
569
669
|
});
|
|
570
670
|
const writeChunk = (chunk) => {
|
|
571
|
-
if (!isCancel &&
|
|
572
|
-
// If readableOriginal doesn't implement readableOriginal.cancel() then it may still emit data after we close the stream. We therefore need to check whether the steam is closed.
|
|
573
|
-
!isClosed) {
|
|
671
|
+
if (!isCancel && !isClosed) {
|
|
574
672
|
controllerProxy.enqueue(encodeForWebStream(chunk));
|
|
575
673
|
debugWithChunk('data written (Web Readable)', chunk);
|
|
576
674
|
}
|
|
@@ -603,6 +701,12 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
603
701
|
readableProxy.push(null);
|
|
604
702
|
};
|
|
605
703
|
const readableProxy = new Readable({ read() { } });
|
|
704
|
+
// Destroy the source when the consumer closes early
|
|
705
|
+
readableProxy.once('close', () => {
|
|
706
|
+
if (!readableProxy.readableEnded)
|
|
707
|
+
onCancel();
|
|
708
|
+
readableOriginal.destroy();
|
|
709
|
+
});
|
|
606
710
|
onReadyToWrite();
|
|
607
711
|
readableOriginal.on('data', (chunk) => {
|
|
608
712
|
onData(chunk);
|
|
@@ -622,8 +726,7 @@ async function createStreamWrapper({ streamOriginal, onError, onData, onEnd, onF
|
|
|
622
726
|
}
|
|
623
727
|
assert(false);
|
|
624
728
|
}
|
|
625
|
-
async function handleReadableWeb(
|
|
626
|
-
const reader = readable.getReader();
|
|
729
|
+
async function handleReadableWeb(reader, { onData, onError, onEnd, }) {
|
|
627
730
|
while (true) {
|
|
628
731
|
let result;
|
|
629
732
|
try {
|
|
@@ -776,8 +879,8 @@ function encodeForWebStream(thing) {
|
|
|
776
879
|
// Because of Cloudflare Workers, we cannot statically import the `stream` module, instead we dynamically import it.
|
|
777
880
|
async function loadStreamNodeModule() {
|
|
778
881
|
const streamModule = (await import_('stream')).default;
|
|
779
|
-
const { Readable, Writable } = streamModule;
|
|
780
|
-
return { Readable, Writable };
|
|
882
|
+
const { Readable, Writable, PassThrough, pipeline } = streamModule;
|
|
883
|
+
return { Readable, Writable, PassThrough, pipeline };
|
|
781
884
|
}
|
|
782
885
|
function getStreamName(kind, type) {
|
|
783
886
|
let typeName = capitalizeFirstLetter(type);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export { serializePageContextHtml };
|
|
2
|
+
export { getStreamedValuesHtml };
|
|
3
|
+
export { writeStreamedValuesHtmlAtStreamEnd };
|
|
4
|
+
export { cancelStreamedValuesHtml };
|
|
5
|
+
export { getStreamedValuesLinesPrerendered };
|
|
6
|
+
export type { PageContextStreamedValuesHtml };
|
|
7
|
+
import { type PageContextSerialization } from './serializeContext.js';
|
|
8
|
+
import type { PageContextCreatedServer } from '../createPageContextServer.js';
|
|
9
|
+
import type { StreamFromReactStreamingPackage } from './stream/react-streaming.js';
|
|
10
|
+
import { type PageContextCspNonce } from '../csp.js';
|
|
11
|
+
import '../../../assertEnvServer.js';
|
|
12
|
+
type StreamedValuesHtml = {
|
|
13
|
+
done: Promise<void>;
|
|
14
|
+
cancel: () => void;
|
|
15
|
+
/** The `<script>` tags not sent yet */
|
|
16
|
+
pending: string[];
|
|
17
|
+
/** Set once the HTML stream is ending */
|
|
18
|
+
writeHtml: null | ((html: string) => void);
|
|
19
|
+
/** Pre-rendering: all lines */
|
|
20
|
+
lines: null | string[];
|
|
21
|
+
};
|
|
22
|
+
type PageContextStreamedValuesHtml = PageContextCreatedServer & PageContextCspNonce & {
|
|
23
|
+
_requestId: number;
|
|
24
|
+
_streamedValuesHtml?: StreamedValuesHtml;
|
|
25
|
+
};
|
|
26
|
+
declare function serializePageContextHtml(pageContext: PageContextStreamedValuesHtml & PageContextSerialization, streamFromReactStreamingPackage: null | StreamFromReactStreamingPackage): string;
|
|
27
|
+
declare function getStreamedValuesHtml(pageContext: PageContextStreamedValuesHtml): Promise<null | string>;
|
|
28
|
+
declare function writeStreamedValuesHtmlAtStreamEnd(pageContext: PageContextStreamedValuesHtml, htmlEnd: string, writeHtml: (html: string) => void): Promise<string>;
|
|
29
|
+
declare function cancelStreamedValuesHtml(pageContext: PageContextStreamedValuesHtml): void;
|
|
30
|
+
declare function getStreamedValuesLinesPrerendered(pageContext: PageContextStreamedValuesHtml): Promise<null | string[]>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// The streamed pageContext values (see shared-server-client/streamedValues.ts) of the HTML's
|
|
2
|
+
// `<script id="vike_pageContext">`: each line is sent as a `<script>` that pushes it to `self.__vike_streamed` (read by
|
|
3
|
+
// Vike's client runtime, see client/shared/streamedValues.ts).
|
|
4
|
+
// - HTML stream of react-streaming: the lines are injected into the stream as they're produced.
|
|
5
|
+
// - HTML stream: the lines produced while the stream is running are sent after it ends, and the lines produced
|
|
6
|
+
// afterwards are sent as they're produced; the HTML ends once all values have ended.
|
|
7
|
+
// - HTML string: the lines are appended to the HTML once all values have ended.
|
|
8
|
+
// - Pre-rendering: the lines are also collected for `index.pageContext.json`, so that the values are read once.
|
|
9
|
+
export { serializePageContextHtml };
|
|
10
|
+
export { getStreamedValuesHtml };
|
|
11
|
+
export { writeStreamedValuesHtmlAtStreamEnd };
|
|
12
|
+
export { cancelStreamedValuesHtml };
|
|
13
|
+
export { getStreamedValuesLinesPrerendered };
|
|
14
|
+
import { assert } from '../../../../utils/assert.js';
|
|
15
|
+
import { pumpStreamedValues } from '../streamedValues/pump.js';
|
|
16
|
+
import { getPageContextClientSerialized } from './serializeContext.js';
|
|
17
|
+
import { inferNonceAttr } from '../csp.js';
|
|
18
|
+
import '../../../assertEnvServer.js';
|
|
19
|
+
// The pageContext of `<script id="vike_pageContext">`, as `[pageContext]` if it has streamed values (which start streaming)
|
|
20
|
+
function serializePageContextHtml(pageContext, streamFromReactStreamingPackage) {
|
|
21
|
+
const { pageContextSerialized, streamedValues } = getPageContextClientSerialized(pageContext, true);
|
|
22
|
+
if (streamedValues.length === 0)
|
|
23
|
+
return pageContextSerialized;
|
|
24
|
+
// The pageContext is serialized once per HTML
|
|
25
|
+
assert(!pageContext._streamedValuesHtml);
|
|
26
|
+
const { isPrerendering } = pageContext;
|
|
27
|
+
const write = (line) => {
|
|
28
|
+
streamedValuesHtml.lines?.push(line);
|
|
29
|
+
const script = getScript(line, pageContext);
|
|
30
|
+
if (streamedValuesHtml.writeHtml) {
|
|
31
|
+
streamedValuesHtml.writeHtml(script);
|
|
32
|
+
}
|
|
33
|
+
else if (streamFromReactStreamingPackage && !streamFromReactStreamingPackage.hasStreamEnded()) {
|
|
34
|
+
streamFromReactStreamingPackage.injectToStream(script, { flush: true });
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
streamedValuesHtml.pending.push(script);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const streamedValuesHtml = {
|
|
41
|
+
// A pre-rendered page can't have a failed value
|
|
42
|
+
...pumpStreamedValues(pageContext, streamedValues, write, { failFast: isPrerendering }),
|
|
43
|
+
pending: [],
|
|
44
|
+
writeHtml: null,
|
|
45
|
+
lines: isPrerendering ? [] : null,
|
|
46
|
+
};
|
|
47
|
+
// Pre-rendering: the error is thrown by getStreamedValuesLinesPrerendered()
|
|
48
|
+
streamedValuesHtml.done.catch(() => { });
|
|
49
|
+
pageContext._streamedValuesHtml = streamedValuesHtml;
|
|
50
|
+
return `[${pageContextSerialized}]`;
|
|
51
|
+
}
|
|
52
|
+
// HTML string
|
|
53
|
+
async function getStreamedValuesHtml(pageContext) {
|
|
54
|
+
const streamedValuesHtml = pageContext._streamedValuesHtml;
|
|
55
|
+
if (!streamedValuesHtml)
|
|
56
|
+
return null;
|
|
57
|
+
await streamedValuesHtml.done.catch(() => { });
|
|
58
|
+
return streamedValuesHtml.pending.join('');
|
|
59
|
+
}
|
|
60
|
+
// HTML stream: `htmlEnd` is what Vike appends after the HTML stream ended. The lines are sent before `</body>`.
|
|
61
|
+
async function writeStreamedValuesHtmlAtStreamEnd(pageContext, htmlEnd, writeHtml) {
|
|
62
|
+
const streamedValuesHtml = pageContext._streamedValuesHtml;
|
|
63
|
+
if (!streamedValuesHtml)
|
|
64
|
+
return htmlEnd;
|
|
65
|
+
let i = htmlEnd.lastIndexOf('</body>');
|
|
66
|
+
if (i === -1)
|
|
67
|
+
i = htmlEnd.length;
|
|
68
|
+
writeHtml(htmlEnd.slice(0, i) + streamedValuesHtml.pending.join(''));
|
|
69
|
+
streamedValuesHtml.writeHtml = writeHtml;
|
|
70
|
+
await streamedValuesHtml.done.catch(() => { });
|
|
71
|
+
return htmlEnd.slice(i);
|
|
72
|
+
}
|
|
73
|
+
// The HTML response was cancelled (e.g. the user closed the tab) or failed
|
|
74
|
+
function cancelStreamedValuesHtml(pageContext) {
|
|
75
|
+
pageContext._streamedValuesHtml?.cancel();
|
|
76
|
+
}
|
|
77
|
+
// Pre-rendering: the lines for `index.pageContext.json` (the values are read once, while rendering the HTML)
|
|
78
|
+
async function getStreamedValuesLinesPrerendered(pageContext) {
|
|
79
|
+
const streamedValuesHtml = pageContext._streamedValuesHtml;
|
|
80
|
+
if (!streamedValuesHtml)
|
|
81
|
+
return null;
|
|
82
|
+
await streamedValuesHtml.done;
|
|
83
|
+
assert(streamedValuesHtml.lines);
|
|
84
|
+
return streamedValuesHtml.lines;
|
|
85
|
+
}
|
|
86
|
+
function getScript(line, pageContext) {
|
|
87
|
+
// A JavaScript string literal: JSON.stringify() escapes quotes, backslashes and line breaks; `<` is escaped so that the
|
|
88
|
+
// script never contains `</script>` nor `<!--`; `/` is escaped for the same reason as in `<script id="vike_pageContext">`
|
|
89
|
+
// (https://github.com/vikejs/vike/pull/2603)
|
|
90
|
+
const literal = JSON.stringify(line).replaceAll('<', '\\u003c').replaceAll('/', '\\/');
|
|
91
|
+
return `<script${inferNonceAttr(pageContext)}>(self.__vike_streamed=self.__vike_streamed||[]).push(${literal})</script>`;
|
|
92
|
+
}
|