Skip to content

only-include-used-components: opt-in trimming of the spacing utility grid in core (~50-60 kB raw) #508

Description

@kevbarns

Follow-up to #304 and #505. With only-include-used-components in place, the consumer-side floor of the DSFR stylesheet is core — shipped as a single block regardless of usage.

Measured breakdown of core.main.min.css (dsfr 1.14.x, 172 kB raw / 25 kB gzip)

Family Raw weight Notes
Base / reset / HTML elements ~62 kB base typography, forms, lists — hard to split safely
Spacing utilities fr-m*-* / fr-p*-* ~39 kB top-level (927 classes) + a large share of the 29 kB min-width:48em block (1,053 responsive selectors) exhaustive grid of values × sides × breakpoints
All @media blocks 45.3 kB 29.2 kB for 48em, 5.1 kB forced-colors
fr-grid / fr-col 6.9 kB + 196 responsive selectors
Typo utilities (fr-text-*, fr-h*, fr-display) ~1.6 kB
@font-face 1.9 kB negligible

Most apps use a small fraction of the spacing grid, so ~50-60 kB raw (~6-8 kB gzip estimated) is the one core family that is both large and trimmable per class with reasonable guarantees: unlike component CSS, these classes are never toggled by the DSFR runtime (data-fr-js-*), so the failure mode of rule-level purging that #505 deliberately avoided does not apply in the same way. The remaining risk is dynamically built class names (`fr-mt-${x}`).

Proposal: opt-in --trim-spacing-utilities in only-include-used-components

Same fail-safe philosophy as #505 — when in doubt, include:

  1. Scan sources for literal fr-(m|p)[trblxvy]?-* classes → allowlist of used utilities.
  2. Detect dynamic forms — any template literal or concatenation whose static prefix matches fr-m/fr-pfall back to including the whole family, with an explicit log line (and a non-silent mode where the fallback is observable in CI).
  3. Separate opt-in from component trimming, so enabling one never silently enables the other.

Tests would need the false-positive cases first (a URL or comment mentioning fr-mt-, an over-broad file that contains everything, the dynamic near-miss), not only the nominal ones.

If the approach sounds right I can put together a PR along the lines of #505/#506.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions