eduardweb.
TypeScriptAvansat#performance#typescript#monorepo#tsconfig

Cum configurezi tsconfig.json într-un monorepo fără să-ți moară laptopul

De Dan Ciobanu, 21 iul. 2026 · 9 vizualizări · 3 like-uri

Postat 21 iul. 2026
json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src",
    "composite": true,
    "incremental": true,
    "tsBuildInfoFile": "./dist/.tsbuildinfo"
  },
  "include": ["src/**/*"],
  "references": [
    { "path": "../shared" },
    { "path": "../core" }
  ]
}

Monorepo-urile sunt geniale până când proiectul crește și TypeScript începe să îți mănânce memoria RAM la fiecare build. Am pățit asta la un proiect cu 12 pachete interne, unde un simplu tsc --watch îmi bloca laptopul timp de două minute la fiecare salvare. Soluția nu e să pui mai mult RAM, ci să configurezi corect Project References și compilarea incrementală.

În acest ghid rapid îți arăt cum să treci de la un setup naiv bazat doar pe paths la unul profesional care folosește puterea compilării incrementale.

De ce paths singur e o capcană la scară mare

La început, toți facem greșeala asta. Definim paths în root-ul tsconfig.json ca să importăm ușor dintr-un pachet în altul. Pare simplu și elegant: "@monorepo/shared/*": ["packages/shared/*"].

Problema majoră? TypeScript tratează tot monorepo-ul ca pe un singur proiect uriaș. Când modifici o singură linie în pachetul shared, compiler-ul reanalizează absolut tot codul din celelalte 11 pachete, chiar dacă acestea nu sunt afectate direct. La peste 50k linii de cod, asta înseamnă timpi de așteptare uriași. În plus, editorul de cod (VS Code sau WebStorm) începe să aibă un lag insuportabil la autocompletion.

Salvarea: composite și references

Ca să rezolvăm problema de performanță, trebuie să spargem monorepo-ul în proiecte TypeScript independente care comunică prin tipuri pre-compilate (.d.ts). Aici intră în scenă flag-ul "composite": true.

Când activezi composite, îi spui compilatorului că acel pachet este o entitate de sine stătătoare. TypeScript va genera automat fișiere .tsbuildinfo și definiții de tipuri în folderul de build.

Trade-off-ul sincer? Devii complet responsabil de legăturile dintre pachete. Dacă pachetul api depinde de shared, trebuie să declari asta explicit în tsconfig.json-ul din api folosind proprietatea references. Da, e destul de enervant și redundant pentru că ai deja dependența declarată în package.json, dar este singurul mod în care compiler-ul știe să nu recompileze shared dacă acolo nu s-a schimbat nimic.

Configurația care chiar funcționează

Strategia mea preferată este să am un tsconfig.base.json în rădăcina proiectului, unde țin toate regulile stricte de tipare și setările comune (target, module resolution, strictețe).

Apoi, în fiecare pachet, extind acest fișier de bază și adaug specificul pachetului respectiv. Cel mai important este să folosim tsc --build (sau tsc -b) în loc de simplul tsc. Flag-ul -b este inteligent: știe să citească graficul de dependențe din references și compilează doar ce s-a schimbat, în ordinea corectă.

Folosind această abordare, pe proiectul menționat mai sus, timpul de build în pipeline-ul de CI a scăzut de la 3 minute la doar 22 de secunde. Pe local, re-compilarea în mod watch durează acum sub 2 secunde.

Voi cum gestionați asta în proiectele mari? Lăsați un tool ca Turborepo / Nx să se ocupe de cache și orchestrare, sau preferați să țineți legăturile strânse direct din configurarea TypeScript?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

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