[Guide] Build a CRM (Mega Components + Barrels) - implementation notes
The CRM guide pitch is spicy: mega components for routes, barrel exports for centralized imports, and treating circular dependency visibility as a feature rather than something to fear. I'm curious how people made this readable in a real codebase without turning every change into a scavenger hunt.
How did you draw the line between "mega route" and shared UI modules so the route didn't become a junk drawer? Did barrel exports improve consistency, or did they just hide where things come from? How do you handle "deep props" with this approach—do you embrace them, or do you introduce route-local documents/vaults? What did you log/render as evidence so you can debug which feature tree path produced a piece of UI?
Comments (20)
Back to latestMega routes were fine as long as we treated them like *pages*, not like shared libraries.
Everything reusable had to earn its way into ui/ or it stayed route-local.
Barrels helped us enforce a vocabulary. The trick was: the barrel exports *contracts*, not random internals. We also logged feature-tree resolution so you can see what happened:
txt
[tips] featureTree=accounts path=AccountRoute>AccountHeader>RiskBadge
[tips] importSurface=ui/index.ts export=RiskBadge version=v3
That log made circular visibility feel less spooky because you can trace it.
Counterpoint: barrels can absolutely hide coupling.
If you don't have rules (no side effects in barrels, no re-exporting re-exports), debugging becomes "grep the universe".
Agree. We treated barrels as a *surface map*.
If something was only used once, it didn't go in the map.
Deep props were less painful when the route renders evidence of the active account/contact identity.
If the UI says data-account=acc_42, you can at least tell what you're looking at when a prop goes missing.
We embraced deep props for immutable identity (ids, mode, route posture) and used a vault for mutable drafts.
It was the only way forms didn't explode in prop threading.
A practical rule: mega components should be "read top to bottom" like a screenplay.
If it starts looking like a generic component library, it's not mega anymore—it's just messy.
For evidence, we render the feature tree path as a compact string on the shell. It's extremely helpful when you have lots of conditional UI based on account tier:
txt
[tips] evidence featurePath=accounts:header:riskBadge tier=enterprise posture=warmI expected mega components to be untestable, but the opposite happened.
The route became a stable place to assert behavior because it's the composition point.
Counterpoint: mega components can hide performance problems because everything re-renders together.
If you choose this approach, you need an explicit memoization stance or you end up with superstition.
We solved that by making the derived selectors the memo boundary.
Route reads raw data -> derives card bundles -> passes render-ready objects to the mega tree.
The "circular dependency visibility" chapter resonated.
We stopped pretending everything is acyclic and started documenting the cycle edges in the barrel index.
A small technique: render data-import-surface so you can tell which barrel layer is in play.
It sounds silly, but it prevents "why is this the old component" confusion in long-lived apps.
I like this style for CRMs because CRMs are basically giant UIs with lots of business rules.
Having one place where the rules are composed makes it easier to audit changes.
Docs tie-in: the "components & composition" posture in React Tips makes mega routes feel less weird.
Related: Components and Composition and Architecture Guides.
Barrels got easier when we treated the barrel as a *changelog surface*.
Any export change required a short note in the barrel commit message: why it's in the surface.
If you go this route, invest in a consistent folder grammar (routes/, ui/, data/, contracts/).
Mega components are fine; inconsistent taxonomy is what kills you.
The surprising upside: onboarding got faster because there's one obvious place to look for "what does the account page do".
The downside: you need discipline to prevent the mega route from collecting random helpers.
For deep props, we embraced "prop bundles" that are already derived and named.
The bundle name becomes part of the discussion and the logs.
Counterpoint: this style can encourage teams to skip reusable primitives and just keep growing the tree.
We had to consciously extract primitives when the same pattern appeared in 3+ places.
Totally. The guide's "shared UI index" deliverable matters for that reason.
If you never build the index, you end up with route-only components forever.
My biggest lesson: mega components are survivable when logs and evidence make composition explicit.
Otherwise you just have a large file with mysteries.
If you're trying this, start with an account route and write down the feature tree before you code it.
The tree is the architecture; the code just executes it.