11import { encodeEntities , styleObjToCss , UNSAFE_NAME , XLINK } from './util' ;
2- import { options , Fragment } from 'preact' ;
2+ import { options , h , Fragment } from 'preact' ;
33import {
4+ CHILDREN ,
45 COMMIT ,
56 COMPONENT ,
67 DIFF ,
78 DIFFED ,
89 DIRTY ,
910 NEXT_STATE ,
11+ PARENT ,
1012 RENDER ,
1113 SKIP_EFFECTS ,
1214 VNODE
@@ -41,8 +43,11 @@ export default function renderToString(vnode, context) {
4143 afterDiff = options [ DIFFED ] ;
4244 renderHook = options [ RENDER ] ;
4345
46+ const parent = h ( Fragment , null ) ;
47+ parent [ CHILDREN ] = [ vnode ] ;
48+
4449 try {
45- return _renderToString ( vnode , context || { } , false , undefined ) ;
50+ return _renderToString ( vnode , context || { } , false , undefined , parent ) ;
4651 } finally {
4752 // options._commit, we don't schedule any effects in this library right now,
4853 // so we can pass an empty queue to this hook.
@@ -107,9 +112,10 @@ function renderClassComponent(vnode, context) {
107112 * @param {any } context
108113 * @param {boolean } isSvgMode
109114 * @param {any } selectValue
115+ * @param {VNode } parent
110116 * @returns {string }
111117 */
112- function _renderToString ( vnode , context , isSvgMode , selectValue ) {
118+ function _renderToString ( vnode , context , isSvgMode , selectValue , parent ) {
113119 // Ignore non-rendered VNodes/values
114120 if ( vnode == null || vnode === true || vnode === false || vnode === '' ) {
115121 return '' ;
@@ -123,75 +129,85 @@ function _renderToString(vnode, context, isSvgMode, selectValue) {
123129 // Recurse into children / Arrays
124130 if ( isArray ( vnode ) ) {
125131 let rendered = '' ;
132+ parent [ CHILDREN ] = vnode ;
126133 for ( let i = 0 ; i < vnode . length ; i ++ ) {
127134 rendered =
128- rendered + _renderToString ( vnode [ i ] , context , isSvgMode , selectValue ) ;
135+ rendered +
136+ _renderToString ( vnode [ i ] , context , isSvgMode , selectValue , parent ) ;
129137 }
130138 return rendered ;
131139 }
132140
141+ vnode [ PARENT ] = parent ;
133142 if ( beforeDiff ) beforeDiff ( vnode ) ;
134143
135144 let type = vnode . type ,
136- props = vnode . props ;
145+ props = vnode . props ,
146+ cctx = context ,
147+ contextType ,
148+ rendered ,
149+ component ;
137150
138151 // Invoke rendering on Components
139- const isComponent = typeof type === 'function' ;
152+ let isComponent = typeof type === 'function' ;
140153 if ( isComponent ) {
141154 if ( type === Fragment ) {
142- return _renderToString ( props . children , context , isSvgMode , selectValue ) ;
143- }
144-
145- let cctx = context ;
146- let cxType = type . contextType ;
147- if ( cxType != null ) {
148- let provider = context [ cxType . __c ] ;
149- cctx = provider ? provider . props . value : cxType . __ ;
150- }
151-
152- let rendered ;
153- let component ;
154- if ( type . prototype && typeof type . prototype . render === 'function' ) {
155- rendered = /**#__NOINLINE__**/ renderClassComponent ( vnode , cctx ) ;
156- component = vnode [ COMPONENT ] ;
155+ rendered = props . children ;
157156 } else {
158- component = {
159- __v : vnode ,
160- props,
161- context : cctx ,
162- // silently drop state updates
163- setState : markAsDirty ,
164- forceUpdate : markAsDirty ,
165- __d : true ,
166- // hooks
167- __h : [ ]
168- } ;
169- vnode [ COMPONENT ] = component ;
170-
171- // If a hook invokes setState() to invalidate the component during rendering,
172- // re-render it up to 25 times to allow "settling" of memoized states.
173- // Note:
174- // This will need to be updated for Preact 11 to use internal.flags rather than component._dirty:
175- // https://github.com/preactjs/preact/blob/d4ca6fdb19bc715e49fd144e69f7296b2f4daa40/src/diff/component.js#L35-L44
176- // let renderHook = options[RENDER];
177- let count = 0 ;
178- while ( component [ DIRTY ] && count ++ < 25 ) {
179- component [ DIRTY ] = false ;
180-
181- if ( renderHook ) renderHook ( vnode ) ;
182-
183- rendered = type . call ( component , props , cctx ) ;
157+ contextType = type . contextType ;
158+ if ( contextType != null ) {
159+ let provider = context [ contextType . __c ] ;
160+ cctx = provider ? provider . props . value : contextType . __ ;
184161 }
185- component [ DIRTY ] = true ;
186- }
187162
188- if ( component . getChildContext != null ) {
189- context = assign ( { } , context , component . getChildContext ( ) ) ;
163+ if ( type . prototype && typeof type . prototype . render === 'function' ) {
164+ rendered = /**#__NOINLINE__**/ renderClassComponent ( vnode , cctx ) ;
165+ component = vnode [ COMPONENT ] ;
166+ } else {
167+ component = {
168+ __v : vnode ,
169+ props,
170+ context : cctx ,
171+ // silently drop state updates
172+ setState : markAsDirty ,
173+ forceUpdate : markAsDirty ,
174+ __d : true ,
175+ // hooks
176+ __h : [ ]
177+ } ;
178+ vnode [ COMPONENT ] = component ;
179+
180+ // If a hook invokes setState() to invalidate the component during rendering,
181+ // re-render it up to 25 times to allow "settling" of memoized states.
182+ // Note:
183+ // This will need to be updated for Preact 11 to use internal.flags rather than component._dirty:
184+ // https://github.com/preactjs/preact/blob/d4ca6fdb19bc715e49fd144e69f7296b2f4daa40/src/diff/component.js#L35-L44
185+ let count = 0 ;
186+ while ( component [ DIRTY ] && count ++ < 25 ) {
187+ component [ DIRTY ] = false ;
188+
189+ if ( renderHook ) renderHook ( vnode ) ;
190+
191+ rendered = type . call ( component , props , cctx ) ;
192+ }
193+ component [ DIRTY ] = true ;
194+ }
195+
196+ if ( component . getChildContext != null ) {
197+ context = assign ( { } , context , component . getChildContext ( ) ) ;
198+ }
190199 }
191200
192201 // Recurse into children before invoking the after-diff hook
193- const str = _renderToString ( rendered , context , isSvgMode , selectValue ) ;
202+ const str = _renderToString (
203+ rendered ,
204+ context ,
205+ isSvgMode ,
206+ selectValue ,
207+ vnode
208+ ) ;
194209 if ( afterDiff ) afterDiff ( vnode ) ;
210+ vnode [ PARENT ] = undefined ;
195211 return str ;
196212 }
197213
@@ -302,10 +318,11 @@ function _renderToString(vnode, context, isSvgMode, selectValue) {
302318 // recurse into this element VNode's children
303319 let childSvgMode =
304320 type === 'svg' || ( type !== 'foreignObject' && isSvgMode ) ;
305- html = _renderToString ( children , context , childSvgMode , selectValue ) ;
321+ html = _renderToString ( children , context , childSvgMode , selectValue , vnode ) ;
306322 }
307323
308324 if ( afterDiff ) afterDiff ( vnode ) ;
325+ vnode [ PARENT ] = undefined ;
309326
310327 // Emit self-closing tag for empty void elements:
311328 if ( ! html ) {
0 commit comments