-
Notifications
You must be signed in to change notification settings - Fork 194
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
JavaScript visitor API for custom transforms #363
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This was referenced Dec 17, 2022
…-visitor # Conflicts: # src/properties/mod.rs # src/properties/transition.rs
…into js-visitor # Conflicts: # src/rules/supports.rs
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This adds a visitor API to the node bindings which enables custom transforms to be written, similar to custom PostCSS plugins. I've re-created several popular PostCSS plugins in the tests to verify that it is possible to do so.
The API tries to let you be as specific as possible about what types of values you care about by defining functions for specific value types, property and rule names, etc. This lets us call from Rust into JS as little as possible, which helps with performance. An example plugin to convert pixels to rems is about 6x faster than an equivalent PostCSS plugin. JS visitors do have a cost however - it's about 2x slower than with no visitors. So this API is there when you want to do something custom, but transforms for standard CSS features should be implemented in Rust as part of core.
At the moment, a visitor runs in a single pass over the AST. We could later add support for multi-pass transforms if needed, but would be nice to avoid if possible. To support multiple visitor "plugins", there is a
composeVisitors
function included which combines multiple visitors into one on the JS side, which can then be passed to the Rust implementation. We try to make the order of the visitors not matter as much as possible. Each visitor has the opportunity to visit each value once. If a visitor returns a new value for a node, that value is visited by the other visitors but not again by the original visitor that created it. We keep track of which visitors have been visited and mutated the value to avoid infinite loops.Implementation wise, it relies on Serde to serialize and deserialize parts of the AST into JS objects as needed. We also use the schemars crate to generate a JSON schema definition from the Rust types, which is then converted into TypeScript. A bulk of the changes in the PR are related to this, and making the AST types nicer to work with in JS.
One downside is that the binary size of lightningcss gets significantly larger with this feature - mostly due to serde derived implementations. I think the feature is worth it to include by default - but if we need to, we could always have an additional "lite" build available for users with strict size requirements that don't need this feature.
API feedback welcome! Check out the tests for some examples.