Read the associated blog post for complete information.
In development, your TypeScript code should feel "alive". When you update your code in one file, the effects of that change should propogate to all files that import it.
This is true even for monorepos, where you may not be importing things from a file, but from a local package.
- import { Fish } from "../pkg-a/index";
+ import { Fish } from "pkg-a"
This repo contains a few strategies you can use to make your TypeScript monorepo feel more alive.
Each subdirectory contains a pnpm monorepo (pnpm-workspace.yaml
) with two packages, pkg-a
and pkg-b
. pkg-b
has a dependency on pkg-a
. Each package has a tsconfig.json
that extends a tsconfig.base.json
in the root of the monorepo.
The file structure looks something like this:
.
├── package.json
├── packages
│ ├── pkg-a
│ │ ├── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ └── pkg-b
│ ├── index.ts
│ ├── package.json
│ └── tsconfig.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── tsconfig.base.json
└── tsconfig.json
Let's break down the approaches. (Refer to the associated blog post for complete breakdowns.)
Use TypeScript project references to link packages together. This has a lot of downsides and doesn't play nice with node
or other tooling out of the box.
Use publishConfig
in package.json
to specify .ts
file in development and .js
file in production.
Configure compilerOptions.paths
in tsconfig.json
to override resolution for local package names.
Using tshy
's liveDev
mode to hard-link the .ts
source code directly into ./dist/esm
and ./dist/commonjs
directories. This lets VS Code discover your live TypeScript source code without any additional package.json
configuration.
Recommended User-defined conditional export in package.json#exports
plus customConditions
in tsconfig.json
To play around with a particular approach, clone this repo and navigate to the appropriate subdirectory.
$ gh repo clone colinhacks/live-typescript-monorepo
$ cd live-typescript-monorepo
$ cd <subdir> # tsconfig-paths, publishconfig, project-references, custom-conditions
Then run the following commands:
$ pnpm i # install
$ code . # open in VS Code
Once the project is open in VS Code, open packages/pkg-a/index.ts
and packages/pkg-b/index.ts
. When you change the definition of Fish
in pkg-a
, those changes should propagate immediately to pkg-b
without a build step.
Each subdirectory also contains a "test"
script that executes pkg-b/index.ts
. (This won't work in project-references
.) This should execute the latest .ts
files for both pkg-a
and pkg-b
! Make some changes and see the effects.
pnpm test
Happy monorepo hacking!