Skip to content

ADR-001: TypeScript Source-Direct — No Build Step

Date: 2026-02-27 Authors: Jean-Francois Meyers Scope: All @granit/* packages

The @granit/* packages are consumed exclusively by Vite-based applications. In local development, packages are linked via pnpm link: and resolved through Vite aliases. Vite transpiles TypeScript on-the-fly via esbuild.

Maintaining a build step (tsc, tsup, rollup) for each package would introduce:

  • An additional watch process during development
  • A propagation delay for modifications reaching applications
  • Configuration complexity (source maps, declaration files, dual CJS/ESM)
  • A risk of desynchronization between source and compiled artifacts

The @granit/* packages export their raw .ts source files directly via the exports field in package.json:

{
"exports": {
".": "./src/index.ts"
}
}

No dist/ directory is generated or committed. Consumer applications resolve imports via Vite aliases pointing to the sources.

A publishConfig with dist/ exports and a tsup build step is provided for npm publication to GitHub Packages.

Option 1: Source-direct with Vite transpilation (selected)

Section titled “Option 1: Source-direct with Vite transpilation (selected)”
  • Advantage: instant HMR, zero build configuration, direct source maps
  • Disadvantage: coupled to Vite (or any bundler capable of TypeScript transpilation)
  • Advantage: standard npm distribution, compatible with any consumer
  • Disadvantage: additional watch process per package, propagation delay, dual CJS/ESM complexity, source map indirection

Option 3: tsc —watch with project references

Section titled “Option 3: tsc —watch with project references”
  • Advantage: official TypeScript tooling, incremental compilation
  • Disadvantage: slow watch mode on large workspaces, declaration file management, no tree-shaking
CriterionSource-directtsup/rollup watchtsc —watch
HMR latencyInstant~1-3s per change~2-5s per change
Dev configurationNonePer-package configtsconfig references
Source mapsDirect to sourceThrough dist/ layerThrough dist/ layer
Refactoring supportFull (IDE resolves source)Partial (may resolve dist/)Good
CI type-checkpnpm tsc --noEmitpnpm tsc --noEmitpnpm tsc --build
npm publicationRequires tsup buildReadyReady
PackageRole
tsupBuild step for npm publication only (publishConfig)
esbuild (via Vite)On-the-fly TypeScript transpilation in development
  • Instant HMR: modifications in a package are reflected immediately in the application
  • Zero build configuration in development
  • Direct source maps to the original code (no intermediate layer)
  • Fluid refactoring: TypeScript tools (rename, find references) traverse packages seamlessly
  • Simplified CI: pnpm tsc --noEmit is sufficient for type checking
  • Coupled to Vite: consumer applications must use a bundler capable of TypeScript source transpilation
  • Publication: a build step is required before npm publication, creating two consumption modes (source-direct vs dist)
  • Compatibility: packages are not directly usable by a Node.js project without transpilation

This decision should be re-evaluated if:

  • A consumer application needs to use a bundler that cannot transpile TypeScript (unlikely)
  • The number of packages grows beyond a point where Vite’s on-the-fly transpilation becomes a performance bottleneck
  • TypeScript natively supports running .ts files without transpilation (Node.js --strip-types)