Skip to content

Commit

Permalink
fix(compiler): do not remove comments in component styles
Browse files Browse the repository at this point in the history
Prior to this commit, comments in CSS were being removed. This caused inline sourcemaps to break to the shift in lines.

This caused sourcemaps to break in the ESBuild based builder as this always adds comments at the top of the file with the filename.

Example
```css
 /* src/app/app.component.scss */
* {
  color: red;
  background: transparent;
}
/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8uL3NyYy9hcHAvYXBwLmNvbXBvbmVudC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBOzs7Ozs7Ozs7Q0FBQTtBQVdBO0VBQ0UsVUFBQTtFQUNBLHVCQUFBO0FBREYiLCJzb3VyY2VzQ29udGVudCI6WyIvL01FRElBIFFVRVJZIE1BTkFHRVJcbi8qXG4gIDAgLSA2MDA6IFBob25lXG4gIDYwMCAtIDkwMDogVGFibGV0IHBvcnRyYWl0XG4gIDkwMCAtIDEyMDA6IFRhYmxldCBsYW5kc2NhcGVcbiAgMTIwMCAtIDE4MDA6IE5vcm1hbCBzdHlsZXNcbiAgMTgwMCsgOiBCaWcgRGVza3RvcFxuICAxZW0gPSAxNnB4XG4gIFRoZSBzbWFsbGVyIGRldmljZSBydWxlcyBhbHdheXMgc2hvdWxkIHdyaXRlIGJlbG93IHRoZSBiaWdnZXIgZGV2aWNlIHJ1bGVzXG4gIEZpeGluZyBPcmRlciA9PiBCYXNlICsgVHlwb2dyYXBoeSA+PiBHZW5lcmFsIExheW91dCArIEdyaWQgPj4gUGFnZSBMYXlvdXQgKyBDb21wb25lbnRcbiovXG5cbioge1xuICBjb2xvcjogcmVkO1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbn1cbiJdLCJzb3VyY2VSb290IjoiIn0= */
```

Closes #50308
  • Loading branch information
