Skip to content

Commit 566eea4

Browse files
Improve walk performance (tailwindlabs#19614)
This PR improves the walk performance by a little bit, but also reduces memory usage. It's a tiny change and all the APIs remain the same. Not the most important PR, but we had this idea on the backburner so we decided to just implement it. Thanks @thecrypticace! ## Test plan - All the existing tests should pass. Co-authored-by: Jordan Pittman <jordan@cryptica.me>
1 parent e3e85b3 commit 566eea4

1 file changed

Lines changed: 24 additions & 9 deletions

File tree

packages/tailwindcss/src/walk.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,42 +52,53 @@ export function walk<T extends object>(
5252
else walkImplementation(ast, hooks.enter, hooks.exit)
5353
}
5454

55+
interface Stack<T> {
56+
value: T
57+
prev: Stack<T> | null
58+
}
59+
5560
function walkImplementation<T extends { nodes?: T[] }>(
5661
ast: T[],
5762
enter: (node: T, ctx: VisitContext<T>) => EnterResult<T> | void = () => WalkAction.Continue,
5863
exit: (node: T, ctx: VisitContext<T>) => ExitResult<T> | void = () => WalkAction.Continue,
5964
) {
60-
let stack: [nodes: T[], offset: number, parent: Parent<T> | null][] = [[ast, 0, null]]
65+
type StackFrame = [nodes: T[], offset: number, parent: Parent<T> | null]
66+
let stack: Stack<StackFrame> | null = { value: [ast, 0, null], prev: null }
67+
6168
let ctx: VisitContext<T> = {
6269
parent: null,
6370
depth: 0,
6471
path() {
6572
let path: T[] = []
6673

67-
for (let i = 1; i < stack.length; i++) {
68-
let parent = stack[i][2]
74+
let frames: Stack<StackFrame> | null = stack
75+
76+
while (frames) {
77+
let parent = frames.value[2]
6978
if (parent) path.push(parent)
79+
frames = frames.prev
7080
}
7181

82+
path.reverse()
83+
7284
return path
7385
},
7486
}
7587

76-
while (stack.length > 0) {
77-
let depth = stack.length - 1
78-
let frame = stack[depth]
88+
while (stack !== null) {
89+
let frame = stack.value
7990
let nodes = frame[0]
8091
let offset = frame[1]
8192
let parent = frame[2]
8293

8394
// Done with this level
8495
if (offset >= nodes.length) {
85-
stack.pop()
96+
stack = stack.prev
97+
ctx.depth -= 1
8698
continue
8799
}
88100

89101
ctx.parent = parent
90-
ctx.depth = depth
91102

92103
// Enter phase (offsets are positive)
93104
if (offset >= 0) {
@@ -97,7 +108,11 @@ function walkImplementation<T extends { nodes?: T[] }>(
97108
switch (result.kind) {
98109
case WalkKind.Continue: {
99110
if (node.nodes && node.nodes.length > 0) {
100-
stack.push([node.nodes, 0, node as Parent<T>])
111+
ctx.depth += 1
112+
stack = {
113+
value: [node.nodes, 0, node as Parent<T>],
114+
prev: stack,
115+
}
101116
}
102117

103118
frame[1] = ~offset // Prepare for exit phase, same offset

0 commit comments

Comments
 (0)