IDE Navigation Between Projects — Declaration Maps¶
Why this change¶
In a monorepo where shared packages (@bricks-common/helpers, @bricks-common/api-communication, @bricks-common-front/helpers) are consumed as pre-built artifacts via tsup, IDEs like VS Code and Cursor resolve "Go to Definition" to the compiled .d.ts files inside dist/. This means developers land on auto-generated type stubs instead of the actual source code, making it hard to read implementations, set breakpoints, or quickly navigate across package boundaries.
TypeScript's declaration maps (declarationMap: true) solve this by emitting .d.ts.map files alongside declarations. These map each declaration back to its original .ts source, so "Go to Definition" jumps straight to the real source file.
However, tsup's built-in dts: true option bundles all declarations into a single rolled-up .d.ts file — which destroys the 1:1 mapping needed for declaration maps to work. The fix is to split the build into two steps: let tsup handle the JavaScript bundling, and let tsc handle type declarations with proper source mapping.
What changed¶
1. Split build: JS bundling (tsup) + type declarations (tsc)¶
Each affected package's build script was changed from a single tsup invocation to a two-step pipeline:
- "build": "tsup"
+ "build": "pnpm run build:js && pnpm run build:types",
+ "build:js": "tsup",
+ "build:types": "tsc -b tsconfig.build.json --force"
Note :
@bricks-common-front/helpersutilisetsc -p tsconfig.build.json(mode mono-projet, sans-bni--force). La formetsc -b … --forceci-dessus s'applique aux deux paquetsboth/(@bricks-common/helperset@bricks-common/api-communication).
build:js— tsup bundles the JavaScript output (ESM + CJS) as before, but withdts: falseso it no longer emits declarations.build:types—tscemits declarations (.d.ts) and declaration maps (.d.ts.map) preserving the per-file structure that IDEs need.
2. tsup: disabled built-in declaration generation¶
In each tsup.config.ts:
tsup's dts: true rolls up all declarations into a single file, which breaks declaration map source links. Disabling it delegates declaration emit to tsc.
3. Réglages d'émission des déclarations (dans tsconfig.build.json)¶
Les réglages requis pour que tsc émette des declaration maps propres vivent dans le tsconfig.build.json de chaque paquet (voir section 4), pas dans tsconfig.json. Pour les deux paquets both/, tsconfig.json reste un fichier de pures références (files: [], include: [], references: [...]) ; pour @bricks-common-front/helpers, tsconfig.json conserve noEmit: true.
"noEmit": false,
"declarationMap": true,
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src",
"tsBuildInfoFile": "./node_modules/.cache/tsconfig.build.tsbuildinfo",
| Option | Purpose |
|---|---|
declarationMap: true |
Emits .d.ts.map files that map declarations back to source .ts files. |
emitDeclarationOnly: true |
Only emits .d.ts and .d.ts.map — no JS (tsup handles that). |
outDir / rootDir |
Controls where declarations land and preserves the directory structure in dist/. |
tsBuildInfoFile |
Stores incremental build info inside node_modules/.cache/ to keep the working tree clean. |
4. tsconfig.build.json: dedicated config for type builds¶
A new tsconfig.build.json was added to each package. Il porte les réglages d'émission des déclarations et exclut les fichiers de test du résultat. Les deux paquets both/ étendent tsconfig.base.json (quatre niveaux plus haut) ; seul @bricks-common-front/helpers étend ./tsconfig.json :
{
"extends": "../../../../tsconfig.base.json", // front/helpers étend "./tsconfig.json"
"compilerOptions": {
"noEmit": false,
"declarationMap": true,
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": "./src",
"tsBuildInfoFile": "./node_modules/.cache/tsconfig.build.tsbuildinfo"
},
"include": ["src/**/*"],
"exclude": ["dist", "node_modules", "**/*.test.ts", "**/*.spec.ts", "**/__test__/**", "**/__tests__/**"]
}
This prevents test files and mocks from leaking into the published type declarations while keeping the base tsconfig.json usable for type-checking and IDE support across all files (including tests).
5. TypeScript project references¶
api-communication/tsconfig.build.json declares a reference to helpers:
This tells tsc -b to build helpers first when building api-communication, respecting the dependency order (api-communication depends on helpers). It also enables cross-project "Go to Definition" navigation.
Packages affected¶
| Package | Path |
|---|---|
@bricks-common/helpers |
projects/common/both/helpers |
@bricks-common/api-communication |
projects/common/both/api-communication |
@bricks-common-front/helpers |
projects/common/front/helpers |
Impact on the monorepo¶
For developers¶
- "Go to Definition" now lands on real source code instead of compiled
.d.tsstubs — across all three shared packages. - No workflow change required:
pnpm buildcontinues to work as before; the split is internal to each package's build script. - Incremental builds:
tsc -bwithcomposite: trueuses.tsbuildinfofiles, making repeated type builds faster.
For CI / builds¶
- Build time may increase marginally because type declarations are now a separate
tscstep rather than inline tsup. In practice this is offset by incremental caching (tsBuildInfoFile). - The
dist/output of each package now contains per-file.d.ts+.d.ts.mappairs instead of a single rolled-upindex.d.ts. Consumers that reference"types": "./dist/index.d.ts"inpackage.jsonare unaffected becausetscstill emits anindex.d.tsentry point.
For future shared packages¶
When creating a new shared package in projects/common/, follow the same pattern:
- Set
dts: falseintsup.config.ts. - Create a
tsconfig.build.json(étendanttsconfig.base.jsonpour un paquetboth/, ou./tsconfig.jsonpour un paquetfront/) avecdeclarationMap,emitDeclarationOnly,outDir,rootDir,tsBuildInfoFileet qui exclut les fichiers de test. - Split the
buildscript intobuild:js(tsup) andbuild:types(tsc -b tsconfig.build.json --forcepour un paquetboth/,tsc -p tsconfig.build.jsonpour un paquetfront/). - If the package depends on another shared package, add a
referencesentry intsconfig.build.json.