Skip to content

perf: shrink the shipped CSS - #338

Merged
mic-web merged 2 commits into
masterfrom
minify-css
Oct 30, 2026
Merged

mic-web merged 2 commits into
masterfrom
minify-css

Conversation

@spawnia

@spawnia spawnia commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

The library ships index.css unminified, with a second, unprefixed copy of some antd 4 styles.
Consumers that inline it as a JavaScript string, such as through style-loader, ship all of it.

esm/index.css Raw gzip
Before 903,158 bytes 93.1 KB
Minified with cssnano 740,843 bytes 85.0 KB
Without the unprefixed copy 590,687 bytes 68.8 KB
The unprefixed copy styles no component of the library

Grid and DatePicker imported antd/es/grid/style/index and antd/es/date-picker/style/index.
rollup-plugin-styles compiled those without the @ant-prefix: mll-ant of src/antd.less, so they emitted .ant-row, .ant-btn, .ant-tag and a second copy of antd's base styles.
Provider sets prefixCls: 'mll-ant', so components render only mll-ant- classes.
src/antd.less covers the same components with the prefix: .mll-ant-col-8, .mll-ant-row, .mll-ant-picker, .mll-ant-btn and .mll-ant-tag all remain.

A consumer that still runs antd 3 got these rules on its own .ant- elements.
Removing them can change how such a consumer looks, so the alpha below gets a visual check there.

The copy also carried antd's base styles in the default theme, after the compact ones.
They set body to font-size: 14px; line-height: 1.5715, so Storybook and consumers that leave body to the library now get the compact 12px; 1.337.

cssnano keeps every @Keyframes, @media and !important declaration

Compared before and after minifying:

  • 61 @keyframes and 32 @media in both. Dropping the unprefixed copy then removes 5 @media of its grid.
  • Every !important declaration stays. The count drops from 101 to 95 only because cssnano merges identical rules and shortens values, such as rgba(0, 0, 0, 0.85) → rgba(0,0,0,.85).
  • url('#linearGradient-1') of the Empty image stays as written.
A per-module build would save a consumer that uses most components little, so it stays out

A prototype shipped each module with preserveModules and compiled one prefixed stylesheet per antd component, imported by the modules that use it.
Measured with webpack 5 in production mode, honoring sideEffects:

Consumer bundle CSS today CSS per module JS today JS per module
116 of 151 exports, as our main consumer uses 591 KB (68.5 KB gzip) 549 KB (64.2 KB gzip) 2.30 MB (609 KB gzip) 2.36 MB (625 KB gzip)
Button only 591 KB 61 KB 2.22 MB 225 KB

It pays off only for consumers that use a few components.
It would be a major release: esm/index.css goes away, the CSS loads through side-effect imports that need a CSS-capable bundler or a Jest mapper, and antd resolves from the consumer's node_modules.

For agents 🤖: visual check passed, in review by mic-web
  • Two commits: minimize: true in styles() of rollup.config.js, then the two style imports removed from src/Grid/index.tsx and src/DatePicker/index.tsx. cssnano 5 comes with rollup-plugin-styles 4, so no new dependency.
  • 21.0.1-alpha.1 is published from the alpha branch, reset to this branch. The visual check in a consumer passed: screenshots of 9 pages identical, only inert antd 3 declarations changed. Next: merge.
  • perf: gives a patch release through semantic-release.
  • Six unprefixed selectors remain, .ant-divider-inner-text and .ant-motion-collapse*, from antd/dist/antd.less itself.
  • Storybook compiles every .less through less-loader in .storybook/main.ts, so it showed the unprefixed copy too. Its body text drops from 14px to the compact 12px; components keep their prefixed styles from src/antd.less.
  • Build output for comparison is untracked: yarn build on the branch writes esm/index.css.
  • The per-module prototype is uncommitted on the local branch per-module-build-prototype. Its side findings, unverified: the source mixes antd/lib and antd/es imports, which can yield two copies of the ConfigProvider context, and babel-plugin-import never runs on .ts/.tsx.

🤖 Generated with Claude Code

esm/index.css and cjs/index.css shrink from 903 KB to 741 KB.

🤖 Generated with Claude Code
Their per-component style imports compiled without the mll-ant prefix and
added a second, unprefixed copy of the base, grid, button, tag and
date-picker styles that no component renders. src/antd.less already
covers them with the prefix.

esm/index.css, minified: 740,843 → 590,687 bytes, gzip 85.0 → 68.8 KB.

🤖 Generated with Claude Code
@spawnia spawnia changed the title perf: minify the shipped CSS perf: shrink the shipped CSS Oct 29, 2026
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 21.0.1-alpha.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@spawnia
spawnia marked this pull request as ready for review October 29, 2026 15:34
@spawnia
spawnia requested a review from mic-web October 29, 2026 15:34
@mic-web
mic-web merged commit c95153b into master Oct 30, 2026
16 checks passed
@mic-web
mic-web deleted the minify-css branch October 30, 2026 07:07
github-actions Bot pushed a commit that referenced this pull request Oct 30, 2026
## [21.0.1](v21.0.0...v21.0.1) (2026-10-30)

### Performance Improvements

* shrink the shipped CSS ([#338](#338)) ([c95153b](c95153b))
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 21.0.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants