-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite JS transformer and scope hoisting in Rust #6230
Conversation
Improves performance
Currently not, but It's easy to implement. I didn't know that the code generator of babel is slow.
I'll just use the system of babel. As it involves running js code, implementing the plugin system in rust would not boost performance. Actually even making |
Makes sense. In regards to your earlier question:
I think it's fairly common to need custom plugins that operate on the source level rather than after compatibility transforms have been applied. For example, plugins might wish to do something with JSX elements (I know several CSS-in-JS plugins like emotion do this). So I think running plugins before SWC runs might actually be better. That's how we've currently set up Parcel's default JS pipeline - Babel runs first if there is a babel config, and after that we run SWC.
The first approach sounds easier, but is more limited. You wouldn't be able to replace the code generator easily, and I guess it might force SWC's transforms to run before other plugins. I think you'd want to parse using SWC, convert the AST to babel, run custom Babel plugins, convert AST back to SWC, run SWC transforms, codegen. |
Btw you might not need to implement the plugin runner from scratch if you invoke Babel programmatically by passing it an AST. You can also set an option to have it return an AST rather than codegen as well. This is how Parcel used to work as well. |
Thanks! I was also worried about the order of transforms. I'll implement babel ast to swc ast transformer. Do you want me to publish this crate on crates.io? |
Yeah we'd be happy to try it out when it's ready! |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
8bafd95
to
b4838c6
Compare
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Apart from the worker count detection question)
And the failing macOS CI 😄
Is there a way to configure swc? AFAICT, .swcrc seems to be ignored. |
What are you looking to configure? At the moment, .swcrc is not used (the fact that Parcel uses SWC is a bit of an internal implementation detail). You can configure preset-env through targets or browserslist. And JSX and TypeScript should be handled automatically. |
I'm using decorators (for mobx), my .swcrc would be {
"jsc": {
"parser": {
"syntax": "ecmascript",
"decorators": true
},
"transform": {
"legacyDecorator": true,
"decoratorsBeforeExport": true
}
}
} |
This is a rewrite of the current JS transformer, including scope hoisting, in Rust. It utilizes SWC for parsing and codegen. All of the features of the existing JS transformer have been ported, including dependency detection, process.env replacement, fs inlining, node global insertion, and scope hoisting. In addition, SWC replaces Babel by default for transpilation when a
browserslist
is set, as well as for compiling JSX and TypeScript, and React Fast Refresh.Overall, build times are up to 10x faster!
On the esbuild benchmark, without terser:
With terser:
Still plenty of optimization potential to go, but this is a great foundation to build on!
It's also really exciting that something like this is even possible. Parcel's language-agnostic core made this entirely possible in plugins. In fact, the old Babel-based plugins and scope hoisting implementation still work entirely without modification. In the future, we will be able to swap out additional plugins to improve performance or output quality as well.
Scope hoisting rewrite
Aside from performance, this PR was motivated by a need to rethink how Parcel's scope hoisting/tree shaking implementation works. We ran into some bugs especially having to do with preserving execution ordering (e.g. #5659) and duplicate execution that necessitated us to rethink how we handle wrapped assets via a module registry. The result is a hybrid between scope hoisting where we can, but falling back wrapping modules in a CJS-style function where needed. The packager is also redesigned to work entirely on strings rather than ASTs, which improves performance massively. You can read more about how this works in the design document for the new scope hoisting implementation.
export default
with a named function/class is still a live binding #5658$parcel$interopDefault
execute wrapped assets on load #5662parcel ..
andparcel build
#6056Possibly fixes (needs verification) #5064 #5914
Non scope hoisting issues: Fixes #5560
Migration
This only swaps out the current JS transformer and JS packager plugins in the default config. If your project has a
browserslist
and no.babelrc
, your code will be transpiled with SWC instead of Babel. If you do have a.babelrc
, nothing changes - Babel will still be used automatically. This means that both custom Babel plugins (e.g. CSS-in-JS transforms, Babel macros, etc.) continue to work out of the box. Scope hoisting, dependency collection, and everything else that was built into Parcel before will now occur in Rust, but this should be completely transparent.This does open up the possibility to improve the performance of your build even further, however. You can now remove
@babel/preset-env
,@babel/preset-react
, and@babel/preset-typescript
from your.babelrc
, and they will be automatically handled by SWC instead. This can significantly improve your build performance. If you have additional custom Babel plugins, you can leave them in your Babel config. If not, you can delete your Babel config entirely. We will likely add a warning in the future to assist with this migration.Closes T-388, Closes T-194, Closes T-470, Closes T-849, Closes T-868