@@ -1068,7 +1068,7 @@ fn minify_template_literal<'a>(lit: &mut TemplateLiteral<'a>, ast: AstBuilder<'a
10681068 }
10691069 // Skip and compress whitespace.
10701070 _ if cur_byte. is_ascii_whitespace ( ) => {
1071- // Consume any following whitespace
1071+ // Consume this whitespace and any further whitespace characters
10721072 let mut next_byte;
10731073 loop {
10741074 i += 1 ;
@@ -1083,33 +1083,41 @@ fn minify_template_literal<'a>(lit: &mut TemplateLiteral<'a>, ast: AstBuilder<'a
10831083 // - `color: red` -> `color:red` (spaces around colons)
10841084 // - `.a { }` -> `.a{}` (spaces around braces)
10851085 // - `margin: 1px , 2px` -> `margin:1px,2px` (spaces around commas)
1086- // But spaces are significant in other contexts like selectors: `.a .b` != `.a.b`
1087- if output. last ( ) . map_or (
1088- // Case 1: If output is empty (no last char), preserve space only if we're
1089- // in a non-first quasi to avoid joining with the previous interpolation.
1090- // Example: `${A} ${B}` - the space between interpolations must be preserved
1091- quasi_index != 0 ,
1092- // Case 2: If we have a last char, preserve space unless it's a CSS delimiter
1093- // that can safely have adjacent spaces removed (space, colon, braces, comma, semicolon)
1094- |& last| !matches ! ( last, b' ' | b':' | b'{' | b'}' | b',' | b';' ) ,
1095- )
1096- // AND check what comes after this whitespace:
1097- // - If we're at the end of the quasi (i == bytes.len()), preserve the space
1098- // to avoid joining with the next interpolation
1099- // - Otherwise, only preserve if the next char is NOT one of: { } , ;
1086+ // But spaces are significant in other contexts like selectors: `.a .b` != `.a.b`.
1087+
1088+ // Check what comes before this whitespace
1089+ if let Some ( & last) = output. last ( ) {
1090+ if matches ! ( last, b' ' | b':' | b'{' | b'}' | b',' | b';' ) {
1091+ // Always safe to remove whitespace after these characters
1092+ continue ;
1093+ }
1094+ } else if quasi_index == 0 {
1095+ // We're at the start of the first quasi, so can trim leading whitespace
1096+ continue ;
1097+ } else {
1098+ // We're at start of a later quasi.
1099+ // Preserve space to avoid joining with previous interpolation.
1100+ }
1101+
1102+ // Check what comes after this whitespace.
1103+ // - If we're at the end of the quasi (`next_byte == None`), preserve the space
1104+ // to avoid joining with the next interpolation.
1105+ // - Remove whitespace before `{`, `}`, `,`, and `;`.
11001106 // Note: We intentionally DON'T include ':' here because spaces before colons
11011107 // are significant in CSS. ` :hover` (descendant pseudo-selector) is different
11021108 // from `:hover` (direct pseudo-selector). Example: `.parent :hover` selects any
11031109 // hovered descendant, while `.parent:hover` selects the parent when hovered.
1104- && next_byte. is_none_or ( |& next| !matches ! ( next, b'{' | b'}' | b',' | b';' ) )
1105- {
1106- // Preserve this space character.
1107- // Examples:
1108- // - `padding: 0 ${VALUE}px` - space before interpolation preserved
1109- // - `${A} ${B}` - space between interpolations preserved
1110- // - `.class :hover` - space before pseudo-selector preserved
1111- output. push ( b' ' ) ;
1110+ if matches ! ( next_byte, Some ( & b'{' | & b'}' | & b',' | & b';' ) ) {
1111+ // Always safe to remove whitespace before these characters
1112+ continue ;
11121113 }
1114+
1115+ // Preserve this space character.
1116+ // Examples:
1117+ // - `padding: 0 ${VALUE}px` - space before interpolation preserved
1118+ // - `${A} ${B}` - space between interpolations preserved
1119+ // - `.class :hover` - space before pseudo-selector preserved
1120+ output. push ( b' ' ) ;
11131121 continue ;
11141122 }
11151123 _ => { }
0 commit comments