Skip to content

perf: cut bundle size by 24.6% (12.0% gzip), drop runtime deps, require Node >=6 - #355

Closed
mattrbeck wants to merge 1 commit into
postcss:mainfrom
mattrbeck:optimize-bundle-size
Closed

mattrbeck wants to merge 1 commit into
postcss:mainfrom
mattrbeck:optimize-bundle-size

Conversation

@mattrbeck

Copy link
Copy Markdown
Contributor

Effect

All numbers are compared with main.

main this PR change
Bundle, minified (esbuild --bundle --minify, dist/index.js) 64,923 B 48,944 B −24.6%
Bundle, gzip -9 15,124 B 13,313 B −12.0%
Bundle, brotli 13,465 B 11,952 B −11.2%
Install size (vs published 7.1.7 plus its dependencies) 242,749 B, 3 packages 196,007 B, 1 package −19.3%
Parse + stringify benchmark (Node 24, median of 9 runs) 336 ms 239 ms −29%
className/attribute escaping benchmark 214 ms 89 ms −58%

Compatibility

Important

engines.node goes from >=4 to >=6.

  • The compiled output is now ES2015 syntax (default/rest parameters, spread, classes), which Node 4/5 can't run.
  • Node 4 has been officially unsupported since 5.0.0-rc.1 (see CHANGELOG.md).
  • postcss 8 already requires Node ^10 || ^12 || >=14.
  • Browser bundles that must ship ES5 (e.g. IE11) will now need their bundler to transpile this package.
  • The public API and outputs are unchanged.

Changes

Savings are cumulative, with the changes applied in this order:

Change gzip minified
tsc target es5 → es2015 −1,550 B (−10.2%) −15,131 B
Bundle a trimmed copy of cssesc and drop the dependency −191 B (−1.3%) −443 B
Replace util-deprecate and drop the dependency −74 B (−0.5%) −191 B
Share one helper across the Container#walk* methods +4 B −214 B
  • cssesc copy (src/util/cssesc.js): trimmed to the options this package uses (isIdentifier, quotes, wrap), with the upstream MIT notice kept. It was tested against cssesc@3 on 1M fuzzed inputs with 0 differences.
  • Deprecation helper: on Node it calls process.emitWarning(msg, "DeprecationWarning"), so --no-deprecation, --throw-deprecation and process.on("warning") behave as before. Elsewhere it falls back to console.warn.

Testing

  • npm test: lint, typecheck and coverage all pass (897/897 tests).
  • npm run format:check reports nothing new; the only flagged files were already flagged on main.

…re Node >=6

Effect, measured against upstream main (1343320):

  Bundle (esbuild --bundle --minify on dist/index.js, browser):
    minified  64,923 -> 48,944 B  (-15,979 B, -24.6%)
    gzip -9   15,124 -> 13,313 B   (-1,811 B, -12.0%)
    brotli    13,465 -> 11,952 B   (-1,513 B, -11.2%)

  Install footprint (vs published 7.1.7 + its dependencies):
    242,749 B in 3 packages -> 196,007 B in 1 package (-46,742 B, -19.3%)

  Runtime (Node 24, median of 9 runs):
    parse + stringify benchmark  336 -> 239 ms  (-29%)
    className/attribute escaping 214 -> 89 ms   (-58%)

  Compatibility:
    engines.node is bumped from >=4 to >=6. The dist is now ES2015
    syntax (default/rest params, spread, classes), which Node 4/5 cannot
    run. Node 4 has been officially unsupported since 5.0.0-rc.1, and
    postcss 8 already requires Node ^10 || ^12 || >=14. Browser bundles
    that must ship ES5 (e.g. IE11) now need to transpile this package.
    Public API and outputs are unchanged.

Changes, with cumulative gzip/minified savings applied in this order:

- tsconfig target es5 -> es2015: -1,550 B gzip (-10.2%), -15,131 B min.
  ES5 output carried class/iterator downlevel helpers.
- Inline cssesc as src/util/cssesc.js, trimmed to the options this
  package uses (isIdentifier, quotes, wrap), keeping the upstream MIT
  notice; drop the cssesc dependency: -191 B gzip (-1.3%), -443 B min.
  Output is identical to cssesc@3 on 1M fuzzed inputs.
- Replace util-deprecate with a small helper that emits a
  DeprecationWarning via process.emitWarning on Node (so
  --no-deprecation, --throw-deprecation and process.on("warning") keep
  working) and falls back to console.warn elsewhere; drop the
  dependency: -74 B gzip (-0.5%), -191 B min.
- Deduplicate the Container#walk* methods via a shared _walkType
  helper: +4 B gzip, -214 B min.
@mattrbeck

Copy link
Copy Markdown
Contributor Author

Apologies for the noise. I was experimenting with this locally, and Gemini got eager and published. I'll re-open this in a better state if there's any desire for it. Feel free to take anything you like from this PR if you feel so inclined.

@mattrbeck mattrbeck closed this Nov 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant