EPBDS-16211 §9.8: unpin LESS — 3.13 → 4.x, output byte-identical - #48
Merged
Merged
Conversation
The pin is gone and the published `static/all.css` still has the sha256 it has
had all through the exit (dcdb0a40…). Verified before touching the manifest, by
compiling the same source through both majors and comparing.
NEITHER ANCHOR WAS WHAT §9.8 SAID IT WAS, and the step-4 measurement had already
shown that: `javascriptEnabled` is required by our OWN `_variables.less:23` — a
`Math.random()` font cache-buster that reaches `static/font.css` and never
`all.css` — so it STAYS. `less-plugin-functions` is not vestigial either: it is
what makes `size()` and `px()` callable, at 186 sites across 30 files.
THE REAL BLOCKER WAS ONE LINE OF THE PLUGIN'S, under its own comment calling it
"the most ugly hack ever":
DetachedSet.prototype.type = 'NotDetachedRuleset';
LESS 4 defines that property with only a getter, so the assignment throws and
every compile dies. `scripts/less-plugin-compat.js` makes the assignment a NO-OP
rather than making it work — the hack exists so a mixin can return a detached
ruleset, and ours return plain values. Costed against the alternatives before
choosing: rewriting 186 call sites changes a computed value at every one and
destroys the readability `size()` exists for; a fork or `patch-package` adds
something to maintain.
TWO FURTHER CHANGES THE BUMP FORCED:
- `math: 'always'`. LESS 4 defaults to `parens-division`, under which `1/4` in
`_variables.less:236` stops being a quotient and `round` gets a non-number.
`always` is LESS 3's semantics and is what keeps the output identical.
- The node build must be required EXPLICITLY. LESS 4's manifest carries a
`browser` field and jest's jsdom environment resolves it, so four CSS suites
failed with a jsdom `AggregateError` from a socket — the browser build fetches
`@import`s over XHR. That error looks nothing like a LESS problem and cost a
detour; the reason is now a comment where the require is.
ALL THREE LIVE IN ONE MODULE. `scripts/less-options.js` is what every LESS
compile imports — three webpack configs, `build-css.js`, the fixture and vendor
generators, and four CSS suites. Ten sites used to set these options
independently, which is the shape that already bit us with the `theme.config`
copy: one implementation cannot drift from another.
A METHOD NOTE, because it nearly produced a false pass: the first LESS 4 trial
succeeded against a copy of the plugin I had patched by hand while diagnosing.
Restoring it to pristine upstream and re-running is what actually proved the shim
does the work.
Gates: jsdom 167 suites / 2540 tests / 38 snapshots on React 16.14, 17 and 18.3,
four consecutive full runs with output kept; Chrome 41/41; `lint:js`,
`lint:css`, `css:fixture:check`, both docs checks, `build-lib` and `build-css`
green; published CSS byte-identical.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The 3.13 pin is gone — the project is on LESS 4 — and the published
static/all.cssstill has the sha256 it has had all through the exit (dcdb0a40…). Verified before touching the manifest, by compiling the same source through both majors and comparing byte for byte.Neither anchor was what §9.8 said it was
Step 4 had already measured this, and it holds:
javascriptEnabledstays. It is required by our own_variables.less:23— a`Math.random()`font cache-buster, which reachesstatic/font.cssand neverall.css. Not Semantic's requirement, and removing it is a separate decision about font caching.less-plugin-functionsstays. It is not vestigial: it is what makessize()andpx()callable, at 186 sites across 30 files.The real blocker was one line of the plugin's
Under its own comment calling it "the most ugly hack ever":
LESS 4 defines that property with only a getter, so the assignment throws and every compile dies.
scripts/less-plugin-compat.jsmakes the assignment a no-op rather than making it work — the hack exists so a mixin can return a detached ruleset, and ours return plain values.Costed against the alternatives before choosing: rewriting 186 call sites changes a computed value at every one and destroys the readability
size()exists for; a fork orpatch-packageadds something to maintain.Two further changes the bump forced
math: 'always'. LESS 4 defaults toparens-division, under which1/4in_variables.less:236stops being a quotient androundreceives a non-number.alwaysis LESS 3's semantics, and it is what keeps the output identical.browserfield and jest'sjsdomenvironment resolves it — so four CSS suites failed with a jsdomAggregateErrorfrom a socket, because the browser build fetches@imports over XHR. That error looks nothing like a LESS problem; the reason is now a comment where the require is.One module, not ten sites
All three live in
scripts/less-options.js, which every LESS compile imports: three webpack configs,build-css.js, the fixture and vendor generators, and four CSS suites. Ten sites used to set these options independently — the same shape that already bit us with thetheme.configcopy.A method note
The first LESS 4 trial succeeded against a copy of the plugin I had patched by hand while diagnosing. Restoring it to pristine upstream and re-running is what actually proved the shim does the work. Worth recording: a green result from a tree you have been poking at is not a result.
Gates
jsdom 167 suites / 2540 tests / 38 snapshots on React 16.14, 17 and 18.3, four consecutive full runs with output kept; Chrome 41/41;
lint:js,lint:css,css:fixture:check, both docs checks,build-libandbuild-cssgreen; published CSS byte-identical.🤖 Generated with Claude Code