@quilted/quilt 0.5.151 → 0.5.153
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/CHANGELOG.md +16 -0
- package/build/cjs/assets.cjs +39 -0
- package/build/cjs/async.cjs +32 -0
- package/build/cjs/events.cjs +46 -0
- package/build/cjs/graphql/testing.cjs +2 -6
- package/build/cjs/html/HTML.cjs +21 -0
- package/build/cjs/html.cjs +33 -6
- package/build/cjs/http.cjs +16 -0
- package/build/cjs/index.cjs +0 -319
- package/build/cjs/localize.cjs +46 -0
- package/build/cjs/navigate/testing.cjs +12 -0
- package/build/cjs/navigate.cjs +70 -0
- package/build/cjs/performance.cjs +26 -0
- package/build/cjs/polyfills/fetch-get-set-cookie.cjs +4 -0
- package/build/cjs/react/testing.cjs +30 -0
- package/build/cjs/react/tools.cjs +19 -0
- package/build/cjs/react.cjs +15 -0
- package/build/cjs/server/ServerContext.cjs +1 -1
- package/build/cjs/server/preload.cjs +1 -1
- package/build/cjs/server/request-router.cjs +215 -231
- package/build/cjs/{server/index.cjs → server.cjs} +26 -52
- package/build/cjs/signals.cjs +51 -0
- package/build/cjs/static/StaticContext.cjs +1 -1
- package/build/cjs/static/index.cjs +43 -51
- package/build/cjs/static/render.cjs +1 -1
- package/build/cjs/testing.cjs +6 -34
- package/build/esm/assets.mjs +2 -0
- package/build/esm/async.mjs +3 -0
- package/build/esm/events.mjs +1 -0
- package/build/esm/graphql/testing.mjs +1 -1
- package/build/esm/html/HTML.mjs +19 -0
- package/build/esm/html.mjs +3 -1
- package/build/esm/http.mjs +1 -1
- package/build/esm/index.mjs +1 -15
- package/build/esm/localize.mjs +1 -0
- package/build/esm/navigate/testing.mjs +1 -0
- package/build/esm/navigate.mjs +1 -0
- package/build/esm/performance.mjs +1 -0
- package/build/esm/polyfills/fetch-get-set-cookie.mjs +1 -0
- package/build/esm/react/testing.mjs +3 -0
- package/build/esm/react/tools.mjs +2 -0
- package/build/esm/react.mjs +2 -0
- package/build/esm/server/ServerContext.mjs +2 -2
- package/build/esm/server/preload.mjs +2 -2
- package/build/esm/server/request-router.mjs +218 -232
- package/build/esm/server.mjs +10 -0
- package/build/esm/signals.mjs +2 -0
- package/build/esm/static/StaticContext.mjs +2 -2
- package/build/esm/static/index.mjs +40 -48
- package/build/esm/static/render.mjs +2 -2
- package/build/esm/testing.mjs +0 -3
- package/build/esnext/assets.esnext +2 -0
- package/build/esnext/async.esnext +3 -0
- package/build/esnext/events.esnext +1 -0
- package/build/esnext/graphql/testing.esnext +1 -1
- package/build/esnext/html/HTML.esnext +19 -0
- package/build/esnext/html.esnext +3 -1
- package/build/esnext/http.esnext +1 -1
- package/build/esnext/index.esnext +1 -15
- package/build/esnext/localize.esnext +1 -0
- package/build/esnext/navigate/testing.esnext +1 -0
- package/build/esnext/navigate.esnext +1 -0
- package/build/esnext/performance.esnext +1 -0
- package/build/esnext/polyfills/fetch-get-set-cookie.esnext +1 -0
- package/build/esnext/react/testing.esnext +3 -0
- package/build/esnext/react/tools.esnext +2 -0
- package/build/esnext/react.esnext +2 -0
- package/build/esnext/server/ServerContext.esnext +2 -2
- package/build/esnext/server/preload.esnext +2 -2
- package/build/esnext/server/request-router.esnext +218 -232
- package/build/esnext/server.esnext +10 -0
- package/build/esnext/signals.esnext +2 -0
- package/build/esnext/static/StaticContext.esnext +2 -2
- package/build/esnext/static/index.esnext +40 -48
- package/build/esnext/static/render.esnext +2 -2
- package/build/esnext/testing.esnext +0 -3
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/typescript/assets.d.ts +3 -1
- package/build/typescript/assets.d.ts.map +1 -1
- package/build/typescript/async.d.ts +6 -0
- package/build/typescript/async.d.ts.map +1 -0
- package/build/typescript/events.d.ts +3 -0
- package/build/typescript/events.d.ts.map +1 -0
- package/build/typescript/globals.d.ts +8 -0
- package/build/typescript/globals.d.ts.map +1 -0
- package/build/typescript/graphql/testing/matchers/operations.d.ts +7 -0
- package/build/typescript/graphql/testing/matchers/operations.d.ts.map +1 -0
- package/build/typescript/graphql/testing/matchers/utilities.d.ts +8 -0
- package/build/typescript/graphql/testing/matchers/utilities.d.ts.map +1 -0
- package/build/typescript/graphql/testing/matchers.d.ts +11 -0
- package/build/typescript/graphql/testing/matchers.d.ts.map +1 -0
- package/build/typescript/graphql/testing.d.ts +2 -1
- package/build/typescript/graphql/testing.d.ts.map +1 -1
- package/build/typescript/html/HTML.d.ts +5 -0
- package/build/typescript/html/HTML.d.ts.map +1 -0
- package/build/typescript/html.d.ts +3 -1
- package/build/typescript/html.d.ts.map +1 -1
- package/build/typescript/http.d.ts +1 -1
- package/build/typescript/http.d.ts.map +1 -1
- package/build/typescript/index.d.ts +1 -24
- package/build/typescript/index.d.ts.map +1 -1
- package/build/typescript/localize.d.ts +3 -0
- package/build/typescript/localize.d.ts.map +1 -0
- package/build/typescript/magic/assets.d.ts +4 -2
- package/build/typescript/magic/assets.d.ts.map +1 -1
- package/build/typescript/navigate/testing.d.ts +2 -0
- package/build/typescript/navigate/testing.d.ts.map +1 -0
- package/build/typescript/navigate.d.ts +3 -0
- package/build/typescript/navigate.d.ts.map +1 -0
- package/build/typescript/performance.d.ts +3 -0
- package/build/typescript/performance.d.ts.map +1 -0
- package/build/typescript/polyfills/fetch-get-set-cookie.d.ts +2 -0
- package/build/typescript/polyfills/fetch-get-set-cookie.d.ts.map +1 -0
- package/build/typescript/react/testing.d.ts +5 -0
- package/build/typescript/react/testing.d.ts.map +1 -0
- package/build/typescript/react/tools.d.ts +3 -0
- package/build/typescript/react/tools.d.ts.map +1 -0
- package/build/typescript/react-dom.d.ts +3 -0
- package/build/typescript/react-dom.d.ts.map +1 -0
- package/build/typescript/react.d.ts +3 -0
- package/build/typescript/react.d.ts.map +1 -0
- package/build/typescript/routing.d.ts +3 -0
- package/build/typescript/routing.d.ts.map +1 -0
- package/build/typescript/server/ServerContext.d.ts +2 -2
- package/build/typescript/server/request-router.d.ts +13 -37
- package/build/typescript/server/request-router.d.ts.map +1 -1
- package/build/typescript/server.d.ts +14 -0
- package/build/typescript/server.d.ts.map +1 -0
- package/build/typescript/signals.d.ts +3 -0
- package/build/typescript/signals.d.ts.map +1 -0
- package/build/typescript/static/StaticContext.d.ts +2 -2
- package/build/typescript/static/index.d.ts.map +1 -1
- package/build/typescript/static/render.d.ts +2 -2
- package/build/typescript/testing.d.ts +0 -4
- package/build/typescript/testing.d.ts.map +1 -1
- package/package.json +158 -54
- package/source/assets.ts +20 -2
- package/source/async.ts +17 -0
- package/source/events.ts +20 -0
- package/source/graphql/testing/matchers.ts +37 -0
- package/source/graphql/testing.ts +3 -2
- package/source/html/HTML.tsx +22 -0
- package/source/html.ts +15 -3
- package/source/http.ts +4 -0
- package/source/index.ts +1 -149
- package/source/localize.ts +21 -0
- package/source/magic/assets.ts +7 -4
- package/source/navigate/testing.ts +1 -0
- package/source/navigate.ts +24 -0
- package/source/performance.ts +12 -0
- package/source/polyfills/fetch-get-set-cookie.ts +1 -0
- package/source/react/testing.ts +30 -0
- package/source/react/tools.ts +2 -0
- package/source/routing.ts +24 -0
- package/source/server/ServerContext.tsx +3 -3
- package/source/server/preload.ts +2 -2
- package/source/server/request-router.tsx +281 -403
- package/source/{server/index.ts → server.ts} +20 -46
- package/source/signals.ts +12 -0
- package/source/static/StaticContext.tsx +3 -3
- package/source/static/index.tsx +40 -56
- package/source/static/render.tsx +2 -2
- package/source/testing.ts +0 -29
- package/build/cjs/App.cjs +0 -72
- package/build/cjs/TestApp.cjs +0 -20
- package/build/cjs/matchers.cjs +0 -4
- package/build/esm/App.mjs +0 -70
- package/build/esm/TestApp.mjs +0 -18
- package/build/esm/matchers.mjs +0 -1
- package/build/esm/server/index.mjs +0 -10
- package/build/esnext/App.esnext +0 -70
- package/build/esnext/TestApp.esnext +0 -18
- package/build/esnext/matchers.esnext +0 -1
- package/build/esnext/server/index.esnext +0 -10
- package/source/App.tsx +0 -162
- package/source/TestApp.tsx +0 -33
- package/source/matchers/graphql.ts +0 -24
- package/source/matchers.ts +0 -3
- /package/build/cjs/{global.cjs → globals.cjs} +0 -0
- /package/build/esm/{global.mjs → globals.mjs} +0 -0
- /package/build/esnext/{global.esnext → globals.esnext} +0 -0
- /package/source/{global.ts → globals.ts} +0 -0
- /package/source/{matchers/graphql → graphql/testing/matchers}/operations.ts +0 -0
- /package/source/{matchers/graphql → graphql/testing/matchers}/utilities.ts +0 -0
- /package/source/{react-dom/index.ts → react-dom.ts} +0 -0
- /package/source/{react/index.ts → react.ts} +0 -0
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {isValidElement, type ReactElement} from 'react';
|
|
2
|
+
import {renderToStaticMarkup} from 'react-dom/server';
|
|
2
3
|
|
|
3
4
|
import {
|
|
4
|
-
styleAssetAttributes,
|
|
5
5
|
styleAssetPreloadAttributes,
|
|
6
|
-
scriptAssetAttributes,
|
|
7
6
|
scriptAssetPreloadAttributes,
|
|
8
7
|
type AssetsCacheKey,
|
|
9
8
|
type BrowserAssets,
|
|
@@ -12,451 +11,313 @@ import {
|
|
|
12
11
|
import {AssetsManager} from '@quilted/react-assets/server';
|
|
13
12
|
import {HttpManager} from '@quilted/react-http/server';
|
|
14
13
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
Head,
|
|
15
|
+
Script,
|
|
16
|
+
ScriptPreload,
|
|
17
|
+
Style,
|
|
18
|
+
StylePreload,
|
|
19
|
+
HTMLManager,
|
|
19
20
|
} from '@quilted/react-html/server';
|
|
20
|
-
import type {
|
|
21
|
-
Options as ExtractOptions,
|
|
22
|
-
ServerRenderRequestContext,
|
|
23
|
-
} from '@quilted/react-server-render/server';
|
|
24
21
|
import {extract} from '@quilted/react-server-render/server';
|
|
25
22
|
|
|
26
|
-
import {
|
|
27
|
-
import type {
|
|
28
|
-
EnhancedRequest,
|
|
29
|
-
RequestHandler,
|
|
30
|
-
RequestContext,
|
|
31
|
-
} from '@quilted/request-router';
|
|
23
|
+
import {HTMLResponse, RedirectResponse} from '@quilted/request-router';
|
|
32
24
|
|
|
33
25
|
import {ServerContext} from './ServerContext.tsx';
|
|
34
26
|
|
|
35
|
-
export interface
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
request: EnhancedRequest,
|
|
46
|
-
context: Context,
|
|
47
|
-
) => ServerRenderRequestContext);
|
|
48
|
-
};
|
|
49
|
-
html?:
|
|
50
|
-
| ServerRenderHtmlRender<Context>
|
|
51
|
-
| {
|
|
52
|
-
readonly rootElement?: HtmlProps['rootElement'];
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export interface ServerRenderHtmlRender<Context> {
|
|
57
|
-
(
|
|
58
|
-
content: string | undefined,
|
|
59
|
-
details: Pick<ServerRenderAppDetails, 'http' | 'html'> & {
|
|
60
|
-
readonly request: EnhancedRequest;
|
|
61
|
-
readonly context: Context;
|
|
27
|
+
export interface RenderOptions<CacheKey = AssetsCacheKey> {
|
|
28
|
+
readonly request: Request;
|
|
29
|
+
readonly stream?: 'headers' | false;
|
|
30
|
+
readonly assets?: BrowserAssets<CacheKey>;
|
|
31
|
+
readonly cacheKey?: CacheKey;
|
|
32
|
+
waitUntil?(promise: Promise<any>): void;
|
|
33
|
+
renderHTML?(
|
|
34
|
+
content: ReadableStream<string>,
|
|
35
|
+
context: {
|
|
36
|
+
readonly manager: HTMLManager;
|
|
62
37
|
readonly assets?: BrowserAssetsEntry;
|
|
63
38
|
readonly preloadAssets?: BrowserAssetsEntry;
|
|
64
|
-
readonly rootElement?: HtmlProps['rootElement'];
|
|
65
39
|
},
|
|
66
|
-
):
|
|
40
|
+
): ReadableStream<any> | Promise<ReadableStream<any>>;
|
|
67
41
|
}
|
|
68
42
|
|
|
69
|
-
export
|
|
70
|
-
|
|
71
|
-
CacheKey
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
43
|
+
export async function renderToResponse<CacheKey = AssetsCacheKey>(
|
|
44
|
+
element: ReactElement<any>,
|
|
45
|
+
options: RenderOptions<CacheKey>,
|
|
46
|
+
): Promise<HTMLResponse | RedirectResponse>;
|
|
47
|
+
export async function renderToResponse<CacheKey = AssetsCacheKey>(
|
|
48
|
+
options: RenderOptions<CacheKey>,
|
|
49
|
+
): Promise<HTMLResponse | RedirectResponse>;
|
|
50
|
+
export async function renderToResponse<CacheKey = AssetsCacheKey>(
|
|
51
|
+
optionsOrElement: ReactElement<any> | RenderOptions<CacheKey>,
|
|
52
|
+
definitelyOptions?: RenderOptions<CacheKey>,
|
|
53
|
+
) {
|
|
54
|
+
let element: ReactElement<any> | undefined;
|
|
55
|
+
let options: RenderOptions<CacheKey>;
|
|
78
56
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
>(
|
|
83
|
-
getApp:
|
|
84
|
-
| ReactElement<any>
|
|
85
|
-
| ((
|
|
86
|
-
request: EnhancedRequest,
|
|
87
|
-
context: Context,
|
|
88
|
-
) =>
|
|
89
|
-
| ReactElement<any>
|
|
90
|
-
| undefined
|
|
91
|
-
| Promise<ReactElement<any> | undefined>),
|
|
92
|
-
options?: ServerRenderOptions<Context, CacheKey>,
|
|
93
|
-
): RequestHandler<Context>;
|
|
94
|
-
export function createServerRender<
|
|
95
|
-
Context = RequestContext,
|
|
96
|
-
CacheKey = AssetsCacheKey,
|
|
97
|
-
>(options?: ServerRenderOptions<Context, CacheKey>): RequestHandler<Context>;
|
|
98
|
-
export function createServerRender<
|
|
99
|
-
Context = RequestContext,
|
|
100
|
-
CacheKey = AssetsCacheKey,
|
|
101
|
-
>(
|
|
102
|
-
...args: [
|
|
103
|
-
(
|
|
104
|
-
| ReactElement<any>
|
|
105
|
-
| ((
|
|
106
|
-
request: EnhancedRequest,
|
|
107
|
-
context: Context,
|
|
108
|
-
) =>
|
|
109
|
-
| ReactElement<any>
|
|
110
|
-
| undefined
|
|
111
|
-
| Promise<ReactElement<any> | undefined>)
|
|
112
|
-
| ServerRenderOptions<Context, CacheKey>
|
|
113
|
-
| undefined
|
|
114
|
-
),
|
|
115
|
-
ServerRenderOptions<Context, CacheKey>?,
|
|
116
|
-
]
|
|
117
|
-
): RequestHandler<Context> {
|
|
118
|
-
let getApp:
|
|
119
|
-
| ReactElement<any>
|
|
120
|
-
| ((
|
|
121
|
-
request: EnhancedRequest,
|
|
122
|
-
context: Context,
|
|
123
|
-
) =>
|
|
124
|
-
| ReactElement<any>
|
|
125
|
-
| undefined
|
|
126
|
-
| Promise<ReactElement<any> | undefined>)
|
|
127
|
-
| undefined;
|
|
128
|
-
let options: ServerRenderOptions<Context, CacheKey>;
|
|
129
|
-
|
|
130
|
-
if (args.length > 1) {
|
|
131
|
-
getApp = args[0] as any;
|
|
132
|
-
options = (args[1] ?? {}) as any;
|
|
57
|
+
if (isValidElement(optionsOrElement)) {
|
|
58
|
+
element = optionsOrElement;
|
|
59
|
+
options = definitelyOptions!;
|
|
133
60
|
} else {
|
|
134
|
-
options =
|
|
61
|
+
options = optionsOrElement as any;
|
|
135
62
|
}
|
|
136
63
|
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
64
|
+
const {
|
|
65
|
+
request,
|
|
66
|
+
stream: shouldStream = false,
|
|
67
|
+
assets,
|
|
68
|
+
cacheKey: explicitCacheKey,
|
|
69
|
+
waitUntil = noop,
|
|
70
|
+
renderHTML,
|
|
71
|
+
} = options;
|
|
72
|
+
|
|
73
|
+
const baseUrl = (request as any).URL ?? new URL(request.url);
|
|
74
|
+
|
|
75
|
+
const cacheKey =
|
|
76
|
+
explicitCacheKey ??
|
|
77
|
+
(((await assets?.cacheKey?.(request)) ?? {}) as CacheKey);
|
|
78
|
+
|
|
79
|
+
const html = new HTMLManager();
|
|
80
|
+
const http = new HttpManager({headers: request.headers});
|
|
81
|
+
const assetsManager = new AssetsManager<CacheKey>({cacheKey});
|
|
82
|
+
|
|
83
|
+
let responseStatus = 200;
|
|
84
|
+
let appHeaders: Headers | undefined;
|
|
85
|
+
let appStream: ReadableStream<any> | undefined;
|
|
86
|
+
|
|
87
|
+
if (shouldStream === false && element != null) {
|
|
88
|
+
const rendered = await extract(element, {
|
|
89
|
+
decorate(element) {
|
|
90
|
+
return (
|
|
91
|
+
<ServerContext
|
|
92
|
+
http={http}
|
|
93
|
+
html={html}
|
|
94
|
+
url={baseUrl}
|
|
95
|
+
assets={assetsManager}
|
|
96
|
+
>
|
|
97
|
+
{element}
|
|
98
|
+
</ServerContext>
|
|
99
|
+
);
|
|
100
|
+
},
|
|
101
|
+
});
|
|
143
102
|
|
|
144
|
-
const
|
|
145
|
-
? renderAppToStreamedResponse
|
|
146
|
-
: renderAppToResponse;
|
|
103
|
+
const {headers, statusCode = 200, redirectUrl} = http.state;
|
|
147
104
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
{
|
|
153
|
-
...options,
|
|
105
|
+
if (redirectUrl) {
|
|
106
|
+
return new RedirectResponse(redirectUrl, {
|
|
107
|
+
status: statusCode as 301,
|
|
108
|
+
headers,
|
|
154
109
|
request,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
...options.extract,
|
|
158
|
-
context:
|
|
159
|
-
typeof options.extract?.context === 'function'
|
|
160
|
-
? options.extract.context(request, requestContext)
|
|
161
|
-
: options.extract?.context,
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
);
|
|
165
|
-
};
|
|
166
|
-
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
167
112
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
CacheKey = AssetsCacheKey,
|
|
171
|
-
>(
|
|
172
|
-
getApp:
|
|
173
|
-
| ReactElement<any>
|
|
174
|
-
| (() =>
|
|
175
|
-
| ReactElement<any>
|
|
176
|
-
| undefined
|
|
177
|
-
| Promise<ReactElement<any> | undefined>)
|
|
178
|
-
| undefined,
|
|
179
|
-
{
|
|
180
|
-
request,
|
|
181
|
-
context,
|
|
182
|
-
assets,
|
|
183
|
-
extract,
|
|
184
|
-
html: htmlOptions,
|
|
185
|
-
}: Pick<
|
|
186
|
-
ServerRenderOptions<Context, CacheKey>,
|
|
187
|
-
'assets' | 'html' | 'extract'
|
|
188
|
-
> & {readonly request: EnhancedRequest; readonly context: Context},
|
|
189
|
-
) {
|
|
190
|
-
const app = typeof getApp === 'function' ? await getApp() : getApp;
|
|
191
|
-
const cacheKey = (await assets?.cacheKey?.(request)) as CacheKey;
|
|
192
|
-
|
|
193
|
-
const renderDetails = await serverRenderDetailsForApp(app, {
|
|
194
|
-
extract,
|
|
195
|
-
cacheKey,
|
|
196
|
-
url: request.url,
|
|
197
|
-
headers: request.headers,
|
|
198
|
-
});
|
|
113
|
+
appHeaders = headers;
|
|
114
|
+
responseStatus = statusCode;
|
|
199
115
|
|
|
200
|
-
|
|
116
|
+
const appTransformStream = new TransformStream();
|
|
117
|
+
const appWriter = appTransformStream.writable.getWriter();
|
|
118
|
+
appStream = appTransformStream.readable;
|
|
201
119
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
status: statusCode as 301,
|
|
205
|
-
headers,
|
|
206
|
-
});
|
|
120
|
+
appWriter.write(rendered);
|
|
121
|
+
appWriter.close();
|
|
207
122
|
}
|
|
208
123
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
124
|
+
if (appStream == null) {
|
|
125
|
+
const appTransformStream = new TransformStream();
|
|
126
|
+
appStream = appTransformStream.readable;
|
|
127
|
+
|
|
128
|
+
const renderAppStream = async function renderAppStream() {
|
|
129
|
+
const appWriter = appTransformStream.writable.getWriter();
|
|
130
|
+
|
|
131
|
+
if (element != null) {
|
|
132
|
+
const rendered = await extract(element, {
|
|
133
|
+
decorate(element) {
|
|
134
|
+
return (
|
|
135
|
+
<ServerContext
|
|
136
|
+
http={http}
|
|
137
|
+
html={html}
|
|
138
|
+
url={baseUrl}
|
|
139
|
+
assets={assetsManager}
|
|
140
|
+
>
|
|
141
|
+
{element}
|
|
142
|
+
</ServerContext>
|
|
143
|
+
);
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
appWriter.write(rendered);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
appWriter.close();
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
waitUntil(renderAppStream());
|
|
154
|
+
}
|
|
218
155
|
|
|
219
|
-
|
|
156
|
+
const {headers, body} = await renderToHTMLStream(appStream);
|
|
157
|
+
|
|
158
|
+
return new HTMLResponse(body, {
|
|
159
|
+
status: responseStatus,
|
|
220
160
|
headers,
|
|
221
|
-
status: statusCode,
|
|
222
161
|
});
|
|
223
|
-
}
|
|
224
162
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
) {
|
|
247
|
-
|
|
248
|
-
|
|
163
|
+
async function renderToHTMLStream(content: ReadableStream<any>) {
|
|
164
|
+
const headers = new Headers(appHeaders);
|
|
165
|
+
|
|
166
|
+
const [synchronousAssets, preloadAssets] = await Promise.all([
|
|
167
|
+
assets?.entry({
|
|
168
|
+
cacheKey,
|
|
169
|
+
modules: assetsManager.usedModules({timing: 'load'}),
|
|
170
|
+
}),
|
|
171
|
+
assets?.modules(assetsManager.usedModules({timing: 'preload'}), {
|
|
172
|
+
cacheKey,
|
|
173
|
+
}),
|
|
174
|
+
]);
|
|
175
|
+
|
|
176
|
+
if (synchronousAssets) {
|
|
177
|
+
for (const style of synchronousAssets.styles) {
|
|
178
|
+
headers.append(
|
|
179
|
+
'Link',
|
|
180
|
+
preloadHeader(styleAssetPreloadAttributes(style)),
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
for (const script of synchronousAssets.scripts) {
|
|
185
|
+
headers.append(
|
|
186
|
+
'Link',
|
|
187
|
+
preloadHeader(scriptAssetPreloadAttributes(script)),
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
249
191
|
|
|
250
|
-
|
|
251
|
-
|
|
192
|
+
if (renderHTML) {
|
|
193
|
+
const body = await renderHTML(content, {
|
|
194
|
+
manager: html,
|
|
195
|
+
assets: synchronousAssets,
|
|
196
|
+
preloadAssets,
|
|
197
|
+
});
|
|
252
198
|
|
|
253
|
-
|
|
254
|
-
for (const style of guaranteedAssets.styles) {
|
|
255
|
-
headers.append('Link', preloadHeader(styleAssetPreloadAttributes(style)));
|
|
199
|
+
return {headers, body};
|
|
256
200
|
}
|
|
257
201
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
202
|
+
const responseStream = new TextEncoderStream();
|
|
203
|
+
const body = responseStream.readable;
|
|
204
|
+
|
|
205
|
+
const renderFullHTML = async function renderFullHTML() {
|
|
206
|
+
const writer = responseStream.writable.getWriter();
|
|
207
|
+
|
|
208
|
+
writer.write(`<!DOCTYPE html>`);
|
|
209
|
+
|
|
210
|
+
const {htmlAttributes, bodyAttributes, ...headProps} = html.state;
|
|
211
|
+
const htmlContent = renderToStaticMarkup(
|
|
212
|
+
// eslint-disable-next-line jsx-a11y/html-has-lang
|
|
213
|
+
<html {...htmlAttributes}>
|
|
214
|
+
<head>
|
|
215
|
+
<Head {...headProps} />
|
|
216
|
+
{synchronousAssets?.scripts.map((script) => (
|
|
217
|
+
<Script key={script.source} asset={script} baseUrl={baseUrl} />
|
|
218
|
+
))}
|
|
219
|
+
{synchronousAssets?.styles.map((style) => (
|
|
220
|
+
<Style key={style.source} asset={style} baseUrl={baseUrl} />
|
|
221
|
+
))}
|
|
222
|
+
{preloadAssets?.styles.map((style) => (
|
|
223
|
+
<StylePreload
|
|
224
|
+
key={style.source}
|
|
225
|
+
asset={style}
|
|
226
|
+
baseUrl={baseUrl}
|
|
227
|
+
/>
|
|
228
|
+
))}
|
|
229
|
+
{preloadAssets?.scripts.map((script) => (
|
|
230
|
+
<ScriptPreload
|
|
231
|
+
key={script.source}
|
|
232
|
+
asset={script}
|
|
233
|
+
baseUrl={baseUrl}
|
|
234
|
+
/>
|
|
235
|
+
))}
|
|
236
|
+
</head>
|
|
237
|
+
<body
|
|
238
|
+
{...bodyAttributes}
|
|
239
|
+
dangerouslySetInnerHTML={{__html: '%%CONTENT%%'}}
|
|
240
|
+
></body>
|
|
241
|
+
</html>,
|
|
262
242
|
);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
renderResponseToStream();
|
|
267
|
-
|
|
268
|
-
return html(stream.readable, {
|
|
269
|
-
headers,
|
|
270
|
-
status: 200,
|
|
271
|
-
});
|
|
272
243
|
|
|
273
|
-
|
|
274
|
-
|
|
244
|
+
const [firstChunk, secondChunk] = htmlContent.split('%%CONTENT%%');
|
|
245
|
+
writer.write(firstChunk);
|
|
246
|
+
if (element != null) writer.write(`<div id="app">`);
|
|
275
247
|
|
|
276
|
-
|
|
277
|
-
extract,
|
|
278
|
-
cacheKey,
|
|
279
|
-
url: request.url,
|
|
280
|
-
headers: request.headers,
|
|
281
|
-
});
|
|
248
|
+
const reader = content.getReader();
|
|
282
249
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
request,
|
|
287
|
-
context,
|
|
288
|
-
assets,
|
|
289
|
-
html: htmlOptions,
|
|
290
|
-
},
|
|
291
|
-
);
|
|
250
|
+
// eslint-disable-next-line no-constant-condition
|
|
251
|
+
while (true) {
|
|
252
|
+
const {done, value} = await reader.read();
|
|
292
253
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
await writer.close();
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
async function serverRenderDetailsForApp<
|
|
301
|
-
Context = RequestContext,
|
|
302
|
-
CacheKey = AssetsCacheKey,
|
|
303
|
-
>(
|
|
304
|
-
app: ReactElement<any> | undefined,
|
|
305
|
-
{
|
|
306
|
-
url,
|
|
307
|
-
headers,
|
|
308
|
-
cacheKey,
|
|
309
|
-
extract: extractOptions,
|
|
310
|
-
}: Pick<ServerRenderOptions, 'extract'> & {
|
|
311
|
-
url?: string | URL;
|
|
312
|
-
cacheKey?: CacheKey;
|
|
313
|
-
headers?: NonNullable<
|
|
314
|
-
ConstructorParameters<typeof HttpManager>[0]
|
|
315
|
-
>['headers'];
|
|
316
|
-
} = {},
|
|
317
|
-
): Promise<ServerRenderAppDetails<Context, CacheKey>> {
|
|
318
|
-
const html = new HtmlManager();
|
|
319
|
-
const http = new HttpManager({headers});
|
|
320
|
-
const assets = new AssetsManager<CacheKey>({cacheKey});
|
|
321
|
-
|
|
322
|
-
const {decorate, ...rest} = extractOptions ?? {};
|
|
323
|
-
|
|
324
|
-
const rendered = app
|
|
325
|
-
? await extract(app, {
|
|
326
|
-
decorate(app) {
|
|
327
|
-
return (
|
|
328
|
-
<ServerContext http={http} html={html} url={url} assets={assets}>
|
|
329
|
-
{decorate?.(app) ?? app}
|
|
330
|
-
</ServerContext>
|
|
331
|
-
);
|
|
332
|
-
},
|
|
333
|
-
...rest,
|
|
334
|
-
})
|
|
335
|
-
: undefined;
|
|
336
|
-
|
|
337
|
-
return {rendered, http, html, assets};
|
|
338
|
-
}
|
|
254
|
+
if (done) {
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
339
257
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
CacheKey = AssetsCacheKey,
|
|
343
|
-
>(
|
|
344
|
-
details: ServerRenderAppDetails<Context, CacheKey>,
|
|
345
|
-
{
|
|
346
|
-
request,
|
|
347
|
-
context,
|
|
348
|
-
assets,
|
|
349
|
-
html: htmlOptions,
|
|
350
|
-
}: Pick<ServerRenderOptions<Context, CacheKey>, 'assets' | 'html'> & {
|
|
351
|
-
readonly request: EnhancedRequest;
|
|
352
|
-
readonly context: Context;
|
|
353
|
-
readonly cacheKey?: Partial<CacheKey>;
|
|
354
|
-
},
|
|
355
|
-
) {
|
|
356
|
-
const {http, rendered, html: htmlManager, assets: assetsManager} = details;
|
|
258
|
+
writer.write(value);
|
|
259
|
+
}
|
|
357
260
|
|
|
358
|
-
|
|
359
|
-
const usedModules = assetsManager.usedModules({timing: 'load'});
|
|
261
|
+
if (element != null) writer.write(`</div>`);
|
|
360
262
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
assets.entry({modules: usedModules, cacheKey}),
|
|
364
|
-
assets.modules(assetsManager.usedModules({timing: 'preload'}), {
|
|
263
|
+
const [newSynchronousAssets, newPreloadAssets] = await Promise.all([
|
|
264
|
+
assets?.entry({
|
|
365
265
|
cacheKey,
|
|
266
|
+
modules: assetsManager.usedModules({timing: 'load'}),
|
|
366
267
|
}),
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
let rootElement: HtmlProps['rootElement'];
|
|
372
|
-
|
|
373
|
-
if (typeof htmlOptions === 'function') {
|
|
374
|
-
renderHtml = htmlOptions;
|
|
375
|
-
} else {
|
|
376
|
-
rootElement = htmlOptions?.rootElement;
|
|
377
|
-
renderHtml = defaultRenderHtml;
|
|
378
|
-
}
|
|
268
|
+
assets?.modules(assetsManager.usedModules({timing: 'preload'}), {
|
|
269
|
+
cacheKey,
|
|
270
|
+
}),
|
|
271
|
+
]);
|
|
379
272
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
assets: entryAssets,
|
|
386
|
-
preloadAssets,
|
|
387
|
-
rootElement,
|
|
388
|
-
});
|
|
273
|
+
if (newSynchronousAssets) {
|
|
274
|
+
const diffedSynchronousAssets = diffBrowserAssetsEntries(
|
|
275
|
+
newSynchronousAssets,
|
|
276
|
+
synchronousAssets!,
|
|
277
|
+
);
|
|
389
278
|
|
|
390
|
-
|
|
391
|
-
|
|
279
|
+
const diffedPreloadAssets = diffBrowserAssetsEntries(
|
|
280
|
+
newPreloadAssets!,
|
|
281
|
+
preloadAssets!,
|
|
282
|
+
);
|
|
392
283
|
|
|
393
|
-
const
|
|
394
|
-
function defaultRenderHtml(
|
|
395
|
-
content,
|
|
396
|
-
{request, html, assets, preloadAssets, rootElement},
|
|
397
|
-
) {
|
|
398
|
-
const baseUrl = new URL(request.url);
|
|
399
|
-
|
|
400
|
-
return (
|
|
401
|
-
<Html
|
|
402
|
-
manager={html}
|
|
403
|
-
rootElement={rootElement}
|
|
404
|
-
headEndContent={
|
|
284
|
+
const additionalAssetsContent = renderToStaticMarkup(
|
|
405
285
|
<>
|
|
406
|
-
{
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
{
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
return <link key={style.source} {...(attributes as any)} />;
|
|
443
|
-
})}
|
|
444
|
-
|
|
445
|
-
{preloadAssets &&
|
|
446
|
-
preloadAssets.scripts.map((script) => {
|
|
447
|
-
const attributes = scriptAssetPreloadAttributes(script, {
|
|
448
|
-
baseUrl,
|
|
449
|
-
});
|
|
450
|
-
|
|
451
|
-
return <link key={script.source} {...(attributes as any)} />;
|
|
452
|
-
})}
|
|
453
|
-
</>
|
|
454
|
-
}
|
|
455
|
-
>
|
|
456
|
-
{content}
|
|
457
|
-
</Html>
|
|
458
|
-
);
|
|
459
|
-
};
|
|
286
|
+
{diffedSynchronousAssets.scripts.map((script) => (
|
|
287
|
+
<Script key={script.source} asset={script} baseUrl={baseUrl} />
|
|
288
|
+
))}
|
|
289
|
+
{diffedSynchronousAssets.styles.map((style) => (
|
|
290
|
+
<Style key={style.source} asset={style} baseUrl={baseUrl} />
|
|
291
|
+
))}
|
|
292
|
+
{diffedPreloadAssets.styles.map((style) => (
|
|
293
|
+
<StylePreload
|
|
294
|
+
key={style.source}
|
|
295
|
+
asset={style}
|
|
296
|
+
baseUrl={baseUrl}
|
|
297
|
+
/>
|
|
298
|
+
))}
|
|
299
|
+
{diffedPreloadAssets.scripts.map((script) => (
|
|
300
|
+
<ScriptPreload
|
|
301
|
+
key={script.source}
|
|
302
|
+
asset={script}
|
|
303
|
+
baseUrl={baseUrl}
|
|
304
|
+
/>
|
|
305
|
+
))}
|
|
306
|
+
</>,
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
writer.write(additionalAssetsContent);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
writer.write(secondChunk);
|
|
313
|
+
writer.close();
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
waitUntil(renderFullHTML());
|
|
317
|
+
|
|
318
|
+
return {headers, body};
|
|
319
|
+
}
|
|
320
|
+
}
|
|
460
321
|
|
|
461
322
|
function preloadHeader(attributes: Partial<HTMLLinkElement>) {
|
|
462
323
|
const {
|
|
@@ -480,3 +341,20 @@ function preloadHeader(attributes: Partial<HTMLLinkElement>) {
|
|
|
480
341
|
|
|
481
342
|
return header;
|
|
482
343
|
}
|
|
344
|
+
|
|
345
|
+
function diffBrowserAssetsEntries(
|
|
346
|
+
newList: BrowserAssetsEntry,
|
|
347
|
+
oldList: BrowserAssetsEntry,
|
|
348
|
+
): BrowserAssetsEntry {
|
|
349
|
+
const oldStyles = new Set(oldList.styles.map((style) => style.source));
|
|
350
|
+
const oldScripts = new Set(oldList.scripts.map((script) => script.source));
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
styles: newList.styles.filter((style) => !oldStyles.has(style.source)),
|
|
354
|
+
scripts: newList.scripts.filter((script) => !oldScripts.has(script.source)),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function noop(..._args: any) {
|
|
359
|
+
// noop
|
|
360
|
+
}
|