Preserve the BOM when stringifying - #2119
Conversation
PostCSS aims for byte-to-byte equal output, but the stringifier dropped a
leading byte order mark: `parse('a{}').toString()` returned `a{}`. The
BOM is already detected (`Input#hasBOM`) but was never re-emitted, so the
`bom.css` round-trip test had to be skipped.
Emit the BOM in `Stringifier#root` when the source had one, and re-enable the
previously skipped test.
|
Thanks. Nice idea. |
|
Released in 8.5.24. |
|
Interesting why BOM was stripped before? Because now this change breaks application production builds where SASS is in chain. Sass by default has We had to downgrade to v @ai What are your thoughts? |
It was a mistake (we forgot about it). BOM is a well expected symbol. It is a big issue of the parser if it can't process it. |
|
So you want to say that this is browsers (Chrome, Firefox, ...) bug that they do not parse BOM properly in inline styles? |
|
No, BOM should be only in the begging of the file. It is bug on inliner tool to not remove BOM in this case. |

PostCSS aims for byte-to-byte equal output, but the stringifier drops a leading byte order mark:
The BOM is already detected (
Input#hasBOM), but it was never re-emitted, so the round-trip isn't lossless. Thebom.cssparser-test fixture was excluded from the stringify round-trip test for this reason (if (name === 'bom.css') return).This emits the BOM in
Stringifier#rootwhen the source had one, and removes that skip so thebom.cssround-trip is now covered. A programmatic root with no source emits no BOM, and non-BOM input is unchanged.Disclosure: written with AI assistance (Claude Code); I reviewed it and verified against the full suite (unit, eslint, check-dts, size-limit all pass, incl. the newly re-enabled test).