eduardweb.
TypeScriptAvansat#architecture#performance#typescript#monorepo

Cum să configurezi tsconfig într-un monorepo fără să-ți distrugi CI-ul

De Cosmin Rotaru, 26 iul. 2026 · 10 vizualizări · 2 like-uri

Postat 26 iul. 2026
json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "composite": true,
    "incremental": true,
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

Am văzut prea multe monorepo-uri unde tsc durează peste 3 minute doar ca să valideze tipurile. O să vă arăt configurarea exactă de tsconfig pe care am folosit-o pe un proiect cu 12 pachete interne, unde am scăzut timpul de CI la typecheck de la 3 minute la sub 14 secunde.

Greșeala clasică: doar paths în root

Când începi un monorepo, prima tentație e să pui în tsconfig.base.json din root un alias de genul "@app/ui": ["packages/ui/src"]. Vizual în VS Code arată superb. Auto-importul funcționează, nu ai erori cu roșu, toată lumea e fericită.

Problema apare când rulezi build-ul. Fără Project References, TypeScript tratează tot monorepo-ul ca pe un singur proiect gigant. Când schimbi un singur fișier din pachetul de utils, compiler-ul reanalizează absolut fiecare fișier din aplicație, ignorând complet faptul că pachetele tale sunt separate în packages/*. Am pățit asta pe un sistem cu 8k useri activi: aveam 12 module mici, dar la orice Push în Git, pipeline-ul de CI bloca coada câteva minute bunicele.

Magic trio: composite, declarationMap și references

Soluția nativă din TypeScript se numește Project References. Ca să meargă corect, trebuie îndeplinite trei condiții în tsconfig.json-ul fiecărui pachet intern:

  1. "composite": true — Îi spune compilatorului că acest folder este un proiect de sine stătător. TS va genera fișiere .tsbuildinfo și .d.ts pentru el.
  2. "declarationMap": true — Esențial pentru DX. Când dai Go to Definition din aplicația web către o componentă din pachetul UI, te duce direct în fișierul sursă .ts, nu în .d.ts-ul generat.
  3. Definirea explicită a dependențelor în secțiunea references din pachetul care le consumă.
// packages/web/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist"
  },
  "references": [
    { "path": "../ui" },
    { "path": "../utils" }
  ]
}

Trade-off-ul de care nu-ți spune nimeni

Project References oferă un boost uriaș de performanță datorită build-urilor incrementale, dar vine la pachet cu o rigoare draconică.

Direct din experiență: dacă pachetul web importă ceva din utils, dar uiți să adaugi { "path": "../utils" } în array-ul de references, compilatorul îți va da eroare pe CI, chiar dacă VS Code s-ar putea să nu țipe imediat dacă ai alias-ul în paths. În plus, trebuie să rulezi comanda tsc --build (sau tsc -b), nu simplul tsc. Flag-ul -b știe să citească graful de dependențe și să compileze pachetele în ordinea corectă, ignorându-le pe cele care nu s-au modificat.

Un alt detaliu: composite: true te obligă să activezi declaration: true și să ai reguli foarte stricte de rootDir. Dacă ai fișiere rătăcite prin afara folderului src, build-ul va eșua instant.

Cum arată fluxul optim

În root păstrezi un tsconfig.base.json cu toate opțiunile de bază (strictness, moduleResolution, target). În fiecare pachet pui un tsconfig.json scurt care extinde baza, activează composite și își declară referințele.

La final, în root pui un tsconfig.json master care doar referențiază toate pachetele. Astfel, când rulezi tsc -b din root, TypeScript verifică tot graful în câteva secunde.

Voi ce folosiți pentru gestionarea monorepo-urilor pe TS? Mergeți pe tsc -b nativ sau lăsați instrumente ca Nx/Turborepo să orchestreze totul?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.