Appearance
CLI & TypeScript โ
The mono commands treat a path app exactly like every other consumer: mono sync has nothing to clone for it, mono env loads its .env.<mode> like a clone's, and mono prepare writes its alias into .mono/tsconfig.json โ pointing outside the project, which is the one thing TypeScript needs a word about.
mono sync โ
Every app is looked at before any network call:
==> Check esw-reports (EJI-ICT/esw-reports@mono) โ a url-only app: cloned as always
๐ esw-master: linked to ../esw-master โ nothing to clone.
๐ esw-project: linked to ../esw-project โ nothing to clone.
===== Summary =====
โ
Success (1):
โข esw-reports (EJI-ICT/esw-reports@mono @ 3c5d768) via git
โ Failed (0):
๐ Linked (2):
โข esw-master (../esw-master, read in place)
โข esw-project (../esw-project, read in place)- A
pathwhose directory is absent and has aurlis synced from GitHub with a warning (โ ๏ธ esw-project: path '../esw-project' not found (looked in โฆ) โ syncing from GitHub instead.). This is the lifted-out-of-the-lith case. - A
pathwhose directory is absent and has nourlfails that app (exit code 1) โ there is nothing to fall back to. - An entry with neither
urlnorpathis rejected while parsingapps[]. - Pruning is unchanged:
.mono/apps/<dir>not named inapps[]is removed; apathapp's name still protects a stale clone of it, which is shadowed and reported, never deleted. Onlyurlapps contribute commit-cache and access-cache keys.
mono env โ
mono env -e .env.dev -- vite loads the root .env.dev, then every federated app's .env.dev โ clones and path siblings, the same list every other command sees:
[mono-env] Loaded root env: .env.dev
[mono-env] Loaded app:esw-master env: ../esw-master/.env.dev
[mono-env] Loaded app:esw-project env: ../esw-project/.env.dev
[mono-env] Apps: esw-master, esw-project-a <name> picks one app by name whether it is a clone or a sibling; MONO_APP_DIR is that app's real directory. (The resolver lives in the built config-node.js; run straight from the repo's bin/, the script falls back to listing .mono/apps as it always did.)
mono prepare โ
.mono/tsconfig.json maps every alias to the directory Vite reads, so for a sibling it now points outside the project:
json
{
"compilerOptions": {
"paths": {
"@esw-host/*": ["../src/*"],
"@esw-host-root/*": ["../*"],
"@esw-project/*": ["../../esw-project/src/*"],
"@esw-project-root/*": ["../../esw-project/*"]
}
}
}rootDir โ
TypeScript refuses a path mapping that escapes compilerOptions.rootDir ("File โฆ is not under 'rootDir'") for every importer of that alias. mono prepare will not edit the option โ only the project knows whether "." was deliberate โ it warns once and lists the keys:
[mono] tsconfig.json sets rootDir "." but @esw-project/*, @esw-project-root/* map outside
the project (apps[].path siblings). Remove rootDir, or set it to the folder that contains
every sibling (e.g. "../").Recommendation: drop rootDir. A Vite / vue-tsc project has noEmit: true, so rootDir buys nothing. If a project insists on one, "../" (the apps/ folder) is the value that contains every sibling. runMonoPrepare() returns the keys as outsideProject for tooling.
Each sibling runs its own prepare โ
mono prepare wires the generated tsconfig into clones only (.mono/apps/<name>/tsconfig.json gains extends: ["../../tsconfig.json"]). It never writes into a path sibling's tsconfig.json: that is someone's real repository, the edit would dirty their tree with a path only valid on this machine, and the host's paths would then resolve inside a project with its own rootDir.
Instead each sibling carries its own mono.config.ts and runs its own mono prepare โ its postinstall already does โ which writes the same map from its point of view (@esw-host/* โ ../../esw-host/src/* in apps/esw-project/.mono/tsconfig.json). A root pnpm install runs every workspace package's postinstall, so the whole lith is prepared in one go.
If a sibling has not run it yet, its tsconfig.json still extends a ./.mono/tsconfig.json that is missing โ Vite's esbuild plugin then fails that sibling's SFCs with "Tsconfig not found". mono prepare in the host detects that and says so:
[mono] esw-project: tsconfig.json extends ./.mono/tsconfig.json but the file is missing โ run `mono prepare` in that app.defineProps<ImportedType>() across siblings โ
@vue/compiler-sfc resolves the type-only imports in defineProps<T>() through the nearest tsconfig.json's paths โ for apps/esw-project/src/x.vue that is esw-project's own tsconfig, never the host's, and Vite's resolve.alias is invisible to it. So a sibling's SFC importing @esw-host/types/โฆ works when:
- the sibling declares
esw-hostin its ownapps[](it does โ remotes list the host back), and - the sibling has run
mono prepare(see above).
tsconfig.build.json โ
A build tsconfig that redefines paths (to add @/*, say) replaces the whole inherited map, so its mono entries have to name the siblings too:
json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"paths": {
"@/*": ["./src/*"],
"@esw-project/*": ["../esw-project/src/*"],
"@esw-project-root/*": ["../esw-project/*"]
}
}
}