Appearance
Mono-Lith โ
A mono-lith is the mono ecosystem with every app in ONE repository, each in its own folder, connected by apps[].path instead of a GitHub clone. The host reads its remotes in place โ dev, build, mono prepare and mono sync all look at the same sibling directory โ and editing a remote hot-updates the running host.
It is the same federation as Mono-Repo: a host compiles its remotes' pages, components, composables and stores as its own, and a remote run standalone borrows the host's shell. What changes is where the other app lives:
| Mono-Repo (sync) | Mono-Lith (path) | |
|---|---|---|
| One app = | one repository | one folder under apps/ |
| Remotes reach the host by | mono sync โ .mono/apps/<name> clone | apps[].path: '../<name>' |
| Editing a remote | push โ mono sync on the host | the running host hot-updates |
| A build reads | the clone | the sibling |
| Lifting one app out | it already is its own repo | copy the folder; url takes over |
Every arrow is a line in that app's own mono.config.ts. Each folder keeps carrying its own config, its own package.json and its own pnpm-workspace.yaml โ so the folder can still be lifted out into a standalone checkout, where the sibling is gone and mono sync falls back to the url.
Layout โ
esw-ui/
โโโ package.json # the runner: dev / build / test via Vite+ (vp)
โโโ pnpm-workspace.yaml # apps/* + catalogs (lib versions), one install
โโโ .npmrc # the mono-libs registry for mono-*, npmjs for the rest
โโโ vite.config.ts # vite-plus: lint defaults + vitest projects
โโโ apps/
โโโ esw-host/ # the shell โ template: 'host'
โ โโโ mono.config.ts # apps: [{ name: 'esw-project', path: '../esw-project', โฆ }]
โ โโโ vite.config.ts # + monoLith()
โ โโโ src/
โโโ esw-master/ # apps: [{ name: 'esw-host', path: '../esw-host', โฆ }]
โโโ esw-project/ # apps: [{ name: 'esw-host', path: '../esw-host', โฆ }]Nothing under apps/<app>/.mono/apps is needed any more: mono sync reports each path app as ๐ linked and clones nothing. A stale clone left there from before is shadowed by the sibling and left alone.
The config โ
The host names its remotes by path and declares itself the shell:
ts
// apps/esw-host/mono.config.ts
export default defineConfig({
name: 'esw-host',
type: 'vue',
template: 'host', // own layouts only, never a remote's
apps: [
{ name: 'esw-master', path: '../esw-master', url: 'https://github.com/org/esw-master/tree/mono', type: 'vue' },
{ name: 'esw-project', path: '../esw-project', url: 'https://github.com/org/esw-project/tree/mono', type: 'vue' },
],
// env / fetching / menu / โฆ exactly as before
})Each remote names the host back, so it can run standalone with the host's shell:
ts
// apps/esw-project/mono.config.ts
apps: [
{ name: 'esw-host', path: '../esw-host', url: 'https://github.com/org/esw-host/tree/mono', type: 'vue' },
]path is relative to the file that declares it and must be a static string literal with forward slashes โ the config is text-parsed before it can be executed. Everything about the rule is in Config: path and url.
When url still matters โ
Keep the url beside the path. It costs nothing in the lith (path wins whenever the directory exists) and it is what makes a folder portable:
- Lifted out. Copy
apps/esw-projectsomewhere on its own:../esw-hostis absent,mono syncclones the host from theurlinto.mono/apps/esw-host, and the app runs exactly as a Mono-Repo remote. - CI that checks out one app. Same story โ the sibling is not there, the clone is.
- A
pathwith nourlis fine too, but then a missing directory is an error rather than a fallback: there is nothing to sync from.
Running it โ
From the root (see Root runner):
bash
pnpm install # once, at the root โ one node_modules for every sibling
pnpm dev # vp run --filter esw-host dev โ the host, with both remotes live
pnpm dev:project # esw-project standalone, wearing the host's shell
pnpm build # the host bundle, remotes included, from the same siblingsBest practice is to develop and build through the host: that is the bundle that ships. Running a remote on its own is for working on it in isolation, and still reads the real host next door.