@quilted/quilt 0.5.130 → 0.5.131

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @quilted/quilt
2
2
 
3
+ ## 0.5.131
4
+
5
+ ### Patch Changes
6
+
7
+ - [#508](https://github.com/lemonmade/quilt/pull/508) [`befb2aa9`](https://github.com/lemonmade/quilt/commit/befb2aa9d374aff66cbfe54fc8157522e3d3af21) Thanks [@lemonmade](https://github.com/lemonmade)! - Move logic out of HTML component
8
+
3
9
  ## 0.5.130
4
10
 
5
11
  ### Patch Changes
@@ -7,7 +7,6 @@ var server$3 = require('@quilted/react-async/server');
7
7
  var requestRouter = require('@quilted/react-localize/request-router');
8
8
  var requestRouter$1 = require('@quilted/request-router');
9
9
  var reactLocalize = require('@quilted/react-localize');
10
- var render = require('./render.cjs');
11
10
  var ServerContext = require('./ServerContext.cjs');
12
11
  var requestRouter$2 = require('./request-router.cjs');
13
12
 
@@ -61,6 +60,22 @@ Object.defineProperty(exports, 'createAssetManifest', {
61
60
  enumerable: true,
62
61
  get: function () { return server$2.createAssetManifest; }
63
62
  });
63
+ Object.defineProperty(exports, 'scriptAssetAttributes', {
64
+ enumerable: true,
65
+ get: function () { return server$2.scriptAssetAttributes; }
66
+ });
67
+ Object.defineProperty(exports, 'scriptAssetPreloadAttributes', {
68
+ enumerable: true,
69
+ get: function () { return server$2.scriptAssetPreloadAttributes; }
70
+ });
71
+ Object.defineProperty(exports, 'styleAssetAttributes', {
72
+ enumerable: true,
73
+ get: function () { return server$2.styleAssetAttributes; }
74
+ });
75
+ Object.defineProperty(exports, 'styleAssetPreloadAttributes', {
76
+ enumerable: true,
77
+ get: function () { return server$2.styleAssetPreloadAttributes; }
78
+ });
64
79
  Object.defineProperty(exports, 'ASYNC_ASSETS_SERVER_ACTION_ID', {
65
80
  enumerable: true,
66
81
  get: function () { return server$3.SERVER_ACTION_ID; }
@@ -105,7 +120,7 @@ Object.defineProperty(exports, 'parseAcceptLanguageHeader', {
105
120
  enumerable: true,
106
121
  get: function () { return reactLocalize.parseAcceptLanguageHeader; }
107
122
  });
108
- exports.renderApp = render.renderApp;
109
123
  exports.ServerContext = ServerContext.ServerContext;
110
124
  exports.createServerRender = requestRouter$2.createServerRender;
111
125
  exports.renderAppToResponse = requestRouter$2.renderAppToResponse;
126
+ exports.renderAppToStreamedResponse = requestRouter$2.renderAppToStreamedResponse;
@@ -1,36 +1,41 @@
1
1
  'use strict';
2
2
 
3
- var server = require('@quilted/react-html/server');
3
+ var react = require('react');
4
+ var server = require('@quilted/async/server');
5
+ var server$2 = require('@quilted/react-async/server');
6
+ var server$3 = require('@quilted/react-http/server');
7
+ var server$1 = require('@quilted/react-html/server');
8
+ var server$4 = require('@quilted/react-server-render/server');
4
9
  var requestRouter = require('@quilted/request-router');
5
- var render = require('./render.cjs');
10
+ var ServerContext = require('./ServerContext.cjs');
6
11
  var jsxRuntime = require('react/jsx-runtime');
7
12
 
8
13
  function createServerRender(render, {
9
14
  context,
15
+ stream,
10
16
  ...options
11
17
  } = {}) {
12
18
  return async (request, requestContext) => {
13
19
  const accepts = request.headers.get('Accept');
14
20
  if (accepts != null && !accepts.includes('text/html')) return;
15
21
  const app = await render(request, requestContext);
16
- return renderAppToResponse(app, request, {
22
+ const renderResponse = stream ? renderAppToStreamedResponse : renderAppToResponse;
23
+ return renderResponse(app, request, {
17
24
  ...options,
18
- context: context?.(request, requestContext) ?? requestContext
25
+ extract: {
26
+ ...options.extract,
27
+ context: options.extract ?? context?.(request, requestContext) ?? requestContext
28
+ }
19
29
  });
20
30
  };
21
31
  }
22
32
  async function renderAppToResponse(app, request, {
23
33
  assets,
24
- renderHtml = defaultRenderHtml,
25
- ...options
34
+ extract,
35
+ renderHtml
26
36
  } = {}) {
27
- const {
28
- html: htmlManager,
29
- http,
30
- rendered,
31
- asyncAssets
32
- } = await render.renderApp(app, {
33
- ...options,
37
+ const renderDetails = await serverRenderDetailsForApp(app, {
38
+ extract,
34
39
  url: request.url,
35
40
  headers: request.headers
36
41
  });
@@ -38,57 +43,202 @@ async function renderAppToResponse(app, request, {
38
43
  headers,
39
44
  statusCode = 200,
40
45
  redirectUrl
41
- } = http.state;
46
+ } = renderDetails.http.state;
42
47
  if (redirectUrl) {
43
48
  return requestRouter.redirect(redirectUrl, {
44
49
  status: statusCode,
45
50
  headers
46
51
  });
47
52
  }
53
+ const content = await renderAppDetailsToHtmlString(renderDetails, request, {
54
+ assets,
55
+ renderHtml
56
+ });
57
+ return requestRouter.html(content, {
58
+ headers,
59
+ status: statusCode
60
+ });
61
+ }
62
+ async function renderAppToStreamedResponse(app, request, {
63
+ assets,
64
+ extract,
65
+ renderHtml
66
+ } = {}) {
67
+ const headers = new Headers();
68
+ const stream = new TransformStream();
69
+ const assetContext = {
70
+ userAgent: request.headers.get('User-Agent')
71
+ };
72
+ const guaranteedAssets = await assets?.assets({
73
+ context: assetContext
74
+ });
75
+ if (guaranteedAssets) {
76
+ for (const style of guaranteedAssets.styles) {
77
+ headers.append('Link', preloadHeader(server.styleAssetPreloadAttributes(style)));
78
+ }
79
+ for (const script of guaranteedAssets.scripts) {
80
+ headers.append('Link', preloadHeader(server.scriptAssetPreloadAttributes(script)));
81
+ }
82
+ }
83
+ renderResponseToStream();
84
+ return requestRouter.html(stream.readable, {
85
+ headers,
86
+ status: 200
87
+ });
88
+ async function renderResponseToStream() {
89
+ const renderDetails = await serverRenderDetailsForApp(app, {
90
+ extract,
91
+ url: request.url,
92
+ headers: request.headers
93
+ });
94
+ const content = await renderAppDetailsToHtmlString(renderDetails, request, {
95
+ assets,
96
+ renderHtml
97
+ });
98
+ const writer = stream.writable.getWriter();
99
+ await writer.write(content);
100
+ await writer.close();
101
+ }
102
+ }
103
+ async function serverRenderDetailsForApp(app, {
104
+ url,
105
+ headers,
106
+ extract: extractOptions
107
+ } = {}) {
108
+ const html = new server$1.HtmlManager();
109
+ const asyncAssets = new server$2.AsyncAssetManager();
110
+ const http = new server$3.HttpManager({
111
+ headers
112
+ });
113
+ const {
114
+ decorate,
115
+ ...rest
116
+ } = extractOptions ?? {};
117
+ const rendered = await server$4.extract(app, {
118
+ decorate(app) {
119
+ return /*#__PURE__*/jsxRuntime.jsx(ServerContext.ServerContext, {
120
+ asyncAssets: asyncAssets,
121
+ http: http,
122
+ html: html,
123
+ url: url,
124
+ children: decorate?.(app) ?? app
125
+ });
126
+ },
127
+ ...rest
128
+ });
129
+ return {
130
+ rendered,
131
+ http,
132
+ html,
133
+ asyncAssets
134
+ };
135
+ }
136
+ async function renderAppDetailsToHtmlString(details, request, {
137
+ assets,
138
+ renderHtml = defaultRenderHtml
139
+ } = {}) {
140
+ const {
141
+ html: htmlManager,
142
+ http,
143
+ rendered,
144
+ asyncAssets
145
+ } = details;
48
146
  const usedAssets = asyncAssets.used({
49
147
  timing: 'load'
50
148
  });
51
- const assetOptions = {
149
+ const assetContext = {
52
150
  userAgent: request.headers.get('User-Agent')
53
151
  };
54
- const [styles, scripts, preload] = assets ? await Promise.all([assets.styles({
152
+ const [entryAssets, preloadAssets] = assets ? await Promise.all([assets.assets({
55
153
  async: usedAssets,
56
- options: assetOptions
57
- }), assets.scripts({
58
- async: usedAssets,
59
- options: assetOptions
154
+ context: assetContext
60
155
  }), assets.asyncAssets(asyncAssets.used({
61
156
  timing: 'preload'
62
157
  }), {
63
- options: assetOptions
64
- })]) : [[], [], []];
158
+ context: assetContext
159
+ })]) : [];
65
160
  const htmlElement = await renderHtml(rendered, request, {
66
161
  html: htmlManager,
67
162
  http,
68
- styles,
69
- scripts,
70
- preload
71
- });
72
- return requestRouter.html(server.renderHtmlToString(htmlElement), {
73
- headers,
74
- status: statusCode
163
+ assets: entryAssets,
164
+ preloadAssets
75
165
  });
166
+ return server$1.renderHtmlToString(htmlElement);
76
167
  }
77
- function defaultRenderHtml(content, request, {
168
+ const defaultRenderHtml = function defaultRenderHtml(content, request, {
78
169
  html,
79
- styles,
80
- scripts,
81
- preload
170
+ assets,
171
+ preloadAssets
82
172
  }) {
83
- return /*#__PURE__*/jsxRuntime.jsx(server.Html, {
84
- url: new URL(request.url),
173
+ const baseUrl = new URL(request.url);
174
+ return /*#__PURE__*/jsxRuntime.jsx(server$1.Html, {
85
175
  manager: html,
86
- styles: styles,
87
- scripts: scripts,
88
- preloadAssets: preload,
176
+ headEndContent: /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
177
+ children: [assets && [...assets.styles].map(style => {
178
+ const attributes = server.styleAssetAttributes(style, {
179
+ baseUrl
180
+ });
181
+ return /*#__PURE__*/jsxRuntime.jsx("link", {
182
+ ...attributes
183
+ }, style.source);
184
+ }), assets && [...assets.scripts].map(script => {
185
+ const isModule = script.attributes.type === 'module';
186
+ const attributes = server.scriptAssetAttributes(script, {
187
+ baseUrl
188
+ });
189
+ if (isModule) {
190
+ return /*#__PURE__*/jsxRuntime.jsxs(react.Fragment, {
191
+ children: [/*#__PURE__*/jsxRuntime.jsx("link", {
192
+ ...server.scriptAssetPreloadAttributes(script)
193
+ }), /*#__PURE__*/jsxRuntime.jsx("script", {
194
+ ...attributes,
195
+ async: true
196
+ })]
197
+ }, script.source);
198
+ }
199
+ return /*#__PURE__*/jsxRuntime.jsx("script", {
200
+ ...attributes,
201
+ defer: true
202
+ }, script.source);
203
+ }), preloadAssets && [...preloadAssets.styles].map(style => {
204
+ const attributes = server.styleAssetPreloadAttributes(style, {
205
+ baseUrl
206
+ });
207
+ return /*#__PURE__*/jsxRuntime.jsx("link", {
208
+ ...attributes
209
+ }, style.source);
210
+ }), preloadAssets && [...preloadAssets.scripts].map(script => {
211
+ const attributes = server.scriptAssetPreloadAttributes(script, {
212
+ baseUrl
213
+ });
214
+ return /*#__PURE__*/jsxRuntime.jsx("link", {
215
+ ...attributes
216
+ }, script.source);
217
+ })]
218
+ }),
89
219
  children: content
90
220
  });
221
+ };
222
+ function preloadHeader(attributes) {
223
+ const {
224
+ as,
225
+ rel = 'preload',
226
+ href,
227
+ crossOrigin,
228
+ crossorigin
229
+ } = attributes;
230
+
231
+ // Support both property and attribute versions of the casing
232
+ const finalCrossOrigin = crossOrigin ?? crossorigin;
233
+ let header = `<${href}>; rel="${rel}"; as="${as}"`;
234
+ if (finalCrossOrigin === '' || finalCrossOrigin === true) {
235
+ header += `; crossorigin`;
236
+ } else if (typeof finalCrossOrigin === 'string') {
237
+ header += `; crossorigin="${finalCrossOrigin}"`;
238
+ }
239
+ return header;
91
240
  }
92
241
 
93
242
  exports.createServerRender = createServerRender;
94
243
  exports.renderAppToResponse = renderAppToResponse;
244
+ exports.renderAppToStreamedResponse = renderAppToStreamedResponse;
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var server$1 = require('@quilted/async/server');
3
4
  var server = require('@quilted/react-html/server');
4
5
  var _static = require('@quilted/react-router/static');
5
6
  var render = require('./render.cjs');
@@ -175,30 +176,20 @@ async function renderStatic(App, {
175
176
  const usedAssets = asyncAssets.used({
176
177
  timing: 'load'
177
178
  });
178
- const [moduleStyles, moduleScripts, modulePreload, nomoduleStyles, nomoduleScripts] = await Promise.all([assets.styles({
179
+ const [moduleAssets, modulePreload, nomoduleAssets] = await Promise.all([assets.assets({
179
180
  async: usedAssets,
180
- options: {
181
- modules: true
182
- }
183
- }), assets.scripts({
184
- async: usedAssets,
185
- options: {
181
+ context: {
186
182
  modules: true
187
183
  }
188
184
  }), assets.asyncAssets(asyncAssets.used({
189
185
  timing: 'preload'
190
186
  }), {
191
- options: {
187
+ context: {
192
188
  modules: true
193
189
  }
194
- }), assets.styles({
195
- async: usedAssets,
196
- options: {
197
- modules: false
198
- }
199
- }), assets.scripts({
190
+ }), assets.assets({
200
191
  async: usedAssets,
201
- options: {
192
+ context: {
202
193
  modules: false
203
194
  }
204
195
  })]);
@@ -206,22 +197,49 @@ async function renderStatic(App, {
206
197
  // We don’t want to load styles from both bundles, so we only use module styles,
207
198
  // since modules are intended to be the default and CSS (usually) doesn’t
208
199
  // have features that meaningfully break older user agents.
209
- const styles = moduleStyles.length > 0 ? moduleStyles : nomoduleStyles;
210
-
211
- // If there are nomodule scripts, we can’t really do preloading, because we can’t
212
- // prevent the nomodule scripts from being preloaded in module browsers. If there
213
- // are only module scripts, we can preload those.
214
- const preload = nomoduleScripts.length > 0 ? [] : modulePreload;
215
- const scripts = [...moduleScripts, ...nomoduleScripts.map(script => ({
216
- ...script,
217
- nomodule: true
218
- }))];
200
+ const styles = moduleAssets.styles.length > 0 ? moduleAssets.styles : nomoduleAssets.styles;
219
201
  const minifiedHtml = server.renderHtmlToString( /*#__PURE__*/jsxRuntime.jsx(server.Html, {
220
- url: url,
221
202
  manager: htmlManager,
222
- styles: styles,
223
- scripts: scripts,
224
- preloadAssets: preload,
203
+ headEndContent: /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
204
+ children: [[...styles].map(style => {
205
+ const attributes = server$1.styleAssetAttributes(style, {
206
+ baseUrl: url
207
+ });
208
+ return /*#__PURE__*/jsxRuntime.jsx("link", {
209
+ ...attributes
210
+ }, style.source);
211
+ }), [...moduleAssets.scripts].map(script => {
212
+ const attributes = server$1.scriptAssetAttributes(script, {
213
+ baseUrl: url
214
+ });
215
+ return /*#__PURE__*/jsxRuntime.jsx("script", {
216
+ ...attributes
217
+ }, script.source);
218
+ }), [...nomoduleAssets.scripts].map(script => {
219
+ const attributes = server$1.scriptAssetAttributes(script, {
220
+ baseUrl: url
221
+ });
222
+ return /*#__PURE__*/jsxRuntime.jsx("script", {
223
+ ...attributes,
224
+ // @ts-expect-error Rendering to HTML, so using the lowercase name
225
+ nomodule: moduleAssets.scripts.length > 0 ? true : undefined
226
+ }, script.source);
227
+ }), [...modulePreload.styles].map(style => {
228
+ const attributes = server$1.styleAssetPreloadAttributes(style, {
229
+ baseUrl: url
230
+ });
231
+ return /*#__PURE__*/jsxRuntime.jsx("link", {
232
+ ...attributes
233
+ }, style.source);
234
+ }), [...modulePreload.scripts].map(script => {
235
+ const attributes = server$1.scriptAssetPreloadAttributes(script, {
236
+ baseUrl: url
237
+ });
238
+ return /*#__PURE__*/jsxRuntime.jsx("link", {
239
+ ...attributes
240
+ }, script.source);
241
+ })]
242
+ }),
225
243
  children: markup
226
244
  }));
227
245
  const html = prettify ? await prettifyHtml(minifiedHtml) : minifiedHtml;
@@ -1,10 +1,9 @@
1
1
  export { SERVER_ACTION_ID as HTML_SERVER_ACTION_ID, Html, HtmlContext, HtmlManager, Serialize, renderHtmlToString } from '@quilted/react-html/server';
2
2
  export { ServerAction, ServerRenderManager, ServerRenderManagerContext, extract, useServerAction } from '@quilted/react-server-render/server';
3
- export { createAssetManifest } from '@quilted/async/server';
3
+ export { createAssetManifest, scriptAssetAttributes, scriptAssetPreloadAttributes, styleAssetAttributes, styleAssetPreloadAttributes } from '@quilted/async/server';
4
4
  export { SERVER_ACTION_ID as ASYNC_ASSETS_SERVER_ACTION_ID, AsyncAssetContext, AsyncAssetManager } from '@quilted/react-async/server';
5
5
  export { createRequestRouterLocalization } from '@quilted/react-localize/request-router';
6
6
  export { EnhancedRequest, EnhancedResponse, Request, Response, createHeaders, createRequestRouter } from '@quilted/request-router';
7
7
  export { parseAcceptLanguageHeader } from '@quilted/react-localize';
8
- export { renderApp } from './render.mjs';
9
8
  export { ServerContext } from './ServerContext.mjs';
10
- export { createServerRender, renderAppToResponse } from './request-router.mjs';
9
+ export { createServerRender, renderAppToResponse, renderAppToStreamedResponse } from './request-router.mjs';