preact-render-to-string 6.4.2 → 6.5.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/dist/commonjs.js +1 -1
- package/dist/commonjs.js.map +1 -1
- 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/internal.d.ts +35 -0
- package/dist/jsx-entry.js +1 -1
- package/dist/jsx-entry.js.map +1 -1
- package/dist/jsx.js.map +1 -1
- package/dist/jsx.mjs +1 -1
- package/dist/jsx.mjs.map +1 -1
- package/dist/jsx.module.js +1 -1
- package/dist/jsx.module.js.map +1 -1
- package/dist/jsx.umd.js +1 -1
- package/dist/jsx.umd.js.map +1 -1
- package/dist/stream-node.js +786 -0
- package/dist/stream-node.js.map +1 -0
- package/dist/stream-node.module.js +786 -0
- package/dist/stream-node.module.js.map +1 -0
- package/dist/stream-node.umd.js +790 -0
- package/dist/stream-node.umd.js.map +1 -0
- package/dist/stream.js +2 -0
- package/dist/stream.js.map +1 -0
- package/dist/stream.module.js +2 -0
- package/dist/stream.module.js.map +1 -0
- package/dist/stream.umd.js +2 -0
- package/dist/stream.umd.js.map +1 -0
- package/jsx.d.ts +1 -1
- package/package.json +172 -157
- package/src/index.js +54 -18
- package/src/internal.d.ts +35 -0
- package/src/jsx.js +2 -4
- package/src/lib/chunked.js +97 -0
- package/src/lib/client.js +61 -0
- package/src/{constants.js → lib/constants.js} +3 -0
- package/src/{util.js → lib/util.js} +13 -1
- package/src/pretty.js +13 -13
- package/src/stream-node.js +60 -0
- package/src/stream.js +43 -0
- /package/src/{polyfills.js → lib/polyfills.js} +0 -0
package/package.json
CHANGED
|
@@ -1,159 +1,174 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
2
|
+
"name": "preact-render-to-string",
|
|
3
|
+
"amdName": "preactRenderToString",
|
|
4
|
+
"version": "6.5.1",
|
|
5
|
+
"description": "Render JSX to an HTML string, with support for Preact components.",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"umd:main": "dist/index.umd.js",
|
|
8
|
+
"module": "dist/index.module.js",
|
|
9
|
+
"jsnext:main": "dist/index.module.js",
|
|
10
|
+
"types": "src/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./src/index.d.ts",
|
|
14
|
+
"browser": "./dist/index.module.js",
|
|
15
|
+
"umd": "./dist/index.umd.js",
|
|
16
|
+
"import": "./dist/index.mjs",
|
|
17
|
+
"require": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./jsx": {
|
|
20
|
+
"types": "./jsx.d.ts",
|
|
21
|
+
"browser": "./dist/jsx.module.js",
|
|
22
|
+
"umd": "./dist/jsx.umd.js",
|
|
23
|
+
"import": "./dist/jsx.mjs",
|
|
24
|
+
"require": "./dist/jsx.js"
|
|
25
|
+
},
|
|
26
|
+
"./stream": {
|
|
27
|
+
"types": "./stream.d.ts",
|
|
28
|
+
"import": "./dist/stream.mjs",
|
|
29
|
+
"browser": "./dist/stream.module.js",
|
|
30
|
+
"require": "./dist/stream.js"
|
|
31
|
+
},
|
|
32
|
+
"./stream-node": {
|
|
33
|
+
"types": "./stream-node.d.ts",
|
|
34
|
+
"import": "./dist/stream-node.mjs",
|
|
35
|
+
"browser": "./dist/stream-node.module.js",
|
|
36
|
+
"require": "./dist/stream-node.js"
|
|
37
|
+
},
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"bench": "BABEL_ENV=test node -r @babel/register benchmarks index.js",
|
|
42
|
+
"bench:v8": "BABEL_ENV=test microbundle benchmarks/index.js -f modern --alias benchmarkjs-pretty=benchmarks/lib/benchmark-lite.js --external none --target node --no-compress --no-sourcemap --raw -o benchmarks/.v8.mjs && v8 --module benchmarks/.v8.modern.js",
|
|
43
|
+
"build": "npm run -s transpile && npm run -s transpile:jsx && npm run -s transpile:stream && npm run -s copy-typescript-definition",
|
|
44
|
+
"postbuild": "node ./config/node-13-exports.js && node ./config/node-commonjs.js && node ./config/node-verify-exports.js",
|
|
45
|
+
"transpile": "microbundle src/index.js -f es,cjs,umd --target web --external preact",
|
|
46
|
+
"transpile:stream": "microbundle src/stream.js -o dist/stream.js -f es,cjs,umd --external preact && microbundle src/stream-node.js -o dist/stream-node.js -f es,cjs,umd --target node --external preact",
|
|
47
|
+
"transpile:jsx": "microbundle src/jsx.js -o dist/jsx.js --target web --external preact && microbundle dist/jsx.js -o dist/jsx.js -f cjs --external preact",
|
|
48
|
+
"copy-typescript-definition": "copyfiles -f src/*.d.ts dist",
|
|
49
|
+
"test": "eslint src test && tsc && npm run test:mocha && npm run test:mocha:compat && npm run test:mocha:debug && npm run bench",
|
|
50
|
+
"test:mocha": "BABEL_ENV=test mocha -r @babel/register -r test/setup.js test/*.test.jsx",
|
|
51
|
+
"test:mocha:compat": "BABEL_ENV=test mocha -r @babel/register -r test/setup.js 'test/compat/*.test.js' 'test/compat/*.test.jsx'",
|
|
52
|
+
"test:mocha:debug": "BABEL_ENV=test mocha -r @babel/register -r test/setup.js 'test/debug/*.test.jsx'",
|
|
53
|
+
"format": "prettier src/**/*.{d.ts,js} test/**/*.js --write",
|
|
54
|
+
"prepublishOnly": "npm run build",
|
|
55
|
+
"release": "npm run build && git commit -am $npm_package_version && git tag $npm_package_version && git push && git push --tags && npm publish"
|
|
56
|
+
},
|
|
57
|
+
"keywords": [
|
|
58
|
+
"preact",
|
|
59
|
+
"render",
|
|
60
|
+
"universal",
|
|
61
|
+
"isomorphic"
|
|
62
|
+
],
|
|
63
|
+
"files": [
|
|
64
|
+
"src",
|
|
65
|
+
"dist",
|
|
66
|
+
"jsx.js",
|
|
67
|
+
"jsx.d.ts",
|
|
68
|
+
"typings.json"
|
|
69
|
+
],
|
|
70
|
+
"eslintConfig": {
|
|
71
|
+
"extends": "developit",
|
|
72
|
+
"rules": {
|
|
73
|
+
"react/prefer-stateless-function": 0,
|
|
74
|
+
"react/jsx-no-bind": 0,
|
|
75
|
+
"react/no-danger": 0,
|
|
76
|
+
"jest/valid-expect": 0,
|
|
77
|
+
"new-cap": 0,
|
|
78
|
+
"curly": "off",
|
|
79
|
+
"brace-style": "off",
|
|
80
|
+
"indent": "off",
|
|
81
|
+
"lines-around-comment": "off"
|
|
82
|
+
},
|
|
83
|
+
"settings": {
|
|
84
|
+
"react": {
|
|
85
|
+
"version": "16.8"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"babel": {
|
|
90
|
+
"env": {
|
|
91
|
+
"test": {
|
|
92
|
+
"presets": [
|
|
93
|
+
[
|
|
94
|
+
"@babel/preset-env",
|
|
95
|
+
{
|
|
96
|
+
"targets": {
|
|
97
|
+
"node": true
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
],
|
|
102
|
+
"plugins": [
|
|
103
|
+
[
|
|
104
|
+
"@babel/plugin-transform-react-jsx",
|
|
105
|
+
{
|
|
106
|
+
"pragma": "h"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"minify": {
|
|
114
|
+
"compress": {
|
|
115
|
+
"reduce_funcs": false
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"author": "The Preact Authors (https://github.com/preactjs/preact/contributors)",
|
|
119
|
+
"license": "MIT",
|
|
120
|
+
"repository": {
|
|
121
|
+
"type": "git",
|
|
122
|
+
"url": "https://github.com/preactjs/preact-render-to-string"
|
|
123
|
+
},
|
|
124
|
+
"bugs": "https://github.com/preactjs/preact-render-to-string/issues",
|
|
125
|
+
"homepage": "https://github.com/preactjs/preact-render-to-string",
|
|
126
|
+
"peerDependencies": {
|
|
127
|
+
"preact": ">=10"
|
|
128
|
+
},
|
|
129
|
+
"devDependencies": {
|
|
130
|
+
"@babel/plugin-transform-react-jsx": "^7.12.12",
|
|
131
|
+
"@babel/preset-env": "^7.12.11",
|
|
132
|
+
"@babel/register": "^7.12.10",
|
|
133
|
+
"@changesets/changelog-github": "^0.4.1",
|
|
134
|
+
"@changesets/cli": "^2.18.0",
|
|
135
|
+
"benchmarkjs-pretty": "^2.0.1",
|
|
136
|
+
"chai": "^4.2.0",
|
|
137
|
+
"copyfiles": "^2.4.1",
|
|
138
|
+
"eslint": "^7.16.0",
|
|
139
|
+
"eslint-config-developit": "^1.2.0",
|
|
140
|
+
"husky": "^4.3.6",
|
|
141
|
+
"lint-staged": "^10.5.3",
|
|
142
|
+
"microbundle": "^0.15.1",
|
|
143
|
+
"mocha": "^8.2.1",
|
|
144
|
+
"baseline-rts": "npm:preact-render-to-string@latest",
|
|
145
|
+
"preact": "^10.13.0",
|
|
146
|
+
"prettier": "^2.2.1",
|
|
147
|
+
"sinon": "^9.2.2",
|
|
148
|
+
"sinon-chai": "^3.5.0",
|
|
149
|
+
"typescript": "^5.0.0",
|
|
150
|
+
"web-streams-polyfill": "^3.2.1"
|
|
151
|
+
},
|
|
152
|
+
"dependencies": {
|
|
153
|
+
"pretty-format": "^3.8.0"
|
|
154
|
+
},
|
|
155
|
+
"prettier": {
|
|
156
|
+
"singleQuote": true,
|
|
157
|
+
"trailingComma": "none",
|
|
158
|
+
"useTabs": true,
|
|
159
|
+
"tabWidth": 2
|
|
160
|
+
},
|
|
161
|
+
"lint-staged": {
|
|
162
|
+
"**/*.{js,jsx,ts,tsx,yml}": [
|
|
163
|
+
"prettier --write"
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
"husky": {
|
|
167
|
+
"hooks": {
|
|
168
|
+
"pre-commit": "lint-staged"
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
"publishConfig": {
|
|
172
|
+
"provenance": true
|
|
173
|
+
}
|
|
159
174
|
}
|
package/src/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
NAMESPACE_REPLACE_REGEX,
|
|
6
6
|
HTML_LOWER_CASE,
|
|
7
7
|
SVG_CAMEL_CASE
|
|
8
|
-
} from './util.js';
|
|
8
|
+
} from './lib/util.js';
|
|
9
9
|
import { options, h, Fragment } from 'preact';
|
|
10
10
|
import {
|
|
11
11
|
CHILDREN,
|
|
@@ -18,10 +18,9 @@ import {
|
|
|
18
18
|
PARENT,
|
|
19
19
|
RENDER,
|
|
20
20
|
SKIP_EFFECTS,
|
|
21
|
-
VNODE
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/** @typedef {import('preact').VNode} VNode */
|
|
21
|
+
VNODE,
|
|
22
|
+
CATCH_ERROR
|
|
23
|
+
} from './lib/constants.js';
|
|
25
24
|
|
|
26
25
|
const EMPTY_ARR = [];
|
|
27
26
|
const isArray = Array.isArray;
|
|
@@ -34,9 +33,10 @@ let beforeDiff, afterDiff, renderHook, ummountHook;
|
|
|
34
33
|
* Render Preact JSX + Components to an HTML string.
|
|
35
34
|
* @param {VNode} vnode JSX Element / VNode to render
|
|
36
35
|
* @param {Object} [context={}] Initial root context object
|
|
36
|
+
* @param {RendererState} [_rendererState] for internal use
|
|
37
37
|
* @returns {string} serialized HTML
|
|
38
38
|
*/
|
|
39
|
-
export function renderToString(vnode, context) {
|
|
39
|
+
export function renderToString(vnode, context, _rendererState) {
|
|
40
40
|
// Performance optimization: `renderToString` is synchronous and we
|
|
41
41
|
// therefore don't execute any effects. To do that we pass an empty
|
|
42
42
|
// array to `options._commit` (`__c`). But we can go one step further
|
|
@@ -61,7 +61,8 @@ export function renderToString(vnode, context) {
|
|
|
61
61
|
false,
|
|
62
62
|
undefined,
|
|
63
63
|
parent,
|
|
64
|
-
false
|
|
64
|
+
false,
|
|
65
|
+
_rendererState
|
|
65
66
|
);
|
|
66
67
|
} catch (e) {
|
|
67
68
|
if (e.then) {
|
|
@@ -109,7 +110,8 @@ export async function renderToStringAsync(vnode, context) {
|
|
|
109
110
|
false,
|
|
110
111
|
undefined,
|
|
111
112
|
parent,
|
|
112
|
-
true
|
|
113
|
+
true,
|
|
114
|
+
undefined
|
|
113
115
|
);
|
|
114
116
|
|
|
115
117
|
if (Array.isArray(rendered)) {
|
|
@@ -204,6 +206,7 @@ function renderClassComponent(vnode, context) {
|
|
|
204
206
|
* @param {any} selectValue
|
|
205
207
|
* @param {VNode} parent
|
|
206
208
|
* @param {boolean} asyncMode
|
|
209
|
+
* @param {RendererState | undefined} [renderer]
|
|
207
210
|
* @returns {string | Promise<string> | (string | Promise<string>)[]}
|
|
208
211
|
*/
|
|
209
212
|
function _renderToString(
|
|
@@ -212,7 +215,8 @@ function _renderToString(
|
|
|
212
215
|
isSvgMode,
|
|
213
216
|
selectValue,
|
|
214
217
|
parent,
|
|
215
|
-
asyncMode
|
|
218
|
+
asyncMode,
|
|
219
|
+
renderer
|
|
216
220
|
) {
|
|
217
221
|
// Ignore non-rendered VNodes/values
|
|
218
222
|
if (vnode == null || vnode === true || vnode === false || vnode === '') {
|
|
@@ -240,7 +244,8 @@ function _renderToString(
|
|
|
240
244
|
isSvgMode,
|
|
241
245
|
selectValue,
|
|
242
246
|
parent,
|
|
243
|
-
asyncMode
|
|
247
|
+
asyncMode,
|
|
248
|
+
renderer
|
|
244
249
|
);
|
|
245
250
|
|
|
246
251
|
if (typeof childRender === 'string') {
|
|
@@ -305,7 +310,8 @@ function _renderToString(
|
|
|
305
310
|
isSvgMode,
|
|
306
311
|
selectValue,
|
|
307
312
|
vnode,
|
|
308
|
-
asyncMode
|
|
313
|
+
asyncMode,
|
|
314
|
+
renderer
|
|
309
315
|
);
|
|
310
316
|
} else {
|
|
311
317
|
// Values are pre-escaped by the JSX transform
|
|
@@ -386,7 +392,8 @@ function _renderToString(
|
|
|
386
392
|
isSvgMode,
|
|
387
393
|
selectValue,
|
|
388
394
|
vnode,
|
|
389
|
-
asyncMode
|
|
395
|
+
asyncMode,
|
|
396
|
+
renderer
|
|
390
397
|
);
|
|
391
398
|
return str;
|
|
392
399
|
} catch (err) {
|
|
@@ -418,7 +425,8 @@ function _renderToString(
|
|
|
418
425
|
isSvgMode,
|
|
419
426
|
selectValue,
|
|
420
427
|
vnode,
|
|
421
|
-
asyncMode
|
|
428
|
+
asyncMode,
|
|
429
|
+
renderer
|
|
422
430
|
);
|
|
423
431
|
}
|
|
424
432
|
|
|
@@ -449,16 +457,38 @@ function _renderToString(
|
|
|
449
457
|
isSvgMode,
|
|
450
458
|
selectValue,
|
|
451
459
|
vnode,
|
|
452
|
-
asyncMode
|
|
460
|
+
asyncMode,
|
|
461
|
+
renderer
|
|
453
462
|
);
|
|
454
463
|
|
|
455
464
|
if (afterDiff) afterDiff(vnode);
|
|
465
|
+
// when we are dealing with suspense we can't do this...
|
|
456
466
|
vnode[PARENT] = null;
|
|
457
467
|
|
|
458
|
-
if (
|
|
468
|
+
if (options.unmount) options.unmount(vnode);
|
|
459
469
|
|
|
460
470
|
return str;
|
|
461
471
|
} catch (error) {
|
|
472
|
+
if (!asyncMode && renderer && renderer.onError) {
|
|
473
|
+
let res = renderer.onError(error, vnode, (child) =>
|
|
474
|
+
_renderToString(
|
|
475
|
+
child,
|
|
476
|
+
context,
|
|
477
|
+
isSvgMode,
|
|
478
|
+
selectValue,
|
|
479
|
+
vnode,
|
|
480
|
+
asyncMode,
|
|
481
|
+
renderer
|
|
482
|
+
)
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
if (res !== undefined) return res;
|
|
486
|
+
|
|
487
|
+
let errorHook = options[CATCH_ERROR];
|
|
488
|
+
if (errorHook) errorHook(error, vnode);
|
|
489
|
+
return '';
|
|
490
|
+
}
|
|
491
|
+
|
|
462
492
|
if (!asyncMode) throw error;
|
|
463
493
|
|
|
464
494
|
if (!error || typeof error.then !== 'function') throw error;
|
|
@@ -471,7 +501,8 @@ function _renderToString(
|
|
|
471
501
|
isSvgMode,
|
|
472
502
|
selectValue,
|
|
473
503
|
vnode,
|
|
474
|
-
asyncMode
|
|
504
|
+
asyncMode,
|
|
505
|
+
renderer
|
|
475
506
|
);
|
|
476
507
|
} catch (e) {
|
|
477
508
|
if (!e || typeof e.then !== 'function') throw e;
|
|
@@ -484,7 +515,8 @@ function _renderToString(
|
|
|
484
515
|
isSvgMode,
|
|
485
516
|
selectValue,
|
|
486
517
|
vnode,
|
|
487
|
-
asyncMode
|
|
518
|
+
asyncMode,
|
|
519
|
+
renderer
|
|
488
520
|
),
|
|
489
521
|
() => renderNestedChildren()
|
|
490
522
|
);
|
|
@@ -628,12 +660,16 @@ function _renderToString(
|
|
|
628
660
|
childSvgMode,
|
|
629
661
|
selectValue,
|
|
630
662
|
vnode,
|
|
631
|
-
asyncMode
|
|
663
|
+
asyncMode,
|
|
664
|
+
renderer
|
|
632
665
|
);
|
|
633
666
|
}
|
|
634
667
|
|
|
635
668
|
if (afterDiff) afterDiff(vnode);
|
|
669
|
+
|
|
670
|
+
// TODO: this was commented before
|
|
636
671
|
vnode[PARENT] = null;
|
|
672
|
+
|
|
637
673
|
if (ummountHook) ummountHook(vnode);
|
|
638
674
|
|
|
639
675
|
// Emit self-closing tag for empty void elements:
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ComponentChildren, VNode } from 'preact';
|
|
2
|
+
|
|
3
|
+
interface Suspended {
|
|
4
|
+
id: string;
|
|
5
|
+
promise: Promise<any>;
|
|
6
|
+
context: any;
|
|
7
|
+
isSvgMode: boolean;
|
|
8
|
+
selectValue: any;
|
|
9
|
+
vnode: VNode;
|
|
10
|
+
parent: VNode | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface RendererErrorHandler {
|
|
14
|
+
(
|
|
15
|
+
this: RendererState,
|
|
16
|
+
error: any,
|
|
17
|
+
vnode: VNode<{ fallback: any }>,
|
|
18
|
+
renderChild: (child: ComponentChildren) => string
|
|
19
|
+
): string | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface RendererState {
|
|
23
|
+
start: number;
|
|
24
|
+
suspended: Suspended[];
|
|
25
|
+
abortSignal?: AbortSignal | undefined;
|
|
26
|
+
onWrite: (str: string) => void;
|
|
27
|
+
onError?: RendererErrorHandler;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface RenderToChunksOptions {
|
|
31
|
+
context?: any;
|
|
32
|
+
onError?: (error: any) => void;
|
|
33
|
+
onWrite: (str: string) => void;
|
|
34
|
+
abortSignal?: AbortSignal;
|
|
35
|
+
}
|
package/src/jsx.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import './polyfills.js';
|
|
1
|
+
import './lib/polyfills.js';
|
|
2
2
|
import renderToString from './pretty.js';
|
|
3
|
-
import { indent, encodeEntities } from './util.js';
|
|
3
|
+
import { indent, encodeEntities } from './lib/util.js';
|
|
4
4
|
import prettyFormat from 'pretty-format';
|
|
5
5
|
|
|
6
|
-
/** @typedef {import('preact').VNode} VNode */
|
|
7
|
-
|
|
8
6
|
// we have to patch in Array support, Possible issue in npm.im/pretty-format
|
|
9
7
|
let preactPlugin = {
|
|
10
8
|
test(object) {
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { renderToString } from '../index.js';
|
|
2
|
+
import { CHILD_DID_SUSPEND, COMPONENT, PARENT } from './constants.js';
|
|
3
|
+
import { Deferred } from './util.js';
|
|
4
|
+
import { createInitScript, createSubtree } from './client.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {VNode} vnode
|
|
8
|
+
* @param {RenderToChunksOptions} options
|
|
9
|
+
* @returns {Promise<void>}
|
|
10
|
+
*/
|
|
11
|
+
export async function renderToChunks(vnode, { context, onWrite, abortSignal }) {
|
|
12
|
+
context = context || {};
|
|
13
|
+
|
|
14
|
+
/** @type {RendererState} */
|
|
15
|
+
const renderer = {
|
|
16
|
+
start: Date.now(),
|
|
17
|
+
abortSignal,
|
|
18
|
+
onWrite,
|
|
19
|
+
onError: handleError,
|
|
20
|
+
suspended: []
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Synchronously render the shell
|
|
24
|
+
// @ts-ignore - using third internal RendererState argument
|
|
25
|
+
const shell = renderToString(vnode, context, renderer);
|
|
26
|
+
onWrite(shell);
|
|
27
|
+
|
|
28
|
+
// Wait for any suspended sub-trees if there are any
|
|
29
|
+
const len = renderer.suspended.length;
|
|
30
|
+
if (len > 0) {
|
|
31
|
+
onWrite('<div hidden>');
|
|
32
|
+
onWrite(createInitScript(len));
|
|
33
|
+
// We should keep checking all promises
|
|
34
|
+
await forkPromises(renderer);
|
|
35
|
+
onWrite('</div>');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function forkPromises(renderer) {
|
|
40
|
+
if (renderer.suspended.length > 0) {
|
|
41
|
+
const suspensions = [...renderer.suspended];
|
|
42
|
+
await Promise.all(renderer.suspended.map((s) => s.promise));
|
|
43
|
+
renderer.suspended = renderer.suspended.filter(
|
|
44
|
+
(s) => !suspensions.includes(s)
|
|
45
|
+
);
|
|
46
|
+
await forkPromises(renderer);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** @type {RendererErrorHandler} */
|
|
51
|
+
function handleError(error, vnode, renderChild) {
|
|
52
|
+
if (!error || !error.then) return;
|
|
53
|
+
|
|
54
|
+
// walk up to the Suspense boundary
|
|
55
|
+
while ((vnode = vnode[PARENT])) {
|
|
56
|
+
let component = vnode[COMPONENT];
|
|
57
|
+
if (component && component[CHILD_DID_SUSPEND]) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!vnode) return;
|
|
63
|
+
|
|
64
|
+
const id = vnode.__v;
|
|
65
|
+
const found = this.suspended.find((x) => x.id === id);
|
|
66
|
+
const race = new Deferred();
|
|
67
|
+
|
|
68
|
+
const abortSignal = this.abortSignal;
|
|
69
|
+
if (abortSignal) {
|
|
70
|
+
// @ts-ignore 2554 - implicit undefined arg
|
|
71
|
+
if (abortSignal.aborted) race.resolve();
|
|
72
|
+
else abortSignal.addEventListener('abort', race.resolve);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const promise = error.then(
|
|
76
|
+
() => {
|
|
77
|
+
if (abortSignal && abortSignal.aborted) return;
|
|
78
|
+
const child = renderChild(vnode.props.children);
|
|
79
|
+
if (child) this.onWrite(createSubtree(id, child));
|
|
80
|
+
},
|
|
81
|
+
// TODO: Abort and send hydration code snippet to client
|
|
82
|
+
// to attempt to recover during hydration
|
|
83
|
+
this.onError
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
this.suspended.push({
|
|
87
|
+
id,
|
|
88
|
+
vnode,
|
|
89
|
+
promise: Promise.race([promise, race.promise])
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const fallback = renderChild(vnode.props.fallback);
|
|
93
|
+
|
|
94
|
+
return found
|
|
95
|
+
? ''
|
|
96
|
+
: `<!--preact-island:${id}-->${fallback}<!--/preact-island:${id}-->`;
|
|
97
|
+
}
|