Skip to content

Commit

Permalink
Ensure @charset is at the top of generated css (#4019)
Browse files Browse the repository at this point in the history
@charset must go at the top of the file, not part way down
  • Loading branch information
BPScott committed Feb 25, 2021
1 parent 7bb90d9 commit fdfc997
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
1 change: 1 addition & 0 deletions UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f
- Fixed `CheckableButton` missing border when focused ([#3987](https://github.com/Shopify/polaris-react/issues/3987))
- Removed all `outline` and `border`instances of `-ms-high-contrast` as it is non-standard ([#3962](https://github.com/Shopify/polaris-react/pull/3962)).
- Fixed `Autocomplete` popover height not being calculated correctly ([#4015](https://github.com/Shopify/polaris-react/pull/4015)).
- Ensured `@charset` declaration is the first thing in our styles.css file ([#4019](https://github.com/Shopify/polaris-react/pull/4019))

### Documentation

Expand Down
40 changes: 39 additions & 1 deletion config/rollup/plugin-styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,17 @@ export function styles({
);
}

const css = bundleModuleIds
let css = bundleModuleIds
.filter((id) => id in cssByFile)
.map((id) => cssByFile[id])
.join('\n\n');

try {
css = hoistCharsetDeclaration(css);
} catch (err) {
rollup.error(err.message);
}

// Regular css file
rollup.emitFile({type: 'asset', fileName: output, source: css});
}
Expand Down Expand Up @@ -174,3 +180,35 @@ export function styles({
function flatMap(array, fn) {
return array.reduce((memo, item) => memo.concat(fn(item)), []);
}

// An @charset declaration must be at the top of a css file rather than part
// way through. Because we're combining multiple files we need to make sure
// that's handled correctly.
function hoistCharsetDeclaration(css) {
let result = css;

const charsetRegex = /(?<=\n|^)@charset .*;\n/;
let standaloneCssFileCharset = '';
let charsetMatch;

// This would be a lot more readable with String.matchAll in node v12
while ((charsetMatch = charsetRegex.exec(result)) !== null) {
// If multiple source files have a charset but they differ then we've
// got a problem when it comes to combining them. This shouldn't ever
// happen though as prettier/editorconfig should force all our source
// files to be UTF-8
if (
standaloneCssFileCharset !== '' &&
charsetMatch[0] === standaloneCssFileCharset
) {
throw new Error(
'Found multiple conflicting @charset declarations in css content',
);
}

standaloneCssFileCharset = charsetMatch[0];
result = result.replace(charsetMatch[0], '');
}

return `${standaloneCssFileCharset}${result}`;
}

0 comments on commit fdfc997

Please sign in to comment.