@quilted/quilt 0.5.135 → 0.5.137
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 +18 -0
- package/build/cjs/App.cjs +4 -9
- package/build/cjs/index.cjs +46 -4
- package/build/cjs/server/ServerContext.cjs +6 -4
- package/build/cjs/server/index.cjs +30 -7
- package/build/cjs/server/preload.cjs +37 -0
- package/build/cjs/server/request-router.cjs +75 -54
- package/build/cjs/static/StaticContext.cjs +6 -4
- package/build/cjs/static/index.cjs +29 -42
- package/build/cjs/static/render.cjs +8 -2
- package/build/esm/App.mjs +5 -10
- package/build/esm/index.mjs +4 -2
- package/build/esm/server/ServerContext.mjs +3 -1
- package/build/esm/server/index.mjs +3 -1
- package/build/esm/server/preload.mjs +35 -0
- package/build/esm/server/request-router.mjs +57 -36
- package/build/esm/static/StaticContext.mjs +3 -1
- package/build/esm/static/index.mjs +24 -37
- package/build/esm/static/render.mjs +6 -0
- package/build/esnext/App.esnext +5 -10
- package/build/esnext/index.esnext +4 -2
- package/build/esnext/server/ServerContext.esnext +3 -1
- package/build/esnext/server/index.esnext +3 -1
- package/build/esnext/server/preload.esnext +35 -0
- package/build/esnext/server/request-router.esnext +57 -36
- package/build/esnext/static/StaticContext.esnext +3 -1
- package/build/esnext/static/index.esnext +24 -37
- package/build/esnext/static/render.esnext +6 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/typescript/App.d.ts.map +1 -1
- package/build/typescript/assets.d.ts +7 -0
- package/build/typescript/assets.d.ts.map +1 -0
- package/build/typescript/index.d.ts +5 -2
- package/build/typescript/index.d.ts.map +1 -1
- package/build/typescript/magic/assets.d.ts +3 -0
- package/build/typescript/magic/assets.d.ts.map +1 -0
- package/build/typescript/server/ServerContext.d.ts +3 -1
- package/build/typescript/server/ServerContext.d.ts.map +1 -1
- package/build/typescript/server/index.d.ts +4 -2
- package/build/typescript/server/index.d.ts.map +1 -1
- package/build/typescript/server/preload.d.ts +8 -0
- package/build/typescript/server/preload.d.ts.map +1 -0
- package/build/typescript/server/request-router.d.ts +23 -12
- package/build/typescript/server/request-router.d.ts.map +1 -1
- package/build/typescript/static/StaticContext.d.ts +3 -1
- package/build/typescript/static/StaticContext.d.ts.map +1 -1
- package/build/typescript/static/index.d.ts +3 -5
- package/build/typescript/static/index.d.ts.map +1 -1
- package/build/typescript/static/render.d.ts +6 -2
- package/build/typescript/static/render.d.ts.map +1 -1
- package/package.json +5 -3
- package/source/App.tsx +8 -17
- package/source/assets.ts +7 -0
- package/source/index.ts +23 -1
- package/source/magic/assets.ts +5 -0
- package/source/server/ServerContext.tsx +15 -7
- package/source/server/index.ts +19 -9
- package/source/server/preload.ts +69 -0
- package/source/server/request-router.tsx +135 -64
- package/source/static/StaticContext.tsx +15 -7
- package/source/static/index.tsx +26 -41
- package/source/static/render.tsx +8 -4
- package/tsconfig.json +2 -0
- package/build/typescript/AppContext.d.ts +0 -8
- package/build/typescript/AppContext.d.ts.map +0 -1
- package/build/typescript/email.d.ts +0 -3
- package/build/typescript/email.d.ts.map +0 -1
- package/build/typescript/http-handlers/index.d.ts +0 -2
- package/build/typescript/http-handlers/index.d.ts.map +0 -1
- package/build/typescript/http-handlers/node.d.ts +0 -2
- package/build/typescript/http-handlers/node.d.ts.map +0 -1
- package/build/typescript/magic/http-handler.d.ts +0 -4
- package/build/typescript/magic/http-handler.d.ts.map +0 -1
- package/build/typescript/server/http-handler.d.ts +0 -13
- package/build/typescript/server/http-handler.d.ts.map +0 -1
- package/build/typescript/server/render.d.ts +0 -17
- package/build/typescript/server/render.d.ts.map +0 -1
- package/source/magic/asset-manifest.ts +0 -5
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {Fragment, type ReactElement
|
|
1
|
+
import {Fragment, type ReactElement} from 'react';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
styleAssetAttributes,
|
|
5
5
|
styleAssetPreloadAttributes,
|
|
6
6
|
scriptAssetAttributes,
|
|
7
7
|
scriptAssetPreloadAttributes,
|
|
8
|
-
type
|
|
9
|
-
type
|
|
10
|
-
|
|
8
|
+
type AssetsCacheKey,
|
|
9
|
+
type BrowserAssets,
|
|
10
|
+
type BrowserAssetsEntry,
|
|
11
|
+
} from '@quilted/assets';
|
|
12
|
+
import {AssetsManager} from '@quilted/react-assets/server';
|
|
11
13
|
import {AsyncAssetManager} from '@quilted/react-async/server';
|
|
12
14
|
import {HttpManager} from '@quilted/react-http/server';
|
|
13
15
|
import {
|
|
@@ -30,39 +32,53 @@ import type {
|
|
|
30
32
|
|
|
31
33
|
import {ServerContext} from './ServerContext';
|
|
32
34
|
|
|
33
|
-
export interface ServerRenderOptions<
|
|
35
|
+
export interface ServerRenderOptions<
|
|
36
|
+
Context = RequestContext,
|
|
37
|
+
CacheKey = AssetsCacheKey,
|
|
38
|
+
> {
|
|
34
39
|
stream?: 'headers' | false;
|
|
35
|
-
assets?:
|
|
36
|
-
extract?: ExtractOptions
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
assets?: BrowserAssets<CacheKey>;
|
|
41
|
+
extract?: Omit<ExtractOptions, 'context'> & {
|
|
42
|
+
readonly context?:
|
|
43
|
+
| ServerRenderRequestContext
|
|
44
|
+
| ((
|
|
45
|
+
request: EnhancedRequest,
|
|
46
|
+
context: Context,
|
|
47
|
+
) => ServerRenderRequestContext);
|
|
48
|
+
};
|
|
41
49
|
renderHtml?(
|
|
42
50
|
content: string | undefined,
|
|
43
|
-
request: Request,
|
|
44
51
|
details: Pick<ServerRenderAppDetails, 'http' | 'html'> & {
|
|
45
|
-
readonly
|
|
46
|
-
readonly
|
|
52
|
+
readonly request: EnhancedRequest;
|
|
53
|
+
readonly context: Context;
|
|
54
|
+
readonly assets?: BrowserAssetsEntry;
|
|
55
|
+
readonly preloadAssets?: BrowserAssetsEntry;
|
|
47
56
|
},
|
|
48
57
|
): ReactElement<any> | Promise<ReactElement<any>>;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
|
-
export interface ServerRenderAppDetails
|
|
60
|
+
export interface ServerRenderAppDetails<
|
|
61
|
+
_Context = RequestContext,
|
|
62
|
+
CacheKey = AssetsCacheKey,
|
|
63
|
+
> {
|
|
52
64
|
readonly http: HttpManager;
|
|
53
65
|
readonly html: HtmlManager;
|
|
66
|
+
readonly assets: AssetsManager<CacheKey>;
|
|
54
67
|
readonly rendered?: string;
|
|
55
68
|
readonly asyncAssets: AsyncAssetManager;
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
export function createServerRender<
|
|
71
|
+
export function createServerRender<
|
|
72
|
+
Context = RequestContext,
|
|
73
|
+
CacheKey = AssetsCacheKey,
|
|
74
|
+
>(
|
|
59
75
|
getApp:
|
|
60
76
|
| ReactElement<any>
|
|
61
77
|
| ((
|
|
62
78
|
request: EnhancedRequest,
|
|
63
79
|
context: Context,
|
|
64
80
|
) => ReactElement<any> | Promise<ReactElement<any>>),
|
|
65
|
-
{
|
|
81
|
+
{stream, ...options}: ServerRenderOptions<Context, CacheKey> = {},
|
|
66
82
|
): RequestHandler<Context> {
|
|
67
83
|
return async (request, requestContext) => {
|
|
68
84
|
const accepts = request.headers.get('Accept');
|
|
@@ -77,36 +93,46 @@ export function createServerRender<Context = RequestContext>(
|
|
|
77
93
|
typeof getApp === 'function'
|
|
78
94
|
? () => getApp(request, requestContext)
|
|
79
95
|
: getApp,
|
|
80
|
-
request,
|
|
81
96
|
{
|
|
82
97
|
...options,
|
|
98
|
+
request,
|
|
99
|
+
context: requestContext,
|
|
83
100
|
extract: {
|
|
84
101
|
...options.extract,
|
|
85
102
|
context:
|
|
86
|
-
options.extract
|
|
87
|
-
|
|
88
|
-
|
|
103
|
+
typeof options.extract?.context === 'function'
|
|
104
|
+
? options.extract.context(request, requestContext)
|
|
105
|
+
: options.extract?.context,
|
|
89
106
|
},
|
|
90
107
|
},
|
|
91
108
|
);
|
|
92
109
|
};
|
|
93
110
|
}
|
|
94
111
|
|
|
95
|
-
export async function renderAppToResponse
|
|
112
|
+
export async function renderAppToResponse<
|
|
113
|
+
Context = RequestContext,
|
|
114
|
+
CacheKey = AssetsCacheKey,
|
|
115
|
+
>(
|
|
96
116
|
getApp:
|
|
97
117
|
| ReactElement<any>
|
|
98
118
|
| (() => ReactElement<any> | Promise<ReactElement<any>>),
|
|
99
|
-
request: Request,
|
|
100
119
|
{
|
|
120
|
+
request,
|
|
121
|
+
context,
|
|
101
122
|
assets,
|
|
102
123
|
extract,
|
|
103
124
|
renderHtml,
|
|
104
|
-
}: Pick<
|
|
125
|
+
}: Pick<
|
|
126
|
+
ServerRenderOptions<Context, CacheKey>,
|
|
127
|
+
'assets' | 'renderHtml' | 'extract'
|
|
128
|
+
> & {readonly request: EnhancedRequest; readonly context: Context},
|
|
105
129
|
) {
|
|
106
130
|
const app = typeof getApp === 'function' ? await getApp() : getApp;
|
|
131
|
+
const cacheKey = (await assets?.cacheKey?.(request)) as CacheKey;
|
|
107
132
|
|
|
108
133
|
const renderDetails = await serverRenderDetailsForApp(app, {
|
|
109
134
|
extract,
|
|
135
|
+
cacheKey,
|
|
110
136
|
url: request.url,
|
|
111
137
|
headers: request.headers,
|
|
112
138
|
});
|
|
@@ -120,10 +146,15 @@ export async function renderAppToResponse(
|
|
|
120
146
|
});
|
|
121
147
|
}
|
|
122
148
|
|
|
123
|
-
const content = await renderAppDetailsToHtmlString
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
149
|
+
const content = await renderAppDetailsToHtmlString<Context, CacheKey>(
|
|
150
|
+
renderDetails,
|
|
151
|
+
{
|
|
152
|
+
request,
|
|
153
|
+
context,
|
|
154
|
+
assets,
|
|
155
|
+
renderHtml,
|
|
156
|
+
},
|
|
157
|
+
);
|
|
127
158
|
|
|
128
159
|
return html(content, {
|
|
129
160
|
headers,
|
|
@@ -131,22 +162,29 @@ export async function renderAppToResponse(
|
|
|
131
162
|
});
|
|
132
163
|
}
|
|
133
164
|
|
|
134
|
-
export async function renderAppToStreamedResponse
|
|
165
|
+
export async function renderAppToStreamedResponse<
|
|
166
|
+
Context = RequestContext,
|
|
167
|
+
CacheKey = AssetsCacheKey,
|
|
168
|
+
>(
|
|
135
169
|
getApp:
|
|
136
170
|
| ReactElement<any>
|
|
137
171
|
| (() => ReactElement<any> | Promise<ReactElement<any>>),
|
|
138
|
-
request: Request,
|
|
139
172
|
{
|
|
173
|
+
request,
|
|
174
|
+
context,
|
|
140
175
|
assets,
|
|
141
176
|
extract,
|
|
142
177
|
renderHtml,
|
|
143
|
-
}: Pick<
|
|
178
|
+
}: Pick<
|
|
179
|
+
ServerRenderOptions<Context, CacheKey>,
|
|
180
|
+
'assets' | 'renderHtml' | 'extract'
|
|
181
|
+
> & {readonly request: EnhancedRequest; readonly context: Context},
|
|
144
182
|
) {
|
|
145
183
|
const headers = new Headers();
|
|
146
184
|
const stream = new TransformStream();
|
|
147
185
|
|
|
148
|
-
const
|
|
149
|
-
const guaranteedAssets = await assets?.
|
|
186
|
+
const cacheKey = (await assets?.cacheKey?.(request)) as CacheKey;
|
|
187
|
+
const guaranteedAssets = await assets?.entry({cacheKey});
|
|
150
188
|
|
|
151
189
|
if (guaranteedAssets) {
|
|
152
190
|
for (const style of guaranteedAssets.styles) {
|
|
@@ -173,14 +211,20 @@ export async function renderAppToStreamedResponse(
|
|
|
173
211
|
|
|
174
212
|
const renderDetails = await serverRenderDetailsForApp(app, {
|
|
175
213
|
extract,
|
|
214
|
+
cacheKey,
|
|
176
215
|
url: request.url,
|
|
177
216
|
headers: request.headers,
|
|
178
217
|
});
|
|
179
218
|
|
|
180
|
-
const content = await renderAppDetailsToHtmlString
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
219
|
+
const content = await renderAppDetailsToHtmlString<Context, CacheKey>(
|
|
220
|
+
renderDetails,
|
|
221
|
+
{
|
|
222
|
+
request,
|
|
223
|
+
context,
|
|
224
|
+
assets,
|
|
225
|
+
renderHtml,
|
|
226
|
+
},
|
|
227
|
+
);
|
|
184
228
|
|
|
185
229
|
const encoder = new TextEncoder();
|
|
186
230
|
const writer = stream.writable.getWriter();
|
|
@@ -189,22 +233,28 @@ export async function renderAppToStreamedResponse(
|
|
|
189
233
|
}
|
|
190
234
|
}
|
|
191
235
|
|
|
192
|
-
async function serverRenderDetailsForApp
|
|
236
|
+
async function serverRenderDetailsForApp<
|
|
237
|
+
Context = RequestContext,
|
|
238
|
+
CacheKey = AssetsCacheKey,
|
|
239
|
+
>(
|
|
193
240
|
app: ReactElement<any>,
|
|
194
241
|
{
|
|
195
242
|
url,
|
|
196
243
|
headers,
|
|
244
|
+
cacheKey,
|
|
197
245
|
extract: extractOptions,
|
|
198
246
|
}: Pick<ServerRenderOptions, 'extract'> & {
|
|
199
247
|
url?: string | URL;
|
|
248
|
+
cacheKey?: CacheKey;
|
|
200
249
|
headers?: NonNullable<
|
|
201
250
|
ConstructorParameters<typeof HttpManager>[0]
|
|
202
251
|
>['headers'];
|
|
203
252
|
} = {},
|
|
204
|
-
): Promise<ServerRenderAppDetails
|
|
253
|
+
): Promise<ServerRenderAppDetails<Context, CacheKey>> {
|
|
205
254
|
const html = new HtmlManager();
|
|
206
255
|
const asyncAssets = new AsyncAssetManager();
|
|
207
256
|
const http = new HttpManager({headers});
|
|
257
|
+
const assets = new AssetsManager<CacheKey>({cacheKey});
|
|
208
258
|
|
|
209
259
|
const {decorate, ...rest} = extractOptions ?? {};
|
|
210
260
|
|
|
@@ -216,6 +266,7 @@ async function serverRenderDetailsForApp(
|
|
|
216
266
|
http={http}
|
|
217
267
|
html={html}
|
|
218
268
|
url={url}
|
|
269
|
+
assets={assets}
|
|
219
270
|
>
|
|
220
271
|
{decorate?.(app) ?? app}
|
|
221
272
|
</ServerContext>
|
|
@@ -224,32 +275,48 @@ async function serverRenderDetailsForApp(
|
|
|
224
275
|
...rest,
|
|
225
276
|
});
|
|
226
277
|
|
|
227
|
-
return {rendered, http, html, asyncAssets};
|
|
278
|
+
return {rendered, http, html, asyncAssets, assets};
|
|
228
279
|
}
|
|
229
280
|
|
|
230
|
-
async function renderAppDetailsToHtmlString
|
|
231
|
-
|
|
232
|
-
|
|
281
|
+
async function renderAppDetailsToHtmlString<
|
|
282
|
+
Context = RequestContext,
|
|
283
|
+
CacheKey = AssetsCacheKey,
|
|
284
|
+
>(
|
|
285
|
+
details: ServerRenderAppDetails<Context, CacheKey>,
|
|
233
286
|
{
|
|
287
|
+
request,
|
|
288
|
+
context,
|
|
234
289
|
assets,
|
|
235
290
|
renderHtml = defaultRenderHtml,
|
|
236
|
-
}: Pick<ServerRenderOptions, 'assets' | 'renderHtml'>
|
|
291
|
+
}: Pick<ServerRenderOptions<Context, CacheKey>, 'assets' | 'renderHtml'> & {
|
|
292
|
+
readonly request: EnhancedRequest;
|
|
293
|
+
readonly context: Context;
|
|
294
|
+
readonly cacheKey?: Partial<CacheKey>;
|
|
295
|
+
},
|
|
237
296
|
) {
|
|
238
|
-
const {
|
|
297
|
+
const {
|
|
298
|
+
http,
|
|
299
|
+
rendered,
|
|
300
|
+
asyncAssets,
|
|
301
|
+
html: htmlManager,
|
|
302
|
+
assets: assetsManager,
|
|
303
|
+
} = details;
|
|
239
304
|
|
|
240
|
-
const
|
|
241
|
-
const
|
|
305
|
+
const usedModules = asyncAssets.used({timing: 'load'});
|
|
306
|
+
const cacheKey = assetsManager.cacheKey as CacheKey;
|
|
242
307
|
|
|
243
308
|
const [entryAssets, preloadAssets] = assets
|
|
244
309
|
? await Promise.all([
|
|
245
|
-
assets.
|
|
246
|
-
assets.
|
|
247
|
-
|
|
310
|
+
assets.entry({modules: usedModules, cacheKey}),
|
|
311
|
+
assets.modules(asyncAssets.used({timing: 'preload'}), {
|
|
312
|
+
cacheKey,
|
|
248
313
|
}),
|
|
249
314
|
])
|
|
250
315
|
: [];
|
|
251
316
|
|
|
252
|
-
const htmlElement = await renderHtml(rendered,
|
|
317
|
+
const htmlElement = await renderHtml(rendered, {
|
|
318
|
+
request,
|
|
319
|
+
context,
|
|
253
320
|
html: htmlManager,
|
|
254
321
|
http,
|
|
255
322
|
assets: entryAssets,
|
|
@@ -260,7 +327,7 @@ async function renderAppDetailsToHtmlString(
|
|
|
260
327
|
}
|
|
261
328
|
|
|
262
329
|
const defaultRenderHtml: NonNullable<ServerRenderOptions<any>['renderHtml']> =
|
|
263
|
-
function defaultRenderHtml(content, request,
|
|
330
|
+
function defaultRenderHtml(content, {request, html, assets, preloadAssets}) {
|
|
264
331
|
const baseUrl = new URL(request.url);
|
|
265
332
|
|
|
266
333
|
return (
|
|
@@ -269,14 +336,14 @@ const defaultRenderHtml: NonNullable<ServerRenderOptions<any>['renderHtml']> =
|
|
|
269
336
|
headEndContent={
|
|
270
337
|
<>
|
|
271
338
|
{assets &&
|
|
272
|
-
|
|
339
|
+
assets.styles.map((style) => {
|
|
273
340
|
const attributes = styleAssetAttributes(style, {baseUrl});
|
|
274
|
-
return <link key={style.source} {...attributes} />;
|
|
341
|
+
return <link key={style.source} {...(attributes as any)} />;
|
|
275
342
|
})}
|
|
276
343
|
|
|
277
344
|
{assets &&
|
|
278
|
-
|
|
279
|
-
const isModule = script.attributes
|
|
345
|
+
assets.scripts.map((script) => {
|
|
346
|
+
const isModule = script.attributes?.type === 'module';
|
|
280
347
|
|
|
281
348
|
const attributes = scriptAssetAttributes(script, {
|
|
282
349
|
baseUrl,
|
|
@@ -285,31 +352,35 @@ const defaultRenderHtml: NonNullable<ServerRenderOptions<any>['renderHtml']> =
|
|
|
285
352
|
if (isModule) {
|
|
286
353
|
return (
|
|
287
354
|
<Fragment key={script.source}>
|
|
288
|
-
<link
|
|
289
|
-
|
|
355
|
+
<link
|
|
356
|
+
{...(scriptAssetPreloadAttributes(script) as any)}
|
|
357
|
+
/>
|
|
358
|
+
<script {...(attributes as any)} async />
|
|
290
359
|
</Fragment>
|
|
291
360
|
);
|
|
292
361
|
}
|
|
293
362
|
|
|
294
|
-
return
|
|
363
|
+
return (
|
|
364
|
+
<script key={script.source} {...(attributes as any)} defer />
|
|
365
|
+
);
|
|
295
366
|
})}
|
|
296
367
|
|
|
297
368
|
{preloadAssets &&
|
|
298
|
-
|
|
369
|
+
preloadAssets.styles.map((style) => {
|
|
299
370
|
const attributes = styleAssetPreloadAttributes(style, {
|
|
300
371
|
baseUrl,
|
|
301
372
|
});
|
|
302
373
|
|
|
303
|
-
return <link key={style.source} {...attributes} />;
|
|
374
|
+
return <link key={style.source} {...(attributes as any)} />;
|
|
304
375
|
})}
|
|
305
376
|
|
|
306
377
|
{preloadAssets &&
|
|
307
|
-
|
|
378
|
+
preloadAssets.scripts.map((script) => {
|
|
308
379
|
const attributes = scriptAssetPreloadAttributes(script, {
|
|
309
380
|
baseUrl,
|
|
310
381
|
});
|
|
311
382
|
|
|
312
|
-
return <link key={script.source} {...attributes} />;
|
|
383
|
+
return <link key={script.source} {...(attributes as any)} />;
|
|
313
384
|
})}
|
|
314
385
|
</>
|
|
315
386
|
}
|
|
@@ -319,7 +390,7 @@ const defaultRenderHtml: NonNullable<ServerRenderOptions<any>['renderHtml']> =
|
|
|
319
390
|
);
|
|
320
391
|
};
|
|
321
392
|
|
|
322
|
-
function preloadHeader(attributes:
|
|
393
|
+
function preloadHeader(attributes: Partial<HTMLLinkElement>) {
|
|
323
394
|
const {
|
|
324
395
|
as,
|
|
325
396
|
rel = 'preload',
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type {PropsWithChildren} from 'react';
|
|
2
2
|
|
|
3
|
+
import {AssetsContext} from '@quilted/react-assets/server';
|
|
4
|
+
import type {AssetsManager} from '@quilted/react-assets/server';
|
|
3
5
|
import {InitialUrlContext} from '@quilted/react-router';
|
|
4
6
|
import {HtmlContext} from '@quilted/react-html/server';
|
|
5
7
|
import type {HtmlManager} from '@quilted/react-html/server';
|
|
@@ -14,6 +16,7 @@ interface Props {
|
|
|
14
16
|
url?: string | URL;
|
|
15
17
|
html?: HtmlManager;
|
|
16
18
|
http?: HttpManager;
|
|
19
|
+
assets?: AssetsManager;
|
|
17
20
|
asyncAssets?: AsyncAssetManager;
|
|
18
21
|
}
|
|
19
22
|
|
|
@@ -21,21 +24,26 @@ export function StaticContext({
|
|
|
21
24
|
url,
|
|
22
25
|
html,
|
|
23
26
|
http,
|
|
27
|
+
assets,
|
|
24
28
|
asyncAssets,
|
|
25
29
|
children,
|
|
26
30
|
}: PropsWithChildren<Props>) {
|
|
27
31
|
const normalizedUrl = typeof url === 'string' ? new URL(url) : url;
|
|
28
32
|
|
|
29
33
|
return maybeWrapContext(
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
AssetsContext,
|
|
35
|
+
assets,
|
|
32
36
|
maybeWrapContext(
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
AsyncAssetContext,
|
|
38
|
+
asyncAssets,
|
|
35
39
|
maybeWrapContext(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
maybeWrapContext(
|
|
40
|
+
HttpServerContext,
|
|
41
|
+
http,
|
|
42
|
+
maybeWrapContext(
|
|
43
|
+
HtmlContext,
|
|
44
|
+
html,
|
|
45
|
+
maybeWrapContext(InitialUrlContext, normalizedUrl, children),
|
|
46
|
+
),
|
|
39
47
|
),
|
|
40
48
|
),
|
|
41
49
|
);
|
package/source/static/index.tsx
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import {Fragment, type ComponentType} from 'react';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
styleAssetAttributes,
|
|
5
5
|
styleAssetPreloadAttributes,
|
|
6
6
|
scriptAssetAttributes,
|
|
7
7
|
scriptAssetPreloadAttributes,
|
|
8
|
-
type
|
|
9
|
-
} from '@quilted/
|
|
8
|
+
type BrowserAssets,
|
|
9
|
+
} from '@quilted/assets';
|
|
10
10
|
import {renderHtmlToString, Html} from '@quilted/react-html/server';
|
|
11
11
|
import type {RouteDefinition} from '@quilted/react-router';
|
|
12
12
|
import {
|
|
@@ -32,7 +32,7 @@ interface RenderableRoute {
|
|
|
32
32
|
|
|
33
33
|
export interface Options {
|
|
34
34
|
routes: string[];
|
|
35
|
-
assets:
|
|
35
|
+
assets: BrowserAssets<any>;
|
|
36
36
|
crawl?: boolean;
|
|
37
37
|
baseUrl?: string;
|
|
38
38
|
prettify?: boolean;
|
|
@@ -212,13 +212,17 @@ export async function renderStatic(
|
|
|
212
212
|
forceFallback: fallback ? url.pathname : undefined,
|
|
213
213
|
});
|
|
214
214
|
|
|
215
|
+
const initialCacheKey = await assets.cacheKey?.(new Request(url));
|
|
216
|
+
|
|
215
217
|
const {
|
|
216
218
|
http,
|
|
217
219
|
html: htmlManager,
|
|
220
|
+
assets: assetsManager,
|
|
218
221
|
markup,
|
|
219
222
|
asyncAssets,
|
|
220
223
|
} = await renderApp(<App />, {
|
|
221
224
|
url,
|
|
225
|
+
cacheKey: initialCacheKey,
|
|
222
226
|
decorate(app) {
|
|
223
227
|
return (
|
|
224
228
|
<StaticRendererContext.Provider value={routeRecorder}>
|
|
@@ -228,71 +232,52 @@ export async function renderStatic(
|
|
|
228
232
|
},
|
|
229
233
|
});
|
|
230
234
|
|
|
231
|
-
const
|
|
235
|
+
const cacheKey = assetsManager.cacheKey;
|
|
232
236
|
|
|
233
|
-
const [
|
|
234
|
-
assets.
|
|
235
|
-
assets.
|
|
236
|
-
context: {modules: true},
|
|
237
|
-
}),
|
|
238
|
-
assets.assets({async: usedAssets, context: {modules: false}}),
|
|
237
|
+
const [mainAssets, preloadAssets] = await Promise.all([
|
|
238
|
+
assets.entry({modules: asyncAssets.used({timing: 'load'}), cacheKey}),
|
|
239
|
+
assets.modules(asyncAssets.used({timing: 'preload'}), {cacheKey}),
|
|
239
240
|
]);
|
|
240
241
|
|
|
241
|
-
// We don’t want to load styles from both bundles, so we only use module styles,
|
|
242
|
-
// since modules are intended to be the default and CSS (usually) doesn’t
|
|
243
|
-
// have features that meaningfully break older user agents.
|
|
244
|
-
const styles =
|
|
245
|
-
moduleAssets.styles.length > 0
|
|
246
|
-
? moduleAssets.styles
|
|
247
|
-
: nomoduleAssets.styles;
|
|
248
|
-
|
|
249
242
|
const minifiedHtml = renderHtmlToString(
|
|
250
243
|
<Html
|
|
251
244
|
manager={htmlManager}
|
|
252
245
|
headEndContent={
|
|
253
246
|
<>
|
|
254
|
-
{[...styles].map((style) => {
|
|
247
|
+
{[...mainAssets.styles].map((style) => {
|
|
255
248
|
const attributes = styleAssetAttributes(style, {baseUrl: url});
|
|
256
|
-
return <link key={style.source} {...attributes} />;
|
|
257
|
-
})}
|
|
258
|
-
|
|
259
|
-
{[...moduleAssets.scripts].map((script) => {
|
|
260
|
-
const attributes = scriptAssetAttributes(script, {
|
|
261
|
-
baseUrl: url,
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
return <script key={script.source} {...attributes} />;
|
|
249
|
+
return <link key={style.source} {...(attributes as any)} />;
|
|
265
250
|
})}
|
|
266
251
|
|
|
267
|
-
{[...
|
|
252
|
+
{[...mainAssets.scripts].map((script) => {
|
|
268
253
|
const attributes = scriptAssetAttributes(script, {
|
|
269
254
|
baseUrl: url,
|
|
270
255
|
});
|
|
271
256
|
|
|
272
|
-
return (
|
|
273
|
-
<script
|
|
274
|
-
|
|
275
|
-
{...attributes}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
/>
|
|
257
|
+
return attributes.type === 'module' ? (
|
|
258
|
+
<Fragment key={script.source}>
|
|
259
|
+
<link {...(scriptAssetPreloadAttributes(script) as any)} />
|
|
260
|
+
<script {...(attributes as any)} />
|
|
261
|
+
</Fragment>
|
|
262
|
+
) : (
|
|
263
|
+
<script key={script.source} {...(attributes as any)} />
|
|
279
264
|
);
|
|
280
265
|
})}
|
|
281
266
|
|
|
282
|
-
{[...
|
|
267
|
+
{[...preloadAssets.styles].map((style) => {
|
|
283
268
|
const attributes = styleAssetPreloadAttributes(style, {
|
|
284
269
|
baseUrl: url,
|
|
285
270
|
});
|
|
286
271
|
|
|
287
|
-
return <link key={style.source} {...attributes} />;
|
|
272
|
+
return <link key={style.source} {...(attributes as any)} />;
|
|
288
273
|
})}
|
|
289
274
|
|
|
290
|
-
{[...
|
|
275
|
+
{[...preloadAssets.scripts].map((script) => {
|
|
291
276
|
const attributes = scriptAssetPreloadAttributes(script, {
|
|
292
277
|
baseUrl: url,
|
|
293
278
|
});
|
|
294
279
|
|
|
295
|
-
return <link key={script.source} {...attributes} />;
|
|
280
|
+
return <link key={script.source} {...(attributes as any)} />;
|
|
296
281
|
})}
|
|
297
282
|
</>
|
|
298
283
|
}
|
package/source/static/render.tsx
CHANGED
|
@@ -5,23 +5,27 @@ import type {Options as ExtractOptions} from '@quilted/react-server-render/serve
|
|
|
5
5
|
import {HtmlManager} from '@quilted/react-html/server';
|
|
6
6
|
import {HttpManager} from '@quilted/react-http/server';
|
|
7
7
|
import {AsyncAssetManager} from '@quilted/react-async/server';
|
|
8
|
+
import {AssetsManager} from '@quilted/react-assets/server';
|
|
9
|
+
import type {AssetsCacheKey} from '@quilted/assets';
|
|
8
10
|
|
|
9
11
|
import {StaticContext} from './StaticContext';
|
|
10
12
|
|
|
11
|
-
interface Options extends ExtractOptions {
|
|
13
|
+
interface Options<CacheKey = AssetsCacheKey> extends ExtractOptions {
|
|
12
14
|
url?: string | URL;
|
|
15
|
+
cacheKey?: CacheKey;
|
|
13
16
|
headers?: NonNullable<
|
|
14
17
|
ConstructorParameters<typeof HttpManager>[0]
|
|
15
18
|
>['headers'];
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
export async function renderApp(
|
|
21
|
+
export async function renderApp<CacheKey = AssetsCacheKey>(
|
|
19
22
|
app: ReactElement<any>,
|
|
20
|
-
{decorate, url, headers, ...rest}: Options = {},
|
|
23
|
+
{decorate, url, headers, cacheKey, ...rest}: Options<CacheKey> = {},
|
|
21
24
|
) {
|
|
22
25
|
const html = new HtmlManager();
|
|
23
26
|
const asyncAssets = new AsyncAssetManager();
|
|
24
27
|
const http = new HttpManager({headers});
|
|
28
|
+
const assets = new AssetsManager<CacheKey>({cacheKey});
|
|
25
29
|
|
|
26
30
|
const markup = await extract(app, {
|
|
27
31
|
decorate(app) {
|
|
@@ -39,5 +43,5 @@ export async function renderApp(
|
|
|
39
43
|
...rest,
|
|
40
44
|
});
|
|
41
45
|
|
|
42
|
-
return {markup, http, html, asyncAssets};
|
|
46
|
+
return {markup, http, html, assets, asyncAssets};
|
|
43
47
|
}
|
package/tsconfig.json
CHANGED
|
@@ -7,11 +7,13 @@
|
|
|
7
7
|
"include": ["source"],
|
|
8
8
|
"exclude": ["quilt.project.ts", "**/*.test.ts", "**/*.test.tsx"],
|
|
9
9
|
"references": [
|
|
10
|
+
{"path": "../assets"},
|
|
10
11
|
{"path": "../async"},
|
|
11
12
|
{"path": "../events"},
|
|
12
13
|
{"path": "../graphql"},
|
|
13
14
|
{"path": "../polyfills"},
|
|
14
15
|
{"path": "../react"},
|
|
16
|
+
{"path": "../react-assets"},
|
|
15
17
|
{"path": "../react-async"},
|
|
16
18
|
{"path": "../react-dom"},
|
|
17
19
|
{"path": "../react-graphql"},
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { PropsWithChildren } from 'react';
|
|
2
|
-
import type { Performance } from '@quilted/react-performance';
|
|
3
|
-
interface Props {
|
|
4
|
-
performance?: Performance;
|
|
5
|
-
}
|
|
6
|
-
export declare function AppContext({ children }: PropsWithChildren<Props>): JSX.Element;
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=AppContext.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AppContext.d.ts","sourceRoot":"","sources":["../../source/AppContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,OAAO,CAAC;AAI7C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,4BAA4B,CAAC;AAE5D,UAAU,KAAK;IACb,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAID,wBAAgB,UAAU,CAAC,EAAC,QAAQ,EAAC,EAAE,iBAAiB,CAAC,KAAK,CAAC,eAQ9D"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"email.d.ts","sourceRoot":"","sources":["../../source/email.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,SAAS,EACT,UAAU,EACV,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAC,MAAM,EAAC,MAAM,sBAAsB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/http-handlers/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../../source/http-handlers/node.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC"}
|