fix(compiler): prevent shimCssText from adding extra blank lines per CSS comment

The comment placeholder restoration in `shimCssText` appended an unconditional
`+ '\n'` to each non-hash comment replacement. Because `_commentRe` does not
consume the newline that follows a comment in the source, that newline already
remains in `cssText`. The extra `'\n'` was therefore inserted on top of the
existing one, shifting every line after each comment down by one. In files with
many comments (e.g. large SCSS preambles) this shifts all subsequent CSS rules
far enough that the CSS sourcemap — generated before `shimCssText` runs —
points to completely wrong source locations in browser DevTools.

The fix is to drop the `+ '\n'`; internal newlines within a multi-line comment
are still preserved via `_newLinesRe`, and the trailing newline that follows the
comment in `cssText` is already present without any extra injection.

(cherry picked from commit 5a712d42d1)
This commit is contained in:
Matt Lewis
2026-03-18 19:22:15 +00:00
committed by Leon Senft
parent 1ba89d1128
commit 880a57d4b3
2 changed files with 8 additions and 10 deletions
+1 -1
View File
@@ -186,7 +186,7 @@ export class ShadowCss {
// Replace non hash comments with empty lines.
// This is done so that we do not leak any sensitive data in comments.
const newLinesMatches = m.match(_newLinesRe);
comments.push((newLinesMatches?.join('') ?? '') + '\n');
comments.push(newLinesMatches?.join('') ?? '');
}
return COMMENT_PLACEHOLDER;
@@ -368,17 +368,17 @@ describe('ShadowCss', () => {
describe('comments', () => {
// Comments should be kept in the same position as otherwise inline sourcemaps break due to
// shift in lines.
it('should replace multiline comments with newline', () => {
expect(shim('/* b {c} */ b {c}', 'contenta')).toBe('\n b[contenta] {c}');
it('should remove inline comments without adding extra lines', () => {
expect(shim('/* b {c} */ b {c}', 'contenta')).toBe(' b[contenta] {c}');
});
it('should replace multiline comments with newline in the original position', () => {
expect(shim('/* b {c}\n */ b {c}', 'contenta')).toBe('\n\n b[contenta] {c}');
it('should preserve internal newlines from multiline comments', () => {
expect(shim('/* b {c}\n */ b {c}', 'contenta')).toBe('\n b[contenta] {c}');
});
it('should replace comments with newline in the original position', () => {
it('should remove multiple inline comments without adding extra lines', () => {
expect(shim('/* b {c} */ b {c} /* a {c} */ a {c}', 'contenta')).toBe(
'\n b[contenta] {c} \n a[contenta] {c}',
' b[contenta] {c} a[contenta] {c}',
);
});
@@ -392,9 +392,7 @@ describe('ShadowCss', () => {
});
it('should handle adjacent comments', () => {
expect(shim('/* comment 1 */ /* comment 2 */ b {c}', 'contenta')).toBe(
'\n \n b[contenta] {c}',
);
expect(shim('/* comment 1 */ /* comment 2 */ b {c}', 'contenta')).toBe(' b[contenta] {c}');
});
});
});