Skip to content

Commit

Permalink
non breaking
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock committed Feb 9, 2024
1 parent 5f7559d commit 80c0a70
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 19 deletions.
7 changes: 4 additions & 3 deletions .changeset/pink-gifts-kneel.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
"preact-render-to-string": major
"preact-render-to-string": minor
---

Allow prepass like behavior in renderToString where a Promise
will be awaited and then continued
Allow prepass like behavior where a Promise
will be awaited and then continued, this is done with
the new `renderToStringAsync` export
12 changes: 5 additions & 7 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ import { VNode } from 'preact';
export default function renderToString<P = {}>(
vnode: VNode<P>,
context?: any
): string | Promise<string>;
): string;

export function render<P = {}>(
vnode: VNode<P>,
context?: any
): string | Promise<string>;
export function renderToString<P = {}>(
export function render<P = {}>(vnode: VNode<P>, context?: any): string;
export function renderToString<P = {}>(vnode: VNode<P>, context?: any): string;
export function renderToStringAsync<P = {}>(
vnode: VNode<P>,
context?: any
): string | Promise<string>;
export function renderToStaticMarkup<P = {}>(
vnode: VNode<P>,
context?: any
): string | Promise<string>;
): string;
96 changes: 87 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,62 @@ export function renderToString(vnode, context) {
const parent = h(Fragment, null);
parent[CHILDREN] = [vnode];

try {
return _renderToString(
vnode,
context || EMPTY_OBJ,
false,
undefined,
parent,
false
);
} catch (e) {
if (e.then) {
throw new Error('Use "renderToStringAsync" for suspenseful rendering.');
}

throw e;
} finally {
// options._commit, we don't schedule any effects in this library right now,
// so we can pass an empty queue to this hook.
if (options[COMMIT]) options[COMMIT](vnode, EMPTY_ARR);
options[SKIP_EFFECTS] = previousSkipEffects;
EMPTY_ARR.length = 0;
}
}

/**
* Render Preact JSX + Components to an HTML string.
* @param {VNode} vnode JSX Element / VNode to render
* @param {Object} [context={}] Initial root context object
* @returns {string} serialized HTML
*/
export function renderToStringAsync(vnode, context) {
// Performance optimization: `renderToString` is synchronous and we
// therefore don't execute any effects. To do that we pass an empty
// array to `options._commit` (`__c`). But we can go one step further
// and avoid a lot of dirty checks and allocations by setting
// `options._skipEffects` (`__s`) too.
const previousSkipEffects = options[SKIP_EFFECTS];
options[SKIP_EFFECTS] = true;

// store options hooks once before each synchronous render call
beforeDiff = options[DIFF];
afterDiff = options[DIFFED];
renderHook = options[RENDER];
ummountHook = options.unmount;

const parent = h(Fragment, null);
parent[CHILDREN] = [vnode];

try {
const rendered = _renderToString(
vnode,
context || EMPTY_OBJ,
false,
undefined,
parent
parent,
true
);

if (Array.isArray(rendered)) {
Expand Down Expand Up @@ -143,9 +192,17 @@ function renderClassComponent(vnode, context) {
* @param {boolean} isSvgMode
* @param {any} selectValue
* @param {VNode} parent
* @param {boolean} asyncMode
* @returns {string | Promise<string> | (string | Promise<string>)[]}
*/
function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
function _renderToString(
vnode,
context,
isSvgMode,
selectValue,
parent,
asyncMode
) {
// Ignore non-rendered VNodes/values
if (vnode == null || vnode === true || vnode === false || vnode === '') {
return '';
Expand All @@ -171,7 +228,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
context,
isSvgMode,
selectValue,
parent
parent,
asyncMode
);

if (typeof childRender === 'string') {
Expand Down Expand Up @@ -235,7 +293,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
context,
isSvgMode,
selectValue,
vnode
vnode,
asyncMode
);
} else {
// Values are pre-escaped by the JSX transform
Expand Down Expand Up @@ -315,7 +374,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
context,
isSvgMode,
selectValue,
vnode
vnode,
asyncMode
);
return str;
} catch (err) {
Expand Down Expand Up @@ -346,7 +406,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
context,
isSvgMode,
selectValue,
vnode
vnode,
asyncMode
);
}

Expand All @@ -373,7 +434,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
context,
isSvgMode,
selectValue,
vnode
vnode,
asyncMode
);
if (afterDiff) afterDiff(vnode);
vnode[PARENT] = undefined;
Expand All @@ -382,10 +444,19 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {

return str;
} catch (error) {
if (!asyncMode) throw error;

if (!error || typeof error.then !== 'function') throw error;

return error.then(() =>
_renderToString(rendered, context, isSvgMode, selectValue, vnode)
_renderToString(
rendered,
context,
isSvgMode,
selectValue,
vnode,
asyncMode
)
);
}
}
Expand Down Expand Up @@ -517,7 +588,14 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) {
// recurse into this element VNode's children
let childSvgMode =
type === 'svg' || (type !== 'foreignObject' && isSvgMode);
html = _renderToString(children, context, childSvgMode, selectValue, vnode);
html = _renderToString(
children,
context,
childSvgMode,
selectValue,
vnode,
asyncMode
);
}

if (afterDiff) afterDiff(vnode);
Expand Down

0 comments on commit 80c0a70

Please sign in to comment.