Skip to content

Conversation

@liuxingbaoyu
Copy link
Member

Q                       A
Fixed Issues? Fixes #1, Fixes #2
Patch: Bug Fix?
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes?
License MIT

Ref: #17005

resync.call(path);

// this path no longer belongs to the tree
if (path.key === null) continue;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new change, which avoids unnecessary scope information collection.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me this change can be shipped to Babel 7, right?

Copy link
Member Author

@liuxingbaoyu liuxingbaoyu Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. In fact the whole PR can now be shipped to Babel 7, there are no known incompatibilities (even with babel-minify).
We are just postponing it to Babel 8 to be conservative.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also moved it to Babel 8 for safety.

@babel-bot
Copy link
Collaborator

babel-bot commented Jan 7, 2025

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/59979

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 12, 2025

Open in StackBlitz

commit: 9f65e82

@nicolo-ribaudo
Copy link
Member

Do you have a before/after benchmark?

@nicolo-ribaudo
Copy link
Member

Oh nevermind, it's in #16923

this._traverseFlags |= SHOULD_SKIP | SHOULD_STOP;
}

export function _forceSetScope(current: NodePath) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this end up being exposed on NodePath.prototype? Maybe lets just move it to where we use it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's private.
If we need to change setScope later, keeping them together helps us not forget to change _forceSetScope. :)

This comment was marked as outdated.

Comment on lines 140 to 142
// Skip method scope if is computed method key or decorator expression
((current.key === "key" || current.listKey === "decorators") &&
path.isMethod()) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add tests covering this change? It seems to me that tests are passing without this change.

Copy link
Member Author

@liuxingbaoyu liuxingbaoyu Sep 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great find!
They were copied from setScope and are useless on this path, so I'll remove them.
I'll try to add a test.

Comment on lines +294 to +318
it.each([
`switch (a) { default: let a = "inside" }`,
`class foo { @a m() { var a = "inside"; } }`,
`class foo { [a]() { var a = "inside" } }`,
])("scope hasGlobal with crawl: `%s`", function (code) {
let hasGlobal;
traverse(
parse(code, {
plugins: [["decorators", { version: "2025-03" }]],
}),
{
Identifier(path) {
if (
path.node.name === "a" &&
path.parent.type !== "VariableDeclarator" &&
path.parent.type !== "AssignmentPattern"
) {
hasGlobal = path.scope.hasGlobal("a");
}
},
},
);
expect(hasGlobal).toBe(true);
});

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests here are indeed weird, but they are the only behavioral changes I could find.

Copy link
Contributor

@JLHwung JLHwung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work.

@JLHwung JLHwung added the PR: Performance (next major) 🏃‍♀️ A type of pull request used for our changelog categories for next major release label Sep 13, 2025
current.scope?.init();
}

export function setScope(this: NodePath) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make setScope just call _forceSetScope(this)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, awesome find!
Thanks to #16965, cache pollution issues are gone in Babel 8, and we can safely remove them.

Comment on lines +1015 to +1017
if (process.env.BABEL_8_BREAKING && path.opts?.noScope) {
return;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new improvement, I realized that we don't need to collect scope information when noScope.

Copy link
Member

@nicolo-ribaudo nicolo-ribaudo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice :)

@nicolo-ribaudo nicolo-ribaudo merged commit 7385eae into babel:main Sep 26, 2025
76 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pkg: traverse (scope) PR: Performance (next major) 🏃‍♀️ A type of pull request used for our changelog categories for next major release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants