Architecture

  • Evaluating it

One package, granular by subpath rather than by sub-package, plus companions for anything heavy. This page shows why the split runs where it does — and recomputes the numbers behind that decision on every build.

Computed at build time from @feugene/granularity 1.1.1

On this page
84
core components
149
export paths
0
runtime dependencies in the core
12
packages in the family

Why the catalogue groups are not package boundaries

The catalogue splits components into groups — actions, forms, data, navigation — and those groups look like ready-made packages. They are not: the groups answer «where do I look for a component», while the dependency graph answers «who renders whom», and the two do not coincide.

92
edges in the render graph
61 (66%)
of them cross group boundaries
4
graph depth
36
components with no dependencies

Edges that cross a group boundary

What everything else is built from

Cut the package along the groups and these components end up in every piece — or behind a peer dependency of every piece.

  • GrIcondatarendered by 15 dependents
  • GrButtonactionsrendered by 15 dependents
  • GrSkeletonfeedbackrendered by 7 dependents
  • GrInputformsrendered by 6 dependents
  • GrChipdatarendered by 4 dependents

Every figure in this section is computed from the installed package: dependencies come from the granular provider, groups from the registry. The library’s own document quotes the same argument measured at an older version — that is exactly why this page measures rather than quotes.

How an import reaches the bundle

Granularity is not a promise about tree-shaking. It is the shape of the package: a subpath per component, an entry per subpath, and a manifest that says which CSS each component needs.

  1. You import a subpath
  2. the bundler takes that entry and its graph
  3. granum reads the package manifests and pulls in the CSS of the components you listed and of their dependencies
  4. the utility engine emits utilities for exactly those classes, and for nothing else

The core and the companions

The core ships the general-purpose components. Anything that carries a heavy dependency, belongs to a domain of its own, or is needed by a minority lives in a companion package with a peer on the core.

That is the one condition under which the decision «one package» is revisited: a family of components acquires a heavy external dependency the rest do not need. Charts, dates, rich text, media and the dashboard left for exactly that reason.

  • @feugene/granularity-chrono
  • @feugene/granularity-media
  • @feugene/granularity-charts
  • @feugene/granularity-code
  • @feugene/granularity-dashboard
  • @feugene/granularity-editor
  • @feugene/granularity-forms-schema

Where the library ends

It is not an application framework. Routing, data fetching, state and the build are yours; the design system gives components, foundations and the pipeline that ties them together — and stops there on purpose.

Read further

The full argument, with the history of the decision, is in the library repository.