alan-agius4 committed May 17, 2023
1 parent 237d90f commit 1f93af9
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 40 deletions.
25 changes: 9 additions & 16 deletions packages/compiler/src/shadow_css.ts
Expand Up @@ -138,12 +138,12 @@ export class ShadowCss {
* The hostSelector is the attribute added to the host itself.
*/
shimCssText(cssText: string, selector: string, hostSelector: string = ''): string {
const commentsWithHash = extractCommentsWithHash(cssText);
cssText = stripComments(cssText);
// **NOTE**: Do not strip comments as this will cause component sourcemaps to break
// due to shift in lines.
cssText = this._insertDirectives(cssText);

const scopedCssText = this._scopeCssText(cssText, selector, hostSelector);
return [scopedCssText, ...commentsWithHash].join('\n');

return scopedCssText;
}

private _insertDirectives(cssText: string): string {
Expand Down Expand Up @@ -802,22 +802,11 @@ const _polyfillHostRe = /-shadowcsshost/gim;
const _colonHostRe = /:host/gim;
const _colonHostContextRe = /:host-context/gim;

const _commentRe = /\/\*[\s\S]*?\*\//g;

const _placeholderRe = /__ph-(\d+)__/g;

function stripComments(input: string): string {
return input.replace(_commentRe, '');
}

const _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g;

function extractCommentsWithHash(input: string): string[] {
return input.match(_commentWithHashRe) || [];
}

const BLOCK_PLACEHOLDER = '%BLOCK%';
const _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g;
const _ruleRe = /(\s*(?:\/\*[\s\S]*?\*\/\s*)?)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g;
const CONTENT_PAIRS = new Map([['{', '}']]);

const COMMA_IN_PLACEHOLDER = '%COMMA_IN_PLACEHOLDER%';
Expand All @@ -836,6 +825,7 @@ export function processRules(input: string, ruleCallback: (rule: CssRule) => Css
const escaped = escapeInStrings(input);
const inputWithEscapedBlocks = escapeBlocks(escaped, CONTENT_PAIRS, BLOCK_PLACEHOLDER);
let nextBlockIndex = 0;
console.log(inputWithEscapedBlocks.escapedString);
const escapedResult = inputWithEscapedBlocks.escapedString.replace(_ruleRe, (...m: string[]) => {
const selector = m[2];
let content = '';
Expand Down Expand Up @@ -869,6 +859,9 @@ function escapeBlocks(
const char = input[i];
if (char === '\\') {
i++;
} else if (char === '/' && input.charAt(i + 1) === '*') {
// Skip content in comments.
i = input.indexOf('*/', i + 1) + 2;
} else if (char === closeChar) {
openCharCount--;
if (openCharCount === 0) {
Expand Down
53 changes: 29 additions & 24 deletions packages/compiler/test/shadow_css/shadow_css_spec.ts
Expand Up @@ -96,30 +96,6 @@ describe('ShadowCss', () => {
expect(css).toEqualCss('div[contenta] {height:calc(100% - 55px);}');
});

it('should strip comments', () => {
expect(shim('/* x */b {c}', 'contenta')).toEqualCss('b[contenta] {c}');
});

it('should ignore special characters in comments', () => {
expect(shim('/* {;, */b {c}', 'contenta')).toEqualCss('b[contenta] {c}');
});

it('should support multiline comments', () => {
expect(shim('/* \n */b {c}', 'contenta')).toEqualCss('b[contenta] {c}');
});

it('should keep sourceMappingURL comments', () => {
expect(shim('b {c}/*# sourceMappingURL=data:x */', 'contenta'))
.toEqualCss('b[contenta] {c} /*# sourceMappingURL=data:x */');
expect(shim('b {c}/* #sourceMappingURL=data:x */', 'contenta'))
.toEqualCss('b[contenta] {c} /* #sourceMappingURL=data:x */');
});

it('should keep sourceURL comments', () => {
expect(shim('/*# sourceMappingURL=data:x */b {c}/*# sourceURL=xxx */', 'contenta'))
.toEqualCss('b[contenta] {c} /*# sourceMappingURL=data:x */ /*# sourceURL=xxx */');
});

it('should shim rules with quoted content', () => {
const styleStr = 'div {background-image: url("a.jpg"); color: red;}';
const css = shim(styleStr, 'contenta');
Expand All @@ -137,4 +113,33 @@ describe('ShadowCss', () => {
const css = shim(styleStr, 'contenta');
expect(css).toEqualCss('div[contenta]::after { content:"{}"}');
});

describe('comments', () => {
// Comments should be kept in the same position as otherwise inline sourcemaps break due to
// shift in lines.
it('should not strip comments', () => {
expect(shim('/* b {c} */ b {c}', 'contenta')).toEqualCss('/* b {c} */ b[contenta] {c}');
});

it('should not strip multiline comments', () => {
expect(shim('/* b {c}\n */ b {c}', 'contenta')).toEqualCss('/* b {c}\n */ b[contenta] {c}');
});

it('should keep comments in the original position', () => {
expect(shim('/* b {c} */ b {c} /* a {c} */ a {c}', 'contenta'))
.toEqualCss('/* b {c} */ b[contenta] {c} /* a {c} */ a[contenta] {c}');
});

it('should keep sourceMappingURL comments', () => {
expect(shim('b {c} /*# sourceMappingURL=data:x */', 'contenta'))
.toEqualCss('b[contenta] {c} /*# sourceMappingURL=data:x */');
expect(shim('b {c}/* #sourceMappingURL=data:x */', 'contenta'))
.toEqualCss('b[contenta] {c}/* #sourceMappingURL=data:x */');
});

it('should keep sourceURL comments', () => {
expect(shim('/*# sourceMappingURL=data:x */b {c}/*# sourceURL=xxx */', 'contenta'))
.toEqualCss('/*# sourceMappingURL=data:x */b[contenta] {c}/*# sourceURL=xxx */');
});
});
});

0 comments on commit 1f93af9

Please sign in to comment.