preact-render-to-string 6.3.1 → 6.4.1
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/README.md +5 -12
- package/dist/commonjs.js +1 -1
- package/dist/commonjs.js.map +1 -1
- package/dist/index.d.ts +14 -4
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.module.js +1 -1
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/jsx.mjs.map +1 -1
- package/dist/jsx.module.js.map +1 -1
- package/dist/jsx.umd.js.map +1 -1
- package/jsx.d.ts +0 -2
- package/package.json +157 -151
- package/src/index.d.ts +14 -4
- package/src/index.js +170 -26
- package/src/util.js +14 -0
package/src/index.js
CHANGED
|
@@ -60,8 +60,74 @@ export function renderToString(vnode, context) {
|
|
|
60
60
|
context || EMPTY_OBJ,
|
|
61
61
|
false,
|
|
62
62
|
undefined,
|
|
63
|
-
parent
|
|
63
|
+
parent,
|
|
64
|
+
false
|
|
64
65
|
);
|
|
66
|
+
} catch (e) {
|
|
67
|
+
if (e.then) {
|
|
68
|
+
throw new Error('Use "renderToStringAsync" for suspenseful rendering.');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
throw e;
|
|
72
|
+
} finally {
|
|
73
|
+
// options._commit, we don't schedule any effects in this library right now,
|
|
74
|
+
// so we can pass an empty queue to this hook.
|
|
75
|
+
if (options[COMMIT]) options[COMMIT](vnode, EMPTY_ARR);
|
|
76
|
+
options[SKIP_EFFECTS] = previousSkipEffects;
|
|
77
|
+
EMPTY_ARR.length = 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Render Preact JSX + Components to an HTML string.
|
|
83
|
+
* @param {VNode} vnode JSX Element / VNode to render
|
|
84
|
+
* @param {Object} [context={}] Initial root context object
|
|
85
|
+
* @returns {string} serialized HTML
|
|
86
|
+
*/
|
|
87
|
+
export async function renderToStringAsync(vnode, context) {
|
|
88
|
+
// Performance optimization: `renderToString` is synchronous and we
|
|
89
|
+
// therefore don't execute any effects. To do that we pass an empty
|
|
90
|
+
// array to `options._commit` (`__c`). But we can go one step further
|
|
91
|
+
// and avoid a lot of dirty checks and allocations by setting
|
|
92
|
+
// `options._skipEffects` (`__s`) too.
|
|
93
|
+
const previousSkipEffects = options[SKIP_EFFECTS];
|
|
94
|
+
options[SKIP_EFFECTS] = true;
|
|
95
|
+
|
|
96
|
+
// store options hooks once before each synchronous render call
|
|
97
|
+
beforeDiff = options[DIFF];
|
|
98
|
+
afterDiff = options[DIFFED];
|
|
99
|
+
renderHook = options[RENDER];
|
|
100
|
+
ummountHook = options.unmount;
|
|
101
|
+
|
|
102
|
+
const parent = h(Fragment, null);
|
|
103
|
+
parent[CHILDREN] = [vnode];
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
const rendered = _renderToString(
|
|
107
|
+
vnode,
|
|
108
|
+
context || EMPTY_OBJ,
|
|
109
|
+
false,
|
|
110
|
+
undefined,
|
|
111
|
+
parent,
|
|
112
|
+
true
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (Array.isArray(rendered)) {
|
|
116
|
+
let count = 0;
|
|
117
|
+
let resolved = rendered;
|
|
118
|
+
|
|
119
|
+
// Resolving nested Promises with a maximum depth of 25
|
|
120
|
+
while (
|
|
121
|
+
resolved.some((element) => typeof element.then === 'function') &&
|
|
122
|
+
count++ < 25
|
|
123
|
+
) {
|
|
124
|
+
resolved = (await Promise.all(resolved)).flat();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return resolved.join('');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return rendered;
|
|
65
131
|
} finally {
|
|
66
132
|
// options._commit, we don't schedule any effects in this library right now,
|
|
67
133
|
// so we can pass an empty queue to this hook.
|
|
@@ -137,9 +203,17 @@ function renderClassComponent(vnode, context) {
|
|
|
137
203
|
* @param {boolean} isSvgMode
|
|
138
204
|
* @param {any} selectValue
|
|
139
205
|
* @param {VNode} parent
|
|
140
|
-
* @
|
|
206
|
+
* @param {boolean} asyncMode
|
|
207
|
+
* @returns {string | Promise<string> | (string | Promise<string>)[]}
|
|
141
208
|
*/
|
|
142
|
-
function _renderToString(
|
|
209
|
+
function _renderToString(
|
|
210
|
+
vnode,
|
|
211
|
+
context,
|
|
212
|
+
isSvgMode,
|
|
213
|
+
selectValue,
|
|
214
|
+
parent,
|
|
215
|
+
asyncMode
|
|
216
|
+
) {
|
|
143
217
|
// Ignore non-rendered VNodes/values
|
|
144
218
|
if (vnode == null || vnode === true || vnode === false || vnode === '') {
|
|
145
219
|
return '';
|
|
@@ -153,16 +227,44 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
|
153
227
|
|
|
154
228
|
// Recurse into children / Arrays
|
|
155
229
|
if (isArray(vnode)) {
|
|
156
|
-
let rendered = ''
|
|
230
|
+
let rendered = '',
|
|
231
|
+
renderArray;
|
|
157
232
|
parent[CHILDREN] = vnode;
|
|
158
233
|
for (let i = 0; i < vnode.length; i++) {
|
|
159
234
|
let child = vnode[i];
|
|
160
235
|
if (child == null || typeof child === 'boolean') continue;
|
|
161
236
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
237
|
+
const childRender = _renderToString(
|
|
238
|
+
child,
|
|
239
|
+
context,
|
|
240
|
+
isSvgMode,
|
|
241
|
+
selectValue,
|
|
242
|
+
parent,
|
|
243
|
+
asyncMode
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
if (typeof childRender === 'string') {
|
|
247
|
+
rendered += childRender;
|
|
248
|
+
} else {
|
|
249
|
+
renderArray = renderArray || [];
|
|
250
|
+
|
|
251
|
+
if (rendered) renderArray.push(rendered);
|
|
252
|
+
|
|
253
|
+
rendered = '';
|
|
254
|
+
|
|
255
|
+
if (Array.isArray(childRender)) {
|
|
256
|
+
renderArray.push(...childRender);
|
|
257
|
+
} else {
|
|
258
|
+
renderArray.push(childRender);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (renderArray) {
|
|
264
|
+
if (rendered) renderArray.push(rendered);
|
|
265
|
+
return renderArray;
|
|
165
266
|
}
|
|
267
|
+
|
|
166
268
|
return rendered;
|
|
167
269
|
}
|
|
168
270
|
|
|
@@ -202,7 +304,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
|
202
304
|
context,
|
|
203
305
|
isSvgMode,
|
|
204
306
|
selectValue,
|
|
205
|
-
vnode
|
|
307
|
+
vnode,
|
|
308
|
+
asyncMode
|
|
206
309
|
);
|
|
207
310
|
} else {
|
|
208
311
|
// Values are pre-escaped by the JSX transform
|
|
@@ -282,7 +385,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
|
282
385
|
context,
|
|
283
386
|
isSvgMode,
|
|
284
387
|
selectValue,
|
|
285
|
-
vnode
|
|
388
|
+
vnode,
|
|
389
|
+
asyncMode
|
|
286
390
|
);
|
|
287
391
|
return str;
|
|
288
392
|
} catch (err) {
|
|
@@ -313,14 +417,15 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
|
313
417
|
context,
|
|
314
418
|
isSvgMode,
|
|
315
419
|
selectValue,
|
|
316
|
-
vnode
|
|
420
|
+
vnode,
|
|
421
|
+
asyncMode
|
|
317
422
|
);
|
|
318
423
|
}
|
|
319
424
|
|
|
320
425
|
return str;
|
|
321
426
|
} finally {
|
|
322
427
|
if (afterDiff) afterDiff(vnode);
|
|
323
|
-
vnode[PARENT] =
|
|
428
|
+
vnode[PARENT] = null;
|
|
324
429
|
|
|
325
430
|
if (ummountHook) ummountHook(vnode);
|
|
326
431
|
}
|
|
@@ -333,20 +438,46 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
|
333
438
|
rendered != null && rendered.type === Fragment && rendered.key == null;
|
|
334
439
|
rendered = isTopLevelFragment ? rendered.props.children : rendered;
|
|
335
440
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
441
|
+
const renderChildren = () =>
|
|
442
|
+
_renderToString(
|
|
443
|
+
rendered,
|
|
444
|
+
context,
|
|
445
|
+
isSvgMode,
|
|
446
|
+
selectValue,
|
|
447
|
+
vnode,
|
|
448
|
+
asyncMode
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
// Recurse into children before invoking the after-diff hook
|
|
453
|
+
const str = renderChildren();
|
|
454
|
+
|
|
455
|
+
if (afterDiff) afterDiff(vnode);
|
|
456
|
+
vnode[PARENT] = null;
|
|
346
457
|
|
|
347
|
-
|
|
458
|
+
if (ummountHook) ummountHook(vnode);
|
|
348
459
|
|
|
349
|
-
|
|
460
|
+
return str;
|
|
461
|
+
} catch (error) {
|
|
462
|
+
if (!asyncMode) throw error;
|
|
463
|
+
|
|
464
|
+
if (!error || typeof error.then !== 'function') throw error;
|
|
465
|
+
|
|
466
|
+
const renderNestedChildren = () => {
|
|
467
|
+
try {
|
|
468
|
+
return renderChildren();
|
|
469
|
+
} catch (e) {
|
|
470
|
+
if (!e || typeof e.then !== 'function') throw e;
|
|
471
|
+
|
|
472
|
+
return e.then(
|
|
473
|
+
() => renderChildren(),
|
|
474
|
+
() => renderNestedChildren()
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
return error.then(() => renderNestedChildren());
|
|
480
|
+
}
|
|
350
481
|
}
|
|
351
482
|
|
|
352
483
|
// Serialize Element VNodes to HTML
|
|
@@ -476,11 +607,18 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
|
476
607
|
// recurse into this element VNode's children
|
|
477
608
|
let childSvgMode =
|
|
478
609
|
type === 'svg' || (type !== 'foreignObject' && isSvgMode);
|
|
479
|
-
html = _renderToString(
|
|
610
|
+
html = _renderToString(
|
|
611
|
+
children,
|
|
612
|
+
context,
|
|
613
|
+
childSvgMode,
|
|
614
|
+
selectValue,
|
|
615
|
+
vnode,
|
|
616
|
+
asyncMode
|
|
617
|
+
);
|
|
480
618
|
}
|
|
481
619
|
|
|
482
620
|
if (afterDiff) afterDiff(vnode);
|
|
483
|
-
vnode[PARENT] =
|
|
621
|
+
vnode[PARENT] = null;
|
|
484
622
|
if (ummountHook) ummountHook(vnode);
|
|
485
623
|
|
|
486
624
|
// Emit self-closing tag for empty void elements:
|
|
@@ -488,7 +626,13 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
|
|
|
488
626
|
return s + '/>';
|
|
489
627
|
}
|
|
490
628
|
|
|
491
|
-
|
|
629
|
+
const endTag = '</' + type + '>';
|
|
630
|
+
const startTag = s + '>';
|
|
631
|
+
|
|
632
|
+
if (Array.isArray(html)) return [startTag, ...html, endTag];
|
|
633
|
+
else if (typeof html !== 'string') return [startTag, html, endTag];
|
|
634
|
+
|
|
635
|
+
return startTag + html + endTag;
|
|
492
636
|
}
|
|
493
637
|
|
|
494
638
|
const SELF_CLOSING = new Set([
|
package/src/util.js
CHANGED
|
@@ -150,3 +150,17 @@ export function createComponent(vnode, context) {
|
|
|
150
150
|
__h: []
|
|
151
151
|
};
|
|
152
152
|
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @template T
|
|
156
|
+
*/
|
|
157
|
+
export class Deferred {
|
|
158
|
+
constructor() {
|
|
159
|
+
// eslint-disable-next-line lines-around-comment
|
|
160
|
+
/** @type {Promise<T>} */
|
|
161
|
+
this.promise = new Promise((resolve, reject) => {
|
|
162
|
+
this.resolve = resolve;
|
|
163
|
+
this.reject = reject;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|