Appearance
Root runner (Vite+) โ
The lith's root folder runs the apps; it is not an app itself. One pnpm install gives every sibling the same node_modules, and Vite+ (vp) dispatches dev, build and test to the app you mean โ the host by default.
Why one install โ
A host compiles its siblings' files. If apps/esw-host and apps/esw-project each had their own node_modules, a sibling page importing vue or mono-helper would resolve from its folder and the host would get a second copy of every runtime โ two Vue instances, mono-* custom elements "already defined", Pinia stores that do not share state. In a single pnpm workspace every apps/*/node_modules/vue is a link into the same store entry, so Vite sees one module.
yaml
# pnpm-workspace.yaml
packages:
- apps/*
catalogs:
internal:
esw-helper: git+https://<token>@github.com/EJI-ICT/libs#path:/packages/esw-helper
esw-utils: git+https://<token>@github.com/EJI-ICT/libs#path:/packages/esw-utils
mono-devextreme: 0.0.1
mono-utils: 0.0.3
mono-helper: 0.0.2
build: { vite: 8.0.16, โฆ }
frontend: { vue: 3.5.24, pinia: 3.0.4, โฆ }ini
# .npmrc โ mono-* come from the mono-libs registry; every other name is
# redirected to npmjs at the edge, so this is the only registry line needed.
registry=https://mono-libs.netlify.app/npm/
//mono-libs.netlify.app/npm/:_authToken=<download token>json
// package.json
{
"packageManager": "pnpm@10.7.0",
"pnpm": {
"overrides": { "vue": "3.5.33", "pinia": "3.0.4", "devextreme": "25.1.6" }
}
}Three things worth knowing:
- Each app keeps its own
pnpm-workspace.yaml(the same catalogs). pnpm ignores the nested file while installing from the root, and it is what lets a folder be lifted out and installed on its own. - Catalogs need pnpm โฅ 9.5.
packageManagermust not name an older pnpm โ pnpm 10 would silently switch to it and thecatalog:specs would fail. - Only
apps/*is in the workspace. Never add a checkout of the libs themselves (or any package that ships its ownvite.config.ts) โvp runloads every workspace package's Vite config to build its task graph.
The libs โ
mono-utils, mono-helper and mono-devextreme are versioned releases on the mono-libs registry (.npmrc above; the versions live in catalogs.internal). esw-helper / esw-utils are token-based git specs. A lith app therefore installs exactly like a Mono-Repo app โ no local libs checkout is involved.
Shipping a lib change is a release: in the libs repo bump the package's package.json and append the version to version.json, run REGISTRY_PUBLISH_TOKEN=โฆ pnpm registry:publish (versions are immutable; devextreme โ utils โ helper), then raise the version in the catalog here and pnpm install. apps[].path needs mono-utils >= 0.0.3.
Iterating on a lib without publishing
Point the root overrides at a local checkout for the duration โ "mono-utils": "link:../../libs/packages/mono-utils" โ and remove the override before committing. A rebuild in libs is then live in every sibling.
Scripts โ
json
{
"scripts": {
"dev": "vp run --filter esw-host dev",
"dev:master": "vp run --filter esw-master dev",
"dev:project": "vp run --filter esw-project dev",
"build": "vp run --filter esw-host build",
"build:dev": "vp run --filter esw-host build:dev",
"build:all": "vp run -r build",
"test": "vp test",
"mono:prepare": "vp run -r mono:prepare"
}
}vp run --filter <name> <script> runs that package's own package.json script (pnpm filter syntax: by name, "./apps/esw-*" by directory, "esw-host..." with dependents), so each app's dev is still mono prepare && mono env -e .env.dev -- vite with the app's own Vite โ Vite+'s bundled core never enters the picture. -r runs a script in every workspace package in dependency order; vp -C apps/esw-project dev runs any command as if you had cd'd there.
ts
// vite.config.ts (root, vite-plus)
import { defineConfig } from 'vite-plus'
export default defineConfig({
lint: { options: { typeAware: true, typeCheck: true } },
test: { projects: ['apps/*'] }, // vp test runs every app's tests with its own vite.config
})Day to day โ
bash
pnpm dev # host on :7100 โ edit apps/esw-project, the host hot-updates
pnpm dev:project # esw-project on :1010, wearing the host's shell from ../esw-host
pnpm build # host bundle, remotes compiled in from the siblings
pnpm test # every apps/* vitest project
pnpm mono:prepare # regenerate every app's .mono/tsconfig.json (postinstall does this too)Develop and build through the host โ that is the artefact that ships, and it is where a broken cross-app import shows up first. Run a remote alone to work on it in isolation; it reads the real host next door, so its shell is never stale.