feat(transformer): support styled components plugin#12066
feat(transformer): support styled components plugin#12066graphite-app[bot] merged 1 commit intomainfrom
Conversation
How to use the Graphite Merge QueueAdd either label to this PR to merge it via the merge queue:
You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
CodSpeed Instrumentation Performance ReportMerging #12066 will not alter performanceComparing Summary
|
8bcb0f1 to
85dd4eb
Compare
85dd4eb to
3fee05b
Compare
3fee05b to
44bd320
Compare
|
I've pushed a commit to enable this plugin in benchmarks, so we can see what impact it has. |
There was a problem hiding this comment.
I've tried to review this properly, but it's hard because I don't understand what any of it is doing! I know we're keen to get this merged ASAP, but afterwards could you possibly add some comments, and I'll read through it again?
Please feel free to merge in the meantime. I'll do a few follow-up PRs with suggested refactoring and perf, and my comments below could also be addressed in follow-ups.
Another thought: Are we able to disable this plugin on files which aren't JSX/TSX? Or does it need to run on JS files too? The loop through all top-level statements is probably quite costly for long files, and it'd be ideal to skip it if we can.
| fn base36_encode<'a>(mut num: u64, ctx: &TraverseCtx<'a>) -> &'a str { | ||
| const BASE36_BYTES: &[u8] = b"abcdefghijklmnopqrstuvwxyz0123456789"; | ||
|
|
||
| num %= 36_u64.pow(6); // 36^6, to ensure the result is <= 6 characters long. | ||
|
|
||
| let mut result = Vec::with_capacity(6); | ||
|
|
||
| while num != 0 { | ||
| result.push(BASE36_BYTES[(num % 36) as usize]); | ||
| num /= 36; | ||
| } | ||
|
|
||
| ctx.ast.allocator.alloc_str( | ||
| // SAFETY: the bytes are valid UTF-8 as they are ASCII characters. | ||
| unsafe { std::str::from_utf8_unchecked(&result) }, | ||
| ) | ||
| } |
There was a problem hiding this comment.
Is there a reason for using base 36 here? Couldn't we use base 64 (A-Z, a-z, 0-9, _, $)?
Division by numbers which aren't a power of 2 is quite expensive, and it'd give a larger range of possibilities in 6 chars (less chance of collisions).
Also, building the string with InlineString would be be more performant than Vec. Like in mangler:
There was a problem hiding this comment.
I guess we can use base64. Using base36 is to align with its Babel plugin.
Ok, I will follow this kind of optimization.
There was a problem hiding this comment.
It's not a big thing! Was just asking if there was a reason because base36 is unusual. Odd choice from styled-components authors!
There was a problem hiding this comment.
@Dunqing I realized now that maybe there is a reason. Maybe class names are case insensitive in some browsers?
It needs to run in all files. One possible case that we need to consider is that they would like to define all of the styled components in a utility file (.js or .ts), and use them in the JSX/TSX files. Another serious performance hit if we need to support CJS, we need to go through the whole AST to find whether there is a |
Merge activity
|
close: #11876 This plugin adds comprehensive support for styled-components with server-side rendering, style minification, and enhanced debugging capabilities. The implementation is ported from the [official Babel plugin](https://github.com/styled-components/babel-plugin-styled-components) to ensure compatibility and feature parity. ## Current Limitations⚠️ **Import Support**: This plugin currently only supports styled-components imported via ES modules (`import` statements). CommonJS imports using `require("styled-components")` are not yet supported. ## Feature Support ### Options: **✅ Fully Supported:** - `displayName`: Adds display names for debugging - `fileName`: Controls filename prefixing in display names - `ssr`: Adds unique component IDs for server-side rendering - `transpileTemplateLiterals`: Converts template literals to function calls - `minify`: Minifies CSS content in template literals - `namespace`: Adds namespace prefixes to component IDs - `meaninglessFileNames`: Controls which filenames are considered meaningless **⚠️ Partially Supported:** - `pure`: Only supports call expressions, not tagged template expressions (bundler limitation) **❌ Not Yet Implemented:** - `cssProp`: JSX css prop transformation - `topLevelImportPaths`: Custom import path handling ## Testing The test suite is adapted from the [official Babel plugin tests](https://github.com/styled-components/babel-plugin-styled-components) with modifications to integrate with our testing infrastructure. **Note**: Some test outputs differ from the original due to our different hashing algorithm for component IDs. This is intentional and follows the same approach used by SWC's implementation.
94ec753 to
19b97c0
Compare
Follow-on after #12066. Tiny refactor. Move clippy exception to cover just the place it's needed, rather than the whole file.
Follow-on after #12066. `helpers` was an `FxHashMap<String, SymbolId>`, but we know all the possible keys, and there's only 6 of them. So use a small array `[Option<SymbolId>; 6]` instead, and convert from strings to indexes into that array via a `StyledComponentsHelper` enum. Array (24 bytes) is smaller than an `FxHashMap`, and involves no allocations, as well as avoiding hashing strings. Note: Using an enum rather than an untyped `usize` index, as with an enum, compiler can statically prove indexing into the array can never be out of bounds, so it skips bounds checks.
|
Consider this stack of PR to be huge, so I am merging this stack and following your suggestion and finishing some missing work in the follow-up PRs later. |
Follow-on after #12066. Pure refactor. Just make the code less deeply nested.
Follow-on after #12066. Pure refactor. Simplify and shorten code.
Argh! Maybe we need to include I suppose we could more easily support |
…sions is part of `ComputedMemberExpression` (#12181) close: #12066 (comment) We haven't supported transform `ComputedMemberExpression`, because I found that Babel plugin support for `styled['div']` is also incomplete. Anyway, short-circuiting for this is still a good improvement.



close: #11876
This plugin adds comprehensive support for styled-components with server-side rendering, style minification, and enhanced debugging capabilities. The implementation is ported from the official Babel plugin to ensure compatibility and feature parity.
Current Limitations
importstatements). CommonJS imports usingrequire("styled-components")are not yet supported.Feature Support
Options:
✅ Fully Supported:
displayName: Adds display names for debuggingfileName: Controls filename prefixing in display namesssr: Adds unique component IDs for server-side renderingtranspileTemplateLiterals: Converts template literals to function callsminify: Minifies CSS content in template literalsnamespace: Adds namespace prefixes to component IDsmeaninglessFileNames: Controls which filenames are considered meaninglesspure: Only supports call expressions, not tagged template expressions (bundler limitation)❌ Not Yet Implemented:
cssProp: JSX css prop transformationtopLevelImportPaths: Custom import path handlingTesting
The test suite is adapted from the official Babel plugin tests with modifications to integrate with our testing infrastructure.
Note: Some test outputs differ from the original due to our different hashing algorithm for component IDs. This is intentional and follows the same approach used by SWC's implementation.