@@ -69,32 +69,6 @@ function cloneTree(tree: NodeTree): NodeTree {
6969 }
7070}
7171
72- // Limited-concurrency worker pool for children processing.
73- // Preserves output order while allowing N async operations in flight.
74- const BUILD_CONCURRENCY = 2
75-
76- async function mapConcurrent < T , R > (
77- items : readonly T [ ] ,
78- fn : ( item : T , index : number ) => Promise < R > ,
79- concurrency : number ,
80- ) : Promise < R [ ] > {
81- if ( items . length === 0 ) return [ ]
82- const results : R [ ] = new Array ( items . length )
83- let nextIndex = 0
84-
85- async function worker ( ) {
86- while ( nextIndex < items . length ) {
87- const i = nextIndex ++
88- results [ i ] = await fn ( items [ i ] , i )
89- }
90- }
91-
92- await Promise . all (
93- Array . from ( { length : Math . min ( concurrency , items . length ) } , ( ) => worker ( ) ) ,
94- )
95- return results
96- }
97-
9872export class Codegen {
9973 components : Map <
10074 string ,
@@ -326,18 +300,15 @@ export class Codegen {
326300 )
327301 }
328302
329- // Build children with limited concurrency (2 workers).
330- // getProps(node) is already in-flight concurrently above.
331- // With variable/text-style/getProps caches in place, Figma API contention is low enough
332- // for 2 concurrent subtree builds. This roughly halves wall-clock for wide trees.
333- const children : NodeTree [ ] =
334- 'children' in node
335- ? await mapConcurrent (
336- node . children ,
337- ( child ) => this . buildTree ( child ) ,
338- BUILD_CONCURRENCY ,
339- )
340- : [ ]
303+ // Build children sequentially — Figma's single-threaded IPC means
304+ // concurrent subtree builds add overhead without improving throughput,
305+ // and sequential order maximizes cache hits for shared nodes.
306+ const children : NodeTree [ ] = [ ]
307+ if ( 'children' in node ) {
308+ for ( const child of node . children ) {
309+ children . push ( await this . buildTree ( child ) )
310+ }
311+ }
341312
342313 // Now await props (likely already resolved while children were processing)
343314 const props = await propsPromise
@@ -417,16 +388,13 @@ export class Codegen {
417388 const t = perfStart ( )
418389 const selectorPropsPromise = getSelectorProps ( node )
419390
420- // Build children with limited concurrency (same as doBuildTree).
421- // INSTANCE children are handled inside doBuildTree when buildTree(child) recurses.
422- const childrenTrees : NodeTree [ ] =
423- 'children' in node
424- ? await mapConcurrent (
425- node . children ,
426- ( child ) => this . buildTree ( child ) ,
427- BUILD_CONCURRENCY ,
428- )
429- : [ ]
391+ // Build children sequentially (same reasoning as doBuildTree).
392+ const childrenTrees : NodeTree [ ] = [ ]
393+ if ( 'children' in node ) {
394+ for ( const child of node . children ) {
395+ childrenTrees . push ( await this . buildTree ( child ) )
396+ }
397+ }
430398
431399 // Await props + selectorProps (likely already resolved while children built)
432400 const [ props , selectorProps ] = await Promise . all ( [
0 commit comments