preact-render-to-string 6.4.2 → 6.5.0

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.
Files changed (43) hide show
  1. package/dist/commonjs.js +1 -1
  2. package/dist/commonjs.js.map +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +1 -1
  5. package/dist/index.module.js +1 -1
  6. package/dist/index.module.js.map +1 -1
  7. package/dist/index.umd.js +1 -1
  8. package/dist/index.umd.js.map +1 -1
  9. package/dist/internal.d.ts +35 -0
  10. package/dist/jsx-entry.js +1 -1
  11. package/dist/jsx-entry.js.map +1 -1
  12. package/dist/jsx.js.map +1 -1
  13. package/dist/jsx.mjs +1 -1
  14. package/dist/jsx.mjs.map +1 -1
  15. package/dist/jsx.module.js +1 -1
  16. package/dist/jsx.module.js.map +1 -1
  17. package/dist/jsx.umd.js +1 -1
  18. package/dist/jsx.umd.js.map +1 -1
  19. package/dist/stream-node.js +786 -0
  20. package/dist/stream-node.js.map +1 -0
  21. package/dist/stream-node.module.js +786 -0
  22. package/dist/stream-node.module.js.map +1 -0
  23. package/dist/stream-node.umd.js +790 -0
  24. package/dist/stream-node.umd.js.map +1 -0
  25. package/dist/stream.js +2 -0
  26. package/dist/stream.js.map +1 -0
  27. package/dist/stream.module.js +2 -0
  28. package/dist/stream.module.js.map +1 -0
  29. package/dist/stream.umd.js +2 -0
  30. package/dist/stream.umd.js.map +1 -0
  31. package/jsx.d.ts +1 -1
  32. package/package.json +166 -157
  33. package/src/index.js +54 -18
  34. package/src/internal.d.ts +35 -0
  35. package/src/jsx.js +2 -4
  36. package/src/lib/chunked.js +97 -0
  37. package/src/lib/client.js +61 -0
  38. package/src/{constants.js → lib/constants.js} +3 -0
  39. package/src/{util.js → lib/util.js} +13 -1
  40. package/src/pretty.js +13 -13
  41. package/src/stream-node.js +60 -0
  42. package/src/stream.js +43 -0
  43. /package/src/{polyfills.js → lib/polyfills.js} +0 -0
@@ -0,0 +1,61 @@
1
+ /* eslint-disable no-var, key-spacing, object-curly-spacing, prefer-arrow-callback, semi, keyword-spacing */
2
+
3
+ function initPreactIslandElement() {
4
+ class PreactIslandElement extends HTMLElement {
5
+ connectedCallback() {
6
+ var d = this;
7
+ if (!d.isConnected) return;
8
+
9
+ let i = this.getAttribute('data-target');
10
+ if (!i) return;
11
+
12
+ var s,
13
+ e,
14
+ c = document.createNodeIterator(document, 128);
15
+ while (c.nextNode()) {
16
+ let n = c.referenceNode;
17
+
18
+ if (n.data == 'preact-island:' + i) s = n;
19
+ else if (n.data == '/preact-island:' + i) e = n;
20
+ if (s && e) break;
21
+ }
22
+ if (s && e) {
23
+ var p = e.previousSibling;
24
+ while (p != s) {
25
+ if (!p || p == s) break;
26
+ e.parentNode.removeChild(p);
27
+ p = e.previousSibling;
28
+ }
29
+
30
+ requestAnimationFrame(() => {
31
+ for (let i = 0; i <= d.children.length; i++) {
32
+ const child = d.children[i];
33
+ e.parentNode.insertBefore(child, e);
34
+ }
35
+
36
+ d.parentNode.removeChild(d);
37
+ });
38
+ }
39
+ }
40
+ }
41
+
42
+ customElements.define('preact-island', PreactIslandElement);
43
+ }
44
+
45
+ const fn = initPreactIslandElement.toString();
46
+ const INIT_SCRIPT = fn
47
+ .slice(fn.indexOf('{') + 1, fn.lastIndexOf('}'))
48
+ .replace(/\n\s+/gm, '');
49
+
50
+ export function createInitScript() {
51
+ return `<script>(function(){${INIT_SCRIPT}}())</script>`;
52
+ }
53
+
54
+ /**
55
+ * @param {string} id
56
+ * @param {string} content
57
+ * @returns {string}
58
+ */
59
+ export function createSubtree(id, content) {
60
+ return `<preact-island hidden data-target="${id}">${content}</preact-island>`;
61
+ }
@@ -4,13 +4,16 @@ export const RENDER = '__r';
4
4
  export const DIFFED = 'diffed';
5
5
  export const COMMIT = '__c';
6
6
  export const SKIP_EFFECTS = '__s';
7
+ export const CATCH_ERROR = '__e';
7
8
 
8
9
  // VNode properties
9
10
  export const COMPONENT = '__c';
10
11
  export const CHILDREN = '__k';
11
12
  export const PARENT = '__';
13
+ export const MASK = '__m';
12
14
 
13
15
  // Component properties
14
16
  export const VNODE = '__v';
15
17
  export const DIRTY = '__d';
16
18
  export const NEXT_STATE = '__s';
19
+ export const CHILD_DID_SUSPEND = '__c';
@@ -1,7 +1,7 @@
1
1
  export const VOID_ELEMENTS = /^(?:area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/;
2
2
  export const UNSAFE_NAME = /[\s\n\\/='"\0<>]/;
3
3
  export const NAMESPACE_REPLACE_REGEX = /^(xlink|xmlns|xml)([A-Z])/;
4
- export const HTML_LOWER_CASE = /^accessK|^auto[A-Z]|^ch|^col|cont|cross|dateT|encT|form[A-Z]|frame|hrefL|inputM|maxL|minL|noV|playsI|readO|rowS|spellC|src[A-Z]|tabI|item[A-Z]/;
4
+ export const HTML_LOWER_CASE = /^accessK|^auto[A-Z]|^cell|^ch|^col|cont|cross|dateT|encT|form[A-Z]|frame|hrefL|inputM|maxL|minL|noV|playsI|popoverT|readO|rowS|spellC|src[A-Z]|tabI|useM|item[A-Z]/;
5
5
  export const SVG_CAMEL_CASE = /^ac|^ali|arabic|basel|cap|clipPath$|clipRule$|color|dominant|enable|fill|flood|font|glyph[^R]|horiz|image|letter|lighting|marker[^WUH]|overline|panose|pointe|paint|rendering|shape|stop|strikethrough|stroke|text[^L]|transform|underline|unicode|units|^v[^i]|^w|^xH/;
6
6
 
7
7
  // DOM properties that should NOT have "px" added when numeric
@@ -151,6 +151,18 @@ export function createComponent(vnode, context) {
151
151
  };
152
152
  }
153
153
 
154
+ // Necessary for createContext api. Setting this property will pass
155
+ // the context value as `this.context` just for this component.
156
+ export function getContext(nodeName, context) {
157
+ let cxType = nodeName.contextType;
158
+ let provider = cxType && context[cxType.__c];
159
+ return cxType != null
160
+ ? provider
161
+ ? provider.props.value
162
+ : cxType.__
163
+ : context;
164
+ }
165
+
154
166
  /**
155
167
  * @template T
156
168
  */
package/src/pretty.js CHANGED
@@ -8,14 +8,13 @@ import {
8
8
  UNSAFE_NAME,
9
9
  VOID_ELEMENTS,
10
10
  NAMESPACE_REPLACE_REGEX,
11
+ SVG_CAMEL_CASE,
11
12
  HTML_LOWER_CASE,
12
- SVG_CAMEL_CASE
13
- } from './util.js';
14
- import { COMMIT, DIFF, DIFFED, RENDER, SKIP_EFFECTS } from './constants.js';
13
+ getContext
14
+ } from './lib/util.js';
15
+ import { COMMIT, DIFF, DIFFED, RENDER, SKIP_EFFECTS } from './lib/constants.js';
15
16
  import { options, Fragment } from 'preact';
16
17
 
17
- /** @typedef {import('preact').VNode} VNode */
18
-
19
18
  // components without names, kept as a hash for later comparison to return consistent UnnamedComponentXX names.
20
19
  const UNNAMED = [];
21
20
 
@@ -104,7 +103,11 @@ function _renderToStringPretty(
104
103
  // components
105
104
  if (typeof nodeName === 'function') {
106
105
  isComponent = true;
107
- if (opts.shallow && (inner || opts.renderRootComponent === false)) {
106
+ if (
107
+ opts.shallow &&
108
+ (inner || opts.renderRootComponent === false) &&
109
+ nodeName !== Fragment
110
+ ) {
108
111
  nodeName = getComponentName(nodeName);
109
112
  } else if (nodeName === Fragment) {
110
113
  const children = [];
@@ -124,17 +127,12 @@ function _renderToStringPretty(
124
127
 
125
128
  let renderHook = options[RENDER];
126
129
 
127
- let cctx = context;
128
- let cxType = nodeName.contextType;
129
- if (cxType != null) {
130
- let provider = context[cxType.__c];
131
- cctx = provider ? provider.props.value : cxType.__;
132
- }
133
-
134
130
  if (
135
131
  !nodeName.prototype ||
136
132
  typeof nodeName.prototype.render !== 'function'
137
133
  ) {
134
+ let cctx = getContext(nodeName, context);
135
+
138
136
  // If a hook invokes setState() to invalidate the component during rendering,
139
137
  // re-render it up to 25 times to allow "settling" of memoized states.
140
138
  // Note:
@@ -150,6 +148,8 @@ function _renderToStringPretty(
150
148
  rendered = nodeName.call(vnode.__c, props, cctx);
151
149
  }
152
150
  } else {
151
+ let cctx = getContext(nodeName, context);
152
+
153
153
  // c = new nodeName(props, context);
154
154
  c = vnode.__c = new nodeName(props, cctx);
155
155
  c.__v = vnode;
@@ -0,0 +1,60 @@
1
+ import { PassThrough } from 'node:stream';
2
+ import { renderToChunks } from './lib/chunked.js';
3
+
4
+ /**
5
+ * @typedef {object} RenderToPipeableStreamOptions
6
+ * @property {() => void} [onShellReady]
7
+ * @property {() => void} [onAllReady]
8
+ * @property {(error) => void} [onError]
9
+ */
10
+
11
+ /**
12
+ * @param {import('preact').VNode} vnode
13
+ * @param {RenderToPipeableStreamOptions} options
14
+ * @param {any} [context]
15
+ * @returns {{}}
16
+ */
17
+ export function renderToPipeableStream(vnode, options, context) {
18
+ const encoder = new TextEncoder('utf-8');
19
+
20
+ const controller = new AbortController();
21
+ const stream = new PassThrough();
22
+
23
+ renderToChunks(vnode, {
24
+ context,
25
+ abortSignal: controller.signal,
26
+ onError: (error) => {
27
+ if (options.onError) {
28
+ options.onError(error);
29
+ }
30
+ controller.abort(error);
31
+ },
32
+ onWrite(s) {
33
+ stream.write(encoder.encode(s));
34
+ }
35
+ })
36
+ .then(() => {
37
+ options.onAllReady && options.onAllReady();
38
+ stream.end();
39
+ })
40
+ .catch((error) => {
41
+ stream.destroy(error);
42
+ });
43
+
44
+ Promise.resolve().then(() => {
45
+ options.onShellReady && options.onShellReady();
46
+ });
47
+
48
+ return {
49
+ abort() {
50
+ controller.abort();
51
+ stream.destroy(new Error('aborted'));
52
+ },
53
+ /**
54
+ * @param {import("stream").Writable} writable
55
+ */
56
+ pipe(writable) {
57
+ stream.pipe(writable, { end: true });
58
+ }
59
+ };
60
+ }
package/src/stream.js ADDED
@@ -0,0 +1,43 @@
1
+ import { Deferred } from './lib/util.js';
2
+ import { renderToChunks } from './lib/chunked.js';
3
+
4
+ /** @typedef {ReadableStream<Uint8Array> & { allReady: Promise<void>}} RenderStream */
5
+
6
+ /**
7
+ * @param {import('preact').VNode} vnode
8
+ * @param {any} [context]
9
+ * @returns {RenderStream}
10
+ */
11
+ export function renderToReadableStream(vnode, context) {
12
+ /** @type {Deferred<void>} */
13
+ const allReady = new Deferred();
14
+ const encoder = new TextEncoder('utf-8');
15
+
16
+ /** @type {RenderStream} */
17
+ const stream = new ReadableStream({
18
+ start(controller) {
19
+ renderToChunks(vnode, {
20
+ context,
21
+ onError: (error) => {
22
+ allReady.reject(error);
23
+ controller.abort(error);
24
+ },
25
+ onWrite(s) {
26
+ controller.enqueue(encoder.encode(s));
27
+ }
28
+ })
29
+ .then(() => {
30
+ controller.close();
31
+ allReady.resolve();
32
+ })
33
+ .catch((error) => {
34
+ controller.error(error);
35
+ allReady.reject(error);
36
+ });
37
+ }
38
+ });
39
+
40
+ stream.allReady = allReady.promise;
41
+
42
+ return stream;
43
+ }
File without changes