From c4f4e5c67ec9d3c26f31b963318e9c33f36bd37f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Jul 2026 23:44:37 +0000 Subject: [PATCH 1/2] docs: optimizing CSS size guide with measured flavors; scaffold size hints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs half of #193. New getting-started page with the three levers, cheapest first: (1) lighter flavors — a measured size table from the current minified dist (complete ~800KB/~82KB gzip down to no-helpers ~595KB/~67KB), with the no-helpers warning that helper props compile to the removed classes; (2) an opt-in PurgeCSS recipe for Vite with the Bulma-aware safelist (is-/has-/theme-*/bestax-*) and verify-your-states guidance; (3) the modular Sass path via the existing Modular guide. variations.md links to it; the create-bestax flavor picker descriptions now carry the gzip sizes so the tradeoff is visible at scaffold time. The opt-in purge tooling in the scaffold itself (issue's remaining half) still needs a design decision and stays open on #193. Refs #193 Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Pohc8xLkdx4gwXkW3xd7up --- create-bestax/src/constants.ts | 12 +- .../guides/getting-started/optimizing-css.md | 107 ++++++++++++++++++ .../docs/guides/getting-started/variations.md | 4 + 3 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 docs/docs/guides/getting-started/optimizing-css.md diff --git a/create-bestax/src/constants.ts b/create-bestax/src/constants.ts index 67c08dd3c..4fc592793 100644 --- a/create-bestax/src/constants.ts +++ b/create-bestax/src/constants.ts @@ -201,14 +201,15 @@ export const BULMA_FLAVORS: BulmaFlavor[] = [ { name: 'complete', display: 'Complete (Recommended)', - description: 'Full Bulma CSS with all components and helpers', + description: 'Full Bulma CSS with all components and helpers (~82 KB gzip)', color: chalk.green, importStatement: "import '@allxsmith/bestax-bulma/bestax.css';", }, { name: 'prefixed', display: 'Prefixed', - description: 'All classes prefixed with "bestax-" to avoid conflicts', + description: + 'All classes prefixed with "bestax-" to avoid conflicts (~84 KB gzip)', color: chalk.blue, importStatement: "import '@allxsmith/bestax-bulma/versions/bestax-prefixed.css';", @@ -217,7 +218,8 @@ export const BULMA_FLAVORS: BulmaFlavor[] = [ { name: 'no-helpers', display: 'No Helpers', - description: 'Core components only, no utility classes', + description: + 'Core components only, no utility classes — helper props need them (~67 KB gzip)', color: chalk.yellow, importStatement: "import '@allxsmith/bestax-bulma/versions/bestax-no-helpers.css';", @@ -225,7 +227,7 @@ export const BULMA_FLAVORS: BulmaFlavor[] = [ { name: 'no-helpers-prefixed', display: 'No Helpers, Prefixed', - description: 'Core components only with "bestax-" prefix', + description: 'Core components only with "bestax-" prefix (~69 KB gzip)', color: chalk.magenta, importStatement: "import '@allxsmith/bestax-bulma/versions/bestax-no-helpers-prefixed.css';", @@ -234,7 +236,7 @@ export const BULMA_FLAVORS: BulmaFlavor[] = [ { name: 'no-dark-mode', display: 'No Dark Mode', - description: 'Light mode only, smaller bundle size', + description: 'Light mode only, smaller bundle size (~70 KB gzip)', color: chalk.cyan, importStatement: "import '@allxsmith/bestax-bulma/versions/bestax-no-dark-mode.css';", diff --git a/docs/docs/guides/getting-started/optimizing-css.md b/docs/docs/guides/getting-started/optimizing-css.md new file mode 100644 index 000000000..326d3c94f --- /dev/null +++ b/docs/docs/guides/getting-started/optimizing-css.md @@ -0,0 +1,107 @@ +--- +title: Optimizing CSS Size +sidebar_label: Optimizing CSS Size +sidebar_position: 6 +--- + +# Optimizing CSS Size + +The JavaScript side of bestax-bulma is lean and tree-shakable (~21 KB gzipped for typical +usage) — but the **stylesheet** ships all of Bulma plus the bestax extras, whatever your app +uses. With the default `complete` flavor, that's roughly **800 KB of CSS (~82 KB gzipped)** in +a production build, essentially constant regardless of how many components you render. + +That's a reasonable default — every component just works, helpers included — but if CSS weight +matters to you, this page gives you the three levers, cheapest first. + +_Sizes below are the minified files shipped in the current package; expect small drift between +releases._ + +## Lever 1 — pick a lighter flavor (zero effort) + +The [CSS variations](./variations.md) trade features for weight. If you don't use Bulma's +helper classes (bestax's helper **props** like `mt="4"` compile to them — most apps _do_ use +them), or you [pin a single color scheme](../features/css-variables.md#dark-mode--contrast), +the lighter flavors are a one-line change: + +| Flavor | Import | Raw | Gzip | +| -------------------------------------------- | ----------------------------------------- | ------- | ------ | +| `complete` (default) | `bestax.css` | ~800 KB | ~82 KB | +| `no-dark-mode` | `versions/bestax-no-dark-mode.css` | ~680 KB | ~70 KB | +| `no-helpers` | `versions/bestax-no-helpers.css` | ~595 KB | ~67 KB | +| `no-helpers` + `prefixed` | `versions/bestax-no-helpers-prefixed.css` | ~655 KB | ~69 KB | +| `prefixed` (compat, not a size optimization) | `versions/bestax-prefixed.css` | ~875 KB | ~84 KB | + +:::warning +`no-helpers` removes the classes that the **helper props** (`m`/`p`, `textAlign`, +`textColor`, `display`, …) compile to — components render, but those props do nothing. Only +pick it if your app styles without them. +::: + +The `npm create bestax` scaffold's `--bulma` flag selects a flavor at project creation +(`-b no-dark-mode`, etc.). + +## Lever 2 — purge unused selectors (build step, biggest win) + +Most of the remaining weight is selectors your app never renders. An opt-in +[PurgeCSS](https://purgecss.com/) step removes them at build time. In a Vite app: + +```bash +npm install -D @fullhuman/postcss-purgecss +``` + +```js title="postcss.config.js" +import purgecss from '@fullhuman/postcss-purgecss'; + +export default { + plugins: [ + ...(process.env.NODE_ENV === 'production' + ? [ + purgecss({ + content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'], + // Bulma builds class names dynamically (is-active, has-*, data-theme + // scheme flips) and bestax composes them at runtime — safelist by + // pattern so state/scheme classes survive: + safelist: { + standard: [/^is-/, /^has-/], + deep: [/theme-dark/, /theme-light/], + greedy: [/^bestax-/], + }, + }), + ] + : []), + ], +}; +``` + +Results depend entirely on how much of the framework you use — small apps commonly drop the +stylesheet by half or more. **Verify the UI after enabling it**: any class name your app +produces only at runtime that isn't matched by `content` scanning or the safelist gets +purged. Test open/active/error states and both color schemes before trusting the number. + +:::tip +Keep the `safelist` patterns above as your starting point. If a style disappears in +production only, it's almost always a purged dynamic class — widen the safelist rather than +disabling the plugin. +::: + +## Lever 3 — hand-rolled modular Sass (maximum control) + +Compile only the Bulma modules and bestax extras partials you actually use — the +[Modular guide's Option C](./modular.md#option-c--hand-rolled-modular-scss-advanced) walks +through it. This yields the smallest honest stylesheet with no purging heuristics, at the cost +of maintaining the import list as your usage grows. + +## Which lever? + +- Shipping a typical app and want a quick win → **Lever 1** (`no-dark-mode` if you pinned a + scheme). +- CSS weight is a real budget item → **Lever 2**, verified against your UI states. +- Design-system discipline and a stable component set → **Lever 3**. + +## Related + +- [CSS Variations](./variations.md) — what each flavor includes. +- [Modular](./modular.md) — JS tree-shaking and the three CSS loading strategies. +- [Dark Mode & Contrast](../features/css-variables.md#dark-mode--contrast) — pin the scheme + before reaching for `no-dark-mode`. diff --git a/docs/docs/guides/getting-started/variations.md b/docs/docs/guides/getting-started/variations.md index aa96d9d75..4f35125d9 100644 --- a/docs/docs/guides/getting-started/variations.md +++ b/docs/docs/guides/getting-started/variations.md @@ -8,6 +8,10 @@ sidebar_position: 2 Bestax ships pre-built CSS variations that combine Bulma with bestax extras into a single file. Each variation mirrors a Bulma variation but includes all bestax extra component styles, so you only need one CSS import. +The variations also differ in **size** — from ~82 KB gzipped (`complete`) down to ~67 KB +(`no-helpers`). For the measured size table, an opt-in PurgeCSS recipe, and guidance on +choosing, see [Optimizing CSS Size](./optimizing-css.md). + --- ## Complete (Recommended) From 53e825bd276137e1eb08efc033c50be75fd6134a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Jul 2026 23:52:45 +0000 Subject: [PATCH 2/2] docs: harden the purgecss recipe against runtime-composed classes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review findings on the Lever 2 safelist, all verified against the helper implementation and Bulma's emitted selectors: - Safelist the spacing classes (m-*/p-* and axis variants) — useSpacingClasses composes them at runtime, so content scanning never sees them (CodeRabbit). - Safelist the [data-theme] attribute selector — Theme colorMode sets the attribute, and /theme-dark/ does not match '[data-theme=dark]', so PurgeCSS could prune the exact scheme flip the comment promised to protect (deep review). - Scan the library bundle in content — the static class literals (button, card, …) live in dist, not app source, and 'Button' in JSX does not match '.button' case-sensitively. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01Pohc8xLkdx4gwXkW3xd7up --- .../guides/getting-started/optimizing-css.md | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/docs/guides/getting-started/optimizing-css.md b/docs/docs/guides/getting-started/optimizing-css.md index 326d3c94f..34127b881 100644 --- a/docs/docs/guides/getting-started/optimizing-css.md +++ b/docs/docs/guides/getting-started/optimizing-css.md @@ -58,14 +58,21 @@ export default { ...(process.env.NODE_ENV === 'production' ? [ purgecss({ - content: ['./index.html', './src/**/*.{js,jsx,ts,tsx}'], - // Bulma builds class names dynamically (is-active, has-*, data-theme - // scheme flips) and bestax composes them at runtime — safelist by - // pattern so state/scheme classes survive: + content: [ + './index.html', + './src/**/*.{js,jsx,ts,tsx}', + // bestax's static class literals (button, card, …) live in the + // library bundle, not your source — scan it too: + './node_modules/@allxsmith/bestax-bulma/dist/**/*.js', + ], + // Classes bestax assembles at runtime (helper props like mt="4" + // → mt-4, is-active state flips, [data-theme] scheme switching) + // never appear verbatim in any scanned file — safelist them by + // pattern: safelist: { - standard: [/^is-/, /^has-/], - deep: [/theme-dark/, /theme-light/], - greedy: [/^bestax-/], + standard: [/^is-/, /^has-/, /^m[trblxy]?-/, /^p[trblxy]?-/], + deep: [/data-theme/, /theme-dark/, /theme-light/], + greedy: [/^bestax-/, /data-theme/], }, }), ]