Skip to content
LogoLogo

Examples

One CRM whose features are plugins, built three times. The SPA is the runtime channel on its own; the two Next.js shells share examples/crm-core — the same manifest rendered by two different servers.

npm run dev:spa        # http://localhost:5173 — client-rendered, createSlot only
npm run dev:next-pages # http://localhost:3000 — Next.js pages router, SSR
npm run dev:next-app   # http://localhost:3001 — app router: RSC tier 2 + streaming

SPA — the runtime channel alone

examples/spa

No manifest, no Resolution and no provider: a plugin is a component that contributes through the createSlot() façade, and installing it is mounting it as a child of the shell. Live toggles are &&. Per-row hosts hand the same fill different props.

It is also where the runtime channel's cost is visible — no error boundary wraps a fill, so the crash-test feature has to bring its own.

Pages router — the registry, server-rendered

examples/nextjs-pages

The same features declared up front, resolved once per request, in the HTML the server sends. Run it and view source at http://localhost:3000/deals?view=stale:

  • the plugins' nav items, deal actions and panels are already in the markup;
  • the saved view has already been applied by the application's resolved table;
  • the pipeline card carries the target its preload fetched.

Two things are missing from that HTML on purpose: the status bar shows its placeholder, because it is a façade fill, and the command list is empty, because setup runs in an effect. Both appear a moment after hydration.

That page is the difference between the two channels, stated in markup instead of prose.

App router — RSC and streaming

examples/nextjs-app

The same HTML again, under React Server Components — tier 2 of the RSC story. The manifests follow the two-module discipline, so a server layout calls resolvePlugins from create-slot/core and hands the whole Resolution across the client boundary as a prop. The sidebar carries a host with no client half at all — entriesOf plus ContributionBoundary in app/server-nav.tsx — and one slow dashboard card streams in on its own, after the rest of the page.

Shared core

examples/crm-core

The features both Next.js shells mount, and where the patterns the library deliberately leaves to the application actually live:

  • resolveViews — exclusive claims, resolved into one table before render, reporting the plugin it refused
  • describeCatalog — an inventory, which is a .map
  • redux slices combined from the catalog, with preload for server-side initial state, and a mobx store per application instance — see Plugin state
  • crm-core/server — the server seam: plugin ids and per-request loaders in a module the server graph can import, separate from the manifests that point at it