|
1 | 1 | Here are the scripts exposed as utility to the user of `react-dsfr` |
| 2 | + |
| 3 | +| Command | Standalone bin | What it does | |
| 4 | +| --------------------------------------------- | ------------------------------ | ---------------------------------------------------------------------------------- | |
| 5 | +| `npx react-dsfr copy-static-assets` | `copy-dsfr-to-public` | Copies the DSFR assets into `public/dsfr` (SPA setups: Vite, CRA). | |
| 6 | +| `npx react-dsfr update-icons` | `only-include-used-icons` | Rebuilds `dsfr/utility/icons/icons.min.css` with only the icons you use. | |
| 7 | +| `npx react-dsfr only-include-used-components` | `only-include-used-components` | Rebuilds `dsfr/dsfr.css` and `dsfr/dsfr.min.css` with only the components you use. | |
| 8 | + |
| 9 | +Every script accepts `--projectDir <path>` to point at the react project (monorepos), |
| 10 | +defaulting to the current working directory. `update-icons` and |
| 11 | +`only-include-used-components` also accept `--silent` to disable the `console.log` |
| 12 | +(warnings are never silenced). |
| 13 | + |
| 14 | +# `only-include-used-components` |
| 15 | + |
| 16 | +Opt-in. `dsfr.min.css` weighs ~600 kB raw / ~76 kB gzip and is loaded render-blocking, |
| 17 | +while most apps use a small subset of the DSFR components. |
| 18 | + |
| 19 | +This script rebuilds `dsfr.css` and `dsfr.min.css` in `node_modules` (and |
| 20 | +`public/dsfr/dsfr.min.css` in SPA setups) by concatenating the granular stylesheets |
| 21 | +already shipped in the package (`dsfr/core/*`, `dsfr/scheme/*`, `dsfr/component/<name>/*`). |
| 22 | +**Whole components are included or excluded, never individual rules**, so everything the |
| 23 | +DSFR JavaScript toggles at runtime (`data-fr-js-*`, `fr-collapse--expanded`, ...) keeps |
| 24 | +working — unlike a PurgeCSS style pass. |
| 25 | + |
| 26 | +## Usage |
| 27 | + |
| 28 | +```bash |
| 29 | +npx react-dsfr only-include-used-components |
| 30 | +``` |
| 31 | + |
| 32 | +Typically as a `prebuild`/`predev` step: |
| 33 | + |
| 34 | +```jsonc |
| 35 | +"scripts": { |
| 36 | + "predev": "react-dsfr update-icons && react-dsfr only-include-used-components", |
| 37 | + "prebuild": "react-dsfr update-icons && react-dsfr only-include-used-components" |
| 38 | +} |
| 39 | +``` |
| 40 | + |
| 41 | +## Ordering with `copy-static-assets` |
| 42 | + |
| 43 | +In SPA setups (Vite, CRA), run `copy-static-assets` **before** |
| 44 | +`only-include-used-components`, not after: |
| 45 | + |
| 46 | +```jsonc |
| 47 | +"prebuild": "react-dsfr copy-static-assets && react-dsfr update-icons && react-dsfr only-include-used-components" |
| 48 | +``` |
| 49 | + |
| 50 | +`copy-static-assets` builds its keep list from the `url()` of the `dsfr.min.css` it finds |
| 51 | +in `node_modules`, then early returns on every later run as long as |
| 52 | +`public/dsfr/version.txt` matches the `@gouvfr/dsfr` version. Running it against an |
| 53 | +already trimmed stylesheet freezes `public/dsfr` on that asset subset. |
| 54 | +`only-include-used-components` copies the assets its own output references, so a component |
| 55 | +added later still gets its icons — but keeping the order above avoids relying on it. |
| 56 | + |
| 57 | +## Detection of used components |
| 58 | + |
| 59 | +1. **Imports** of `@codegouvfr/react-dsfr/<Module>` in your sources |
| 60 | + (`.ts`, `.tsx`, `.js`, `.jsx`, `.mdx`, `.html`, `.svelte`, `.vue`), resolved through a |
| 61 | + static table that includes transitive dependencies (a `Header` renders a navigation, a |
| 62 | + search bar and a modal). |
| 63 | +2. **Raw class names**, e.g. `fr.cx("fr-table")` or a plain `class="fr-table"`, for when |
| 64 | + you use DSFR classes without the React component. |
| 65 | + |
| 66 | +Stylesheets (`.css`, `.scss`, ...) are **not** scanned: class name detection is substring |
| 67 | +based, so a single compiled bundle would mark every component as used. Use |
| 68 | +`additionalComponents` below for the components you only reference from a stylesheet. |
| 69 | + |
| 70 | +## `additionalComponents`, the escape hatch |
| 71 | + |
| 72 | +For anything the detection cannot see (class names built dynamically, CMS content, |
| 73 | +components only referenced from a `@import`ed stylesheet), in your **`package.json`**: |
| 74 | + |
| 75 | +```jsonc |
| 76 | +{ |
| 77 | + "react-dsfr": { |
| 78 | + "additionalComponents": ["table", "Range"] |
| 79 | + } |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +Values are DSFR CSS component names (the `dsfr/component/<name>` directories) or |
| 84 | +react-dsfr component names. An unknown value is a hard warning, not a silent no-op. |
| 85 | + |
| 86 | +## Fail-safe and `--strict` |
| 87 | + |
| 88 | +If anything can't be resolved — typically a react-dsfr module added in a newer release that |
| 89 | +this script does not know about — the script **warns and includes every component**. The |
| 90 | +output is then equivalent to the original bundle: never a broken page, but no trimming |
| 91 | +either, and the run still exits `0`. |
| 92 | + |
| 93 | +Because nobody reads warnings in CI, add `--strict` there to turn that fallback into a |
| 94 | +failure: |
| 95 | + |
| 96 | +```bash |
| 97 | +npx react-dsfr only-include-used-components --strict |
| 98 | +``` |
| 99 | + |
| 100 | +Please [report](https://github.com/codegouvfr/react-dsfr/issues) any module that triggers |
| 101 | +the fail-safe, the static tables need to be updated. |
| 102 | + |
| 103 | +## Known limitations |
| 104 | + |
| 105 | +- Detection is textual: a dynamically composed import path or class name is not seen. |
| 106 | + That is what `additionalComponents` is for. |
| 107 | +- `utility/colors` and `utility/icons` are not part of `dsfr.css` upstream and are left |
| 108 | + untouched (icons are handled by `update-icons`). |
0 commit comments