@quilted/quilt 0.8.6 → 0.8.8

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.
@@ -1 +1 @@
1
- {"version":3,"file":"request-router.d.ts","sourceRoot":"","sources":["../../../source/server/request-router.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,KAAK,EAAW,MAAM,QAAQ,CAAC;AAM5D,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,eAAe,EAKhB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAe,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAIvE,MAAM,WAAW,kBAAkB;IACjC,CACE,OAAO,EAAE,cAAc,CAAC,MAAM,CAAC,EAC/B,OAAO,EAAE;QACP,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;KACpC,GACA,cAAc,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,kBAAkB,CAAC;IAC7E,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;CACzC;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,EACnB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAC7B,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"request-router.d.ts","sourceRoot":"","sources":["../../../source/server/request-router.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,KAAK,EAAC,MAAM,QAAQ,CAAC;AAMlD,OAAO,EAGL,KAAK,aAAa,EAEnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAKL,eAAe,EAMhB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAe,gBAAgB,EAAC,MAAM,yBAAyB,CAAC;AAIvE,MAAM,WAAW,kBAAkB;IACjC,CACE,OAAO,EAAE,cAAc,CAAC,MAAM,CAAC,EAC/B,OAAO,EAAE;QACP,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;KACpC,GACA,cAAc,CAAC,GAAG,CAAC,GAAG,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC;IACpC,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,kBAAkB,CAAC;IAC7E,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;CACzC;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,EACnB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAC7B,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CAAC"}
@@ -5,8 +5,4 @@ export * from '@quilted/assets';
5
5
  export { parseAcceptLanguageHeader } from '@quilted/preact-localize';
6
6
  declare function noopCreateRequestRouterLocalization(): void;
7
7
  export { noopCreateRequestRouterLocalization as createRequestRouterLocalization };
8
- declare function noopRenderToResponse(): void;
9
- export { noopRenderToResponse as renderToResponse };
10
- declare function NoopServerContext(): null;
11
- export { NoopServerContext as ServerContext };
12
8
  //# sourceMappingURL=server.browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.browser.d.ts","sourceRoot":"","sources":["../../source/server.browser.ts"],"names":[],"mappings":"AAAA,iBAAS,kBAAkB,SAAK;AAEhC,OAAO,EACL,kBAAkB,IAAI,cAAc,EACpC,kBAAkB,IAAI,mBAAmB,EACzC,kBAAkB,IAAI,oBAAoB,GAC3C,CAAC;AACF,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC;AAEhC,OAAO,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAEnE,iBAAS,mCAAmC,SAAK;AACjD,OAAO,EAAC,mCAAmC,IAAI,+BAA+B,EAAC,CAAC;AAEhF,iBAAS,oBAAoB,SAAK;AAClC,OAAO,EAAC,oBAAoB,IAAI,gBAAgB,EAAC,CAAC;AAElD,iBAAS,iBAAiB,SAEzB;AACD,OAAO,EAAC,iBAAiB,IAAI,aAAa,EAAC,CAAC"}
1
+ {"version":3,"file":"server.browser.d.ts","sourceRoot":"","sources":["../../source/server.browser.ts"],"names":[],"mappings":"AAAA,iBAAS,kBAAkB,SAAK;AAEhC,OAAO,EACL,kBAAkB,IAAI,cAAc,EACpC,kBAAkB,IAAI,mBAAmB,EACzC,kBAAkB,IAAI,oBAAoB,GAC3C,CAAC;AACF,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC;AAEhC,OAAO,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAEnE,iBAAS,mCAAmC,SAAK;AACjD,OAAO,EAAC,mCAAmC,IAAI,+BAA+B,EAAC,CAAC"}
@@ -3,6 +3,4 @@ export * from '@quilted/preact-browser/server';
3
3
  export * from '@quilted/assets';
4
4
  export { parseAcceptLanguageHeader } from '@quilted/preact-localize';
5
5
  export { createRequestRouterLocalization } from '@quilted/preact-localize/request-router';
6
- export { renderToResponse, type RenderToResponseOptions, type RenderHTMLFunction, } from './server/request-router.tsx';
7
- export { ServerContext } from './server/ServerContext.tsx';
8
6
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../source/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC;AAEhC,OAAO,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAC,+BAA+B,EAAC,MAAM,yCAAyC,CAAC;AAExF,OAAO,EACL,gBAAgB,EAChB,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,GACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAC,aAAa,EAAC,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../source/server.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iBAAiB,CAAC;AAEhC,OAAO,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAC,+BAA+B,EAAC,MAAM,yCAAyC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@quilted/quilt",
3
3
  "type": "module",
4
- "version": "0.8.6",
4
+ "version": "0.8.8",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/lemonmade/quilt.git",
@@ -241,26 +241,26 @@
241
241
  "./build/esm/signals.mjs"
242
242
  ],
243
243
  "dependencies": {
244
- "@quilted/assets": "^0.1.5",
244
+ "@quilted/assets": "^0.1.6",
245
245
  "@quilted/async": "^0.4.22",
246
246
  "@quilted/events": "^2.1.1",
247
247
  "@quilted/graphql": "^3.3.8",
248
248
  "@quilted/preact-async": "^0.1.2",
249
- "@quilted/preact-browser": "^0.1.10",
249
+ "@quilted/preact-browser": "^0.1.12",
250
250
  "@quilted/preact-context": "^0.1.2",
251
251
  "@quilted/preact-graphql": "^0.1.0",
252
- "@quilted/preact-localize": "^0.3.0",
252
+ "@quilted/preact-localize": "^0.3.4",
253
253
  "@quilted/preact-performance": "^0.1.0",
254
254
  "@quilted/preact-router": "^0.2.10",
255
255
  "@quilted/preact-signals": "^0.1.0",
256
256
  "@quilted/preact-workers": "^0.2.0",
257
257
  "@quilted/preact-testing": "^0.1.6",
258
258
  "@quilted/react": "^18.2.0",
259
- "@quilted/react-dom": "^18.2.11",
260
- "@quilted/request-router": "^0.3.0",
259
+ "@quilted/react-dom": "^18.2.15",
260
+ "@quilted/request-router": "^0.3.1",
261
261
  "@quilted/signals": "^0.2.0",
262
262
  "@quilted/threads": "^3.0.0",
263
- "preact-render-to-string": "^6.4.0",
263
+ "preact-render-to-string": "^6.5.0",
264
264
  "jest-matcher-utils": "^29.0.0"
265
265
  },
266
266
  "peerDependencies": {
@@ -12,11 +12,3 @@ export {parseAcceptLanguageHeader} from '@quilted/preact-localize';
12
12
 
13
13
  function noopCreateRequestRouterLocalization() {}
14
14
  export {noopCreateRequestRouterLocalization as createRequestRouterLocalization};
15
-
16
- function noopRenderToResponse() {}
17
- export {noopRenderToResponse as renderToResponse};
18
-
19
- function NoopServerContext() {
20
- return null;
21
- }
22
- export {NoopServerContext as ServerContext};
package/source/server.ts CHANGED
@@ -8,10 +8,3 @@ export * from '@quilted/assets';
8
8
 
9
9
  export {parseAcceptLanguageHeader} from '@quilted/preact-localize';
10
10
  export {createRequestRouterLocalization} from '@quilted/preact-localize/request-router';
11
-
12
- export {
13
- renderToResponse,
14
- type RenderToResponseOptions,
15
- type RenderHTMLFunction,
16
- } from './server/request-router.tsx';
17
- export {ServerContext} from './server/ServerContext.tsx';
@@ -1,20 +0,0 @@
1
- import { BrowserDetailsContext, BrowserAssetsManifestContext } from '@quilted/preact-browser/server';
2
- import { jsx } from 'preact/jsx-runtime';
3
-
4
- function ServerContext({
5
- browser,
6
- assets,
7
- children
8
- }) {
9
- const withBrowser = browser ? jsx(BrowserDetailsContext.Provider, {
10
- value: browser,
11
- children: children
12
- }) : children;
13
- const withAssets = assets ? jsx(BrowserAssetsManifestContext.Provider, {
14
- value: assets,
15
- children: withBrowser
16
- }) : withBrowser;
17
- return withAssets;
18
- }
19
-
20
- export { ServerContext };
@@ -1,251 +0,0 @@
1
- import { isValidElement } from 'preact';
2
- import { renderToStringAsync, renderToStaticMarkup } from 'preact-render-to-string';
3
- import { styleAssetPreloadAttributes, scriptAssetPreloadAttributes } from '@quilted/assets';
4
- import { BrowserResponse, ScriptAsset, StyleAsset, StyleAssetPreload, ScriptAssetPreload } from '@quilted/preact-browser/server';
5
- import { EnhancedResponse, HTMLResponse } from '@quilted/request-router';
6
- import { ServerContext } from './ServerContext.mjs';
7
- import { jsx, jsxs, Fragment } from 'preact/jsx-runtime';
8
-
9
- async function renderToResponse(optionsOrElement, definitelyOptions) {
10
- let element;
11
- let options;
12
- if (isValidElement(optionsOrElement)) {
13
- element = optionsOrElement;
14
- options = definitelyOptions;
15
- } else {
16
- options = optionsOrElement;
17
- }
18
- const {
19
- request,
20
- assets,
21
- status: explicitStatus,
22
- headers: explicitHeaders,
23
- serializations: explicitSerializations,
24
- waitUntil = noop,
25
- stream: shouldStream = false,
26
- renderHTML = true
27
- } = options;
28
- const baseURL = request.URL ?? new URL(request.url);
29
- const browserResponse = new BrowserResponse({
30
- request,
31
- status: explicitStatus,
32
- headers: new Headers(explicitHeaders),
33
- serializations: explicitSerializations
34
- });
35
- let appStream;
36
- if (shouldStream === false && element != null) {
37
- let rendered;
38
- try {
39
- rendered = await renderToStringAsync(jsx(ServerContext, {
40
- assets: assets,
41
- browser: browserResponse,
42
- children: element
43
- }));
44
- } catch (error) {
45
- if (error instanceof Response) {
46
- const mergedHeaders = new Headers(browserResponse.headers);
47
-
48
- // Copy headers from error response, potentially overwriting existing ones
49
- for (const [key, value] of error.headers) {
50
- if (key.toLowerCase() === 'set-cookie') continue;
51
- mergedHeaders.set(key, value);
52
- }
53
- for (const setCookie of error.headers.getSetCookie()) {
54
- mergedHeaders.append('Set-Cookie', setCookie);
55
- }
56
- const mergedResponse = new EnhancedResponse(error.body, {
57
- status: Math.max(browserResponse.status.value, error.status),
58
- headers: mergedHeaders
59
- });
60
- return mergedResponse;
61
- }
62
- throw error;
63
- }
64
- const appTransformStream = new TransformStream();
65
- const appWriter = appTransformStream.writable.getWriter();
66
- appStream = appTransformStream.readable;
67
- appWriter.write(rendered);
68
- appWriter.close();
69
- }
70
- if (appStream == null) {
71
- const appTransformStream = new TransformStream();
72
- appStream = appTransformStream.readable;
73
- const renderAppStream = async function renderAppStream() {
74
- const appWriter = appTransformStream.writable.getWriter();
75
- if (element != null) {
76
- // TODO: how could we handle redirects automatically? For now, if people want
77
- // this, they will explicitly turn on streaming and will have to use some in-app
78
- // to manually handle redirects (e.g., by rendering a script tag that uses JavaScript
79
- // to redirect)
80
- const rendered = await renderToStringAsync(jsx(ServerContext, {
81
- assets: assets,
82
- browser: browserResponse,
83
- children: element
84
- }));
85
- appWriter.write(rendered);
86
- }
87
- appWriter.close();
88
- };
89
- waitUntil(renderAppStream());
90
- }
91
- const body = await renderToHTMLBody(appStream);
92
- return new HTMLResponse(body, {
93
- status: browserResponse.status.value,
94
- headers: browserResponse.headers
95
- });
96
- async function renderToHTMLBody(content) {
97
- if (typeof renderHTML === 'function') {
98
- const body = await renderHTML(content, {
99
- response: browserResponse
100
- });
101
- return body;
102
- } else if (renderHTML === false || renderHTML === 'fragment') {
103
- return content;
104
- }
105
- const responseStream = new TextEncoderStream();
106
- const body = responseStream.readable;
107
- const renderFullHTML = async function renderFullHTML() {
108
- const writer = responseStream.writable.getWriter();
109
- writer.write(`<!DOCTYPE html>`);
110
- const synchronousAssets = assets?.entry({
111
- request,
112
- modules: browserResponse.assets.get({
113
- timing: 'load'
114
- })
115
- });
116
- const preloadAssets = assets?.modules(browserResponse.assets.get({
117
- timing: 'preload'
118
- }), {
119
- request
120
- });
121
- if (synchronousAssets) {
122
- for (const style of synchronousAssets.styles) {
123
- browserResponse.headers.append('Link', preloadHeader(styleAssetPreloadAttributes(style)));
124
- }
125
- for (const script of synchronousAssets.scripts) {
126
- browserResponse.headers.append('Link', preloadHeader(scriptAssetPreloadAttributes(script)));
127
- }
128
- }
129
- const htmlContent = renderToStaticMarkup(jsxs("html", {
130
- ...browserResponse.htmlAttributes.value,
131
- children: [jsxs("head", {
132
- children: [browserResponse.title.value && jsx("title", {
133
- children: browserResponse.title.value
134
- }), browserResponse.links.value.map(link => jsx("link", {
135
- ...link
136
- })), browserResponse.metas.value.map(meta => jsx("meta", {
137
- ...meta
138
- })), browserResponse.serializations.value.map(({
139
- name,
140
- content
141
- }) =>
142
- // @ts-expect-error a custom element that I don’t want to define,
143
- // since it’s an optional part of the browser library.
144
- jsx("browser-serialization", {
145
- name: name,
146
- content: JSON.stringify(content)
147
- })), synchronousAssets?.scripts.map(script => jsx(ScriptAsset, {
148
- asset: script,
149
- baseURL: baseURL
150
- }, script.source)), synchronousAssets?.styles.map(style => jsx(StyleAsset, {
151
- asset: style,
152
- baseURL: baseURL
153
- }, style.source)), preloadAssets?.styles.map(style => jsx(StyleAssetPreload, {
154
- asset: style,
155
- baseURL: baseURL
156
- }, style.source)), preloadAssets?.scripts.map(script => jsx(ScriptAssetPreload, {
157
- asset: script,
158
- baseURL: baseURL
159
- }, script.source))]
160
- }), jsx("body", {
161
- ...browserResponse.bodyAttributes.value,
162
- dangerouslySetInnerHTML: {
163
- __html: '%%CONTENT%%'
164
- }
165
- })]
166
- }));
167
- const [firstChunk, secondChunk] = htmlContent.split('%%CONTENT%%');
168
- writer.write(firstChunk);
169
- if (element != null) writer.write(`<div id="app">`);
170
- const reader = content.getReader();
171
- while (true) {
172
- const {
173
- done,
174
- value
175
- } = await reader.read();
176
- if (done) {
177
- break;
178
- }
179
- writer.write(value);
180
- }
181
- if (element != null) writer.write(`</div>`);
182
- const newSynchronousAssets = assets?.entry({
183
- request,
184
- modules: browserResponse.assets.get({
185
- timing: 'load'
186
- })
187
- });
188
- const newPreloadAssets = assets?.modules(browserResponse.assets.get({
189
- timing: 'preload'
190
- }), {
191
- request
192
- });
193
- if (newSynchronousAssets) {
194
- const diffedSynchronousAssets = diffBrowserAssetsEntries(newSynchronousAssets, synchronousAssets);
195
- const diffedPreloadAssets = diffBrowserAssetsEntries(newPreloadAssets, preloadAssets);
196
- const additionalAssetsContent = renderToStaticMarkup(jsxs(Fragment, {
197
- children: [diffedSynchronousAssets.scripts.map(script => jsx(ScriptAsset, {
198
- asset: script,
199
- baseURL: baseURL
200
- }, script.source)), diffedSynchronousAssets.styles.map(style => jsx(StyleAsset, {
201
- asset: style,
202
- baseURL: baseURL
203
- }, style.source)), diffedPreloadAssets.styles.map(style => jsx(StyleAssetPreload, {
204
- asset: style,
205
- baseURL: baseURL
206
- }, style.source)), diffedPreloadAssets.scripts.map(script => jsx(ScriptAssetPreload, {
207
- asset: script,
208
- baseURL: baseURL
209
- }, script.source))]
210
- }));
211
- writer.write(additionalAssetsContent);
212
- }
213
- writer.write(secondChunk);
214
- writer.close();
215
- };
216
- waitUntil(renderFullHTML());
217
- return body;
218
- }
219
- }
220
- function preloadHeader(attributes) {
221
- const {
222
- as,
223
- rel = 'preload',
224
- href,
225
- crossOrigin,
226
- crossorigin
227
- } = attributes;
228
-
229
- // Support both property and attribute versions of the casing
230
- const finalCrossOrigin = crossOrigin ?? crossorigin;
231
- let header = `<${href}>; rel="${rel}"; as="${as}"`;
232
- if (finalCrossOrigin === '' || finalCrossOrigin === true) {
233
- header += `; crossorigin`;
234
- } else if (typeof finalCrossOrigin === 'string') {
235
- header += `; crossorigin="${finalCrossOrigin}"`;
236
- }
237
- return header;
238
- }
239
- function diffBrowserAssetsEntries(newList, oldList) {
240
- const oldStyles = new Set(oldList.styles.map(style => style.source));
241
- const oldScripts = new Set(oldList.scripts.map(script => script.source));
242
- return {
243
- styles: newList.styles.filter(style => !oldStyles.has(style.source)),
244
- scripts: newList.scripts.filter(script => !oldScripts.has(script.source))
245
- };
246
- }
247
- function noop(..._args) {
248
- // noop
249
- }
250
-
251
- export { renderToResponse };
@@ -1,14 +0,0 @@
1
- import { jsx } from 'preact/jsx-runtime';
2
- import { BrowserDetailsContext, BrowserAssetsManifestContext } from '@quilted/preact-browser/server';
3
-
4
- function ServerContext({
5
- browser,
6
- assets,
7
- children
8
- }) {
9
- const withBrowser = browser ? /* @__PURE__ */ jsx(BrowserDetailsContext.Provider, { value: browser, children }) : children;
10
- const withAssets = assets ? /* @__PURE__ */ jsx(BrowserAssetsManifestContext.Provider, { value: assets, children: withBrowser }) : withBrowser;
11
- return withAssets;
12
- }
13
-
14
- export { ServerContext };
@@ -1,273 +0,0 @@
1
- import { jsx, jsxs, Fragment } from 'preact/jsx-runtime';
2
- import { isValidElement } from 'preact';
3
- import { renderToStringAsync, renderToStaticMarkup } from 'preact-render-to-string';
4
- import { styleAssetPreloadAttributes, scriptAssetPreloadAttributes } from '@quilted/assets';
5
- import { BrowserResponse, ScriptAsset, StyleAsset, StyleAssetPreload, ScriptAssetPreload } from '@quilted/preact-browser/server';
6
- import { EnhancedResponse, HTMLResponse } from '@quilted/request-router';
7
- import { ServerContext } from './ServerContext.esnext';
8
-
9
- async function renderToResponse(optionsOrElement, definitelyOptions) {
10
- let element;
11
- let options;
12
- if (isValidElement(optionsOrElement)) {
13
- element = optionsOrElement;
14
- options = definitelyOptions;
15
- } else {
16
- options = optionsOrElement;
17
- }
18
- const {
19
- request,
20
- assets,
21
- status: explicitStatus,
22
- headers: explicitHeaders,
23
- serializations: explicitSerializations,
24
- waitUntil = noop,
25
- stream: shouldStream = false,
26
- renderHTML = true
27
- } = options;
28
- const baseURL = request.URL ?? new URL(request.url);
29
- const browserResponse = new BrowserResponse({
30
- request,
31
- status: explicitStatus,
32
- headers: new Headers(explicitHeaders),
33
- serializations: explicitSerializations
34
- });
35
- let appStream;
36
- if (shouldStream === false && element != null) {
37
- let rendered;
38
- try {
39
- rendered = await renderToStringAsync(
40
- /* @__PURE__ */ jsx(ServerContext, { assets, browser: browserResponse, children: element })
41
- );
42
- } catch (error) {
43
- if (error instanceof Response) {
44
- const mergedHeaders = new Headers(browserResponse.headers);
45
- for (const [key, value] of error.headers) {
46
- if (key.toLowerCase() === "set-cookie") continue;
47
- mergedHeaders.set(key, value);
48
- }
49
- for (const setCookie of error.headers.getSetCookie()) {
50
- mergedHeaders.append("Set-Cookie", setCookie);
51
- }
52
- const mergedResponse = new EnhancedResponse(error.body, {
53
- status: Math.max(browserResponse.status.value, error.status),
54
- headers: mergedHeaders
55
- });
56
- return mergedResponse;
57
- }
58
- throw error;
59
- }
60
- const appTransformStream = new TransformStream();
61
- const appWriter = appTransformStream.writable.getWriter();
62
- appStream = appTransformStream.readable;
63
- appWriter.write(rendered);
64
- appWriter.close();
65
- }
66
- if (appStream == null) {
67
- const appTransformStream = new TransformStream();
68
- appStream = appTransformStream.readable;
69
- const renderAppStream = async function renderAppStream2() {
70
- const appWriter = appTransformStream.writable.getWriter();
71
- if (element != null) {
72
- const rendered = await renderToStringAsync(
73
- /* @__PURE__ */ jsx(ServerContext, { assets, browser: browserResponse, children: element })
74
- );
75
- appWriter.write(rendered);
76
- }
77
- appWriter.close();
78
- };
79
- waitUntil(renderAppStream());
80
- }
81
- const body = await renderToHTMLBody(appStream);
82
- return new HTMLResponse(body, {
83
- status: browserResponse.status.value,
84
- headers: browserResponse.headers
85
- });
86
- async function renderToHTMLBody(content) {
87
- if (typeof renderHTML === "function") {
88
- const body3 = await renderHTML(content, {
89
- response: browserResponse
90
- });
91
- return body3;
92
- } else if (renderHTML === false || renderHTML === "fragment") {
93
- return content;
94
- }
95
- const responseStream = new TextEncoderStream();
96
- const body2 = responseStream.readable;
97
- const renderFullHTML = async function renderFullHTML2() {
98
- const writer = responseStream.writable.getWriter();
99
- writer.write(`<!DOCTYPE html>`);
100
- const synchronousAssets = assets?.entry({
101
- request,
102
- modules: browserResponse.assets.get({ timing: "load" })
103
- });
104
- const preloadAssets = assets?.modules(
105
- browserResponse.assets.get({ timing: "preload" }),
106
- {
107
- request
108
- }
109
- );
110
- if (synchronousAssets) {
111
- for (const style of synchronousAssets.styles) {
112
- browserResponse.headers.append(
113
- "Link",
114
- preloadHeader(styleAssetPreloadAttributes(style))
115
- );
116
- }
117
- for (const script of synchronousAssets.scripts) {
118
- browserResponse.headers.append(
119
- "Link",
120
- preloadHeader(scriptAssetPreloadAttributes(script))
121
- );
122
- }
123
- }
124
- const htmlContent = renderToStaticMarkup(
125
- /* @__PURE__ */ jsxs("html", { ...browserResponse.htmlAttributes.value, children: [
126
- /* @__PURE__ */ jsxs("head", { children: [
127
- browserResponse.title.value && /* @__PURE__ */ jsx("title", { children: browserResponse.title.value }),
128
- browserResponse.links.value.map((link) => /* @__PURE__ */ jsx("link", { ...link })),
129
- browserResponse.metas.value.map((meta) => /* @__PURE__ */ jsx("meta", { ...meta })),
130
- browserResponse.serializations.value.map(({ name, content: content2 }) => (
131
- // @ts-expect-error a custom element that I don’t want to define,
132
- // since it’s an optional part of the browser library.
133
- /* @__PURE__ */ jsx(
134
- "browser-serialization",
135
- {
136
- name,
137
- content: JSON.stringify(content2)
138
- }
139
- )
140
- )),
141
- synchronousAssets?.scripts.map((script) => /* @__PURE__ */ jsx(
142
- ScriptAsset,
143
- {
144
- asset: script,
145
- baseURL
146
- },
147
- script.source
148
- )),
149
- synchronousAssets?.styles.map((style) => /* @__PURE__ */ jsx(StyleAsset, { asset: style, baseURL }, style.source)),
150
- preloadAssets?.styles.map((style) => /* @__PURE__ */ jsx(
151
- StyleAssetPreload,
152
- {
153
- asset: style,
154
- baseURL
155
- },
156
- style.source
157
- )),
158
- preloadAssets?.scripts.map((script) => /* @__PURE__ */ jsx(
159
- ScriptAssetPreload,
160
- {
161
- asset: script,
162
- baseURL
163
- },
164
- script.source
165
- ))
166
- ] }),
167
- /* @__PURE__ */ jsx(
168
- "body",
169
- {
170
- ...browserResponse.bodyAttributes.value,
171
- dangerouslySetInnerHTML: { __html: "%%CONTENT%%" }
172
- }
173
- )
174
- ] })
175
- );
176
- const [firstChunk, secondChunk] = htmlContent.split("%%CONTENT%%");
177
- writer.write(firstChunk);
178
- if (element != null) writer.write(`<div id="app">`);
179
- const reader = content.getReader();
180
- while (true) {
181
- const { done, value } = await reader.read();
182
- if (done) {
183
- break;
184
- }
185
- writer.write(value);
186
- }
187
- if (element != null) writer.write(`</div>`);
188
- const newSynchronousAssets = assets?.entry({
189
- request,
190
- modules: browserResponse.assets.get({ timing: "load" })
191
- });
192
- const newPreloadAssets = assets?.modules(
193
- browserResponse.assets.get({ timing: "preload" }),
194
- {
195
- request
196
- }
197
- );
198
- if (newSynchronousAssets) {
199
- const diffedSynchronousAssets = diffBrowserAssetsEntries(
200
- newSynchronousAssets,
201
- synchronousAssets
202
- );
203
- const diffedPreloadAssets = diffBrowserAssetsEntries(
204
- newPreloadAssets,
205
- preloadAssets
206
- );
207
- const additionalAssetsContent = renderToStaticMarkup(
208
- /* @__PURE__ */ jsxs(Fragment, { children: [
209
- diffedSynchronousAssets.scripts.map((script) => /* @__PURE__ */ jsx(
210
- ScriptAsset,
211
- {
212
- asset: script,
213
- baseURL
214
- },
215
- script.source
216
- )),
217
- diffedSynchronousAssets.styles.map((style) => /* @__PURE__ */ jsx(StyleAsset, { asset: style, baseURL }, style.source)),
218
- diffedPreloadAssets.styles.map((style) => /* @__PURE__ */ jsx(
219
- StyleAssetPreload,
220
- {
221
- asset: style,
222
- baseURL
223
- },
224
- style.source
225
- )),
226
- diffedPreloadAssets.scripts.map((script) => /* @__PURE__ */ jsx(
227
- ScriptAssetPreload,
228
- {
229
- asset: script,
230
- baseURL
231
- },
232
- script.source
233
- ))
234
- ] })
235
- );
236
- writer.write(additionalAssetsContent);
237
- }
238
- writer.write(secondChunk);
239
- writer.close();
240
- };
241
- waitUntil(renderFullHTML());
242
- return body2;
243
- }
244
- }
245
- function preloadHeader(attributes) {
246
- const {
247
- as,
248
- rel = "preload",
249
- href,
250
- crossOrigin,
251
- crossorigin
252
- } = attributes;
253
- const finalCrossOrigin = crossOrigin ?? crossorigin;
254
- let header = `<${href}>; rel="${rel}"; as="${as}"`;
255
- if (finalCrossOrigin === "" || finalCrossOrigin === true) {
256
- header += `; crossorigin`;
257
- } else if (typeof finalCrossOrigin === "string") {
258
- header += `; crossorigin="${finalCrossOrigin}"`;
259
- }
260
- return header;
261
- }
262
- function diffBrowserAssetsEntries(newList, oldList) {
263
- const oldStyles = new Set(oldList.styles.map((style) => style.source));
264
- const oldScripts = new Set(oldList.scripts.map((script) => script.source));
265
- return {
266
- styles: newList.styles.filter((style) => !oldStyles.has(style.source)),
267
- scripts: newList.scripts.filter((script) => !oldScripts.has(script.source))
268
- };
269
- }
270
- function noop(..._args) {
271
- }
272
-
273
- export { renderToResponse };