From 2f66dd2306d94c6c8f3ea62a89a890f2a7966b5e Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Mon, 28 Jul 2025 13:34:01 +0000 Subject: [PATCH] fix(transformer/styled-components): preserve whitespace before interpolations in minification (#12558) close: #12556 Fixed an issue where spaces before template literal interpolations were incorrectly removed during CSS minification in the styled-components plugin. The fix ensures spaces are preserved (e.g., `padding: 0 ${PADDING}px` stays as `padding:0 ${PADDING}px` instead of becoming `padding:0${PADDING}px`). --- .../src/plugins/styled_components.rs | 10 +++++++++- .../snapshots/oxc.snap.md | 4 ++-- .../input.js | 19 +++++++++++++++++++ .../options.json | 18 ++++++++++++++++++ .../output.js | 5 +++++ 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/input.js create mode 100644 tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/options.json create mode 100644 tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/output.js diff --git a/crates/oxc_transformer/src/plugins/styled_components.rs b/crates/oxc_transformer/src/plugins/styled_components.rs index e1d5c52d90218..ef5bf3ce24d43 100644 --- a/crates/oxc_transformer/src/plugins/styled_components.rs +++ b/crates/oxc_transformer/src/plugins/styled_components.rs @@ -1067,8 +1067,16 @@ fn minify_template_literal<'a>(lit: &mut TemplateLiteral<'a>, ast: AstBuilder<'a // but preserve whitespace preceding colon, to avoid joining selectors. if output.last().is_some_and(|&last| { !matches!(last, b' ' | b':' | b'{' | b'}' | b',' | b';') - }) && (i < bytes.len() && !matches!(bytes[i], b'{' | b'}' | b',' | b';')) + }) && (i == bytes.len() || !matches!(bytes[i], b'{' | b'}' | b',' | b';')) { + // `i == bytes.len()` means we're at the end of the quasi that has an + // interpolation after it. Preserve trailing whitespace to avoid joining + // with the interpolation. + // + // For example: + // `padding: 0 ${PADDING}px` + // ^ this space should be preserved to avoid it becomes + // `padding:0${PADDING}px` output.push(b' '); } continue; diff --git a/tasks/transform_conformance/snapshots/oxc.snap.md b/tasks/transform_conformance/snapshots/oxc.snap.md index 486626e944121..6f7d63de7aa20 100644 --- a/tasks/transform_conformance/snapshots/oxc.snap.md +++ b/tasks/transform_conformance/snapshots/oxc.snap.md @@ -1,6 +1,6 @@ commit: 1d4546bc -Passed: 180/300 +Passed: 181/301 # All Passed: * babel-plugin-transform-class-static-block @@ -1470,7 +1470,7 @@ after transform: ["Function", "babelHelpers"] rebuilt : ["babelHelpers", "dec"] -# plugin-styled-components (20/34) +# plugin-styled-components (21/35) * styled-components/add-identifier-with-top-level-import-paths/input.js x Output mismatch diff --git a/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/input.js b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/input.js new file mode 100644 index 0000000000000..b6ac7726b04eb --- /dev/null +++ b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/input.js @@ -0,0 +1,19 @@ +import styled from 'styled-components'; + +const PADDING = 2; + +// Test case for whitespace before interpolation +const Button = styled.div` + padding: 0 ${PADDING}px 0 2px; +`; + +// Multiple interpolations with spaces before +const Box = styled.div` + margin: ${props => props.margin}px ${props => props.margin}px; + padding: 0 ${PADDING}px; +`; + +// Space before interpolation in middle of value +const Container = styled.div` + width: calc(100% - ${PADDING}px); +`; diff --git a/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/options.json b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/options.json new file mode 100644 index 0000000000000..6af071704e5d1 --- /dev/null +++ b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/options.json @@ -0,0 +1,18 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "modules": false, + "targets": "defaults" + } + ] + ], + "plugins": [ + ["styled-components", { + "ssr": false, + "displayName": false, + "transpileTemplateLiterals": false + }] + ] +} \ No newline at end of file diff --git a/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/output.js b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/output.js new file mode 100644 index 0000000000000..bd0a3a32bc02c --- /dev/null +++ b/tasks/transform_conformance/tests/plugin-styled-components/test/fixtures/minify-whitespace-before-interpolation/output.js @@ -0,0 +1,5 @@ +import styled from 'styled-components'; +const PADDING = 2; +const Button = styled.div`padding:0 ${PADDING}px 0 2px;`; +const Box = styled.div`margin:${props => props.margin}px ${props => props.margin}px;padding:0 ${PADDING}px;`; +const Container = styled.div`width:calc(100% - ${PADDING}px);`; \ No newline at end of file