Skip to content

Commit

Permalink
Apply suggestions from code review
Browse files Browse the repository at this point in the history
Co-authored-by: James Henry <[email protected]>
  • Loading branch information
juristr and JamesHenry authored Jan 23, 2025
1 parent 2ef1bb2 commit e9dd93c
Showing 1 changed file with 9 additions and 9 deletions.
18 changes: 9 additions & 9 deletions docs/blog/2025-01-20-linking-ts-in-monorepos.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors: [Juri Strumpflohner]
tags: []
---

Managing TypeScript packages in a monorepo comes with unique challenges. As your monorepo grow, so does the complexity of structuring and resolving dependencies between packages. From using simple relative imports to leveraging TypeScript path aliases, project references, and leveraging the package manager's workspaces feature: developers have a variety of strategies at their disposal. But which one is the right fit for your needs?
Managing TypeScript packages in a monorepo presents unique challenges. As your monorepo grows, so does the complexity of structuring and resolving dependencies between packages. From using simple relative imports to taking advantage of TypeScript path aliases, project references, and your package managers workspaces feature, developers have a variety of strategies at their disposal. But which approach is the best fit for you?

{% toc /%}

Expand All @@ -22,7 +22,7 @@ import { something } from '@tsmono/mypackage';
To have this work we need to be able to resolve the `@tsmono/mypackage` import to the actual file path. This needs to happen during:

- **Build:** This includes type checking and compilation/transpilation.
- **Execution:** This is when the application runs.
- **Runtime:** This is when the application runs in the browser/on the server.

In this article we'll mostly **focus on the building part, in particular type checking**. In real world applications you'll most often have some sort of bundler in the pipeline where `tsc` is used for type checking and the actual compilation part is being taken care of by the bundler (e.g. esbuild, Rspack, or Vite).

Expand Down Expand Up @@ -312,7 +312,7 @@ Imports remain the same, relying on TypeScript path aliases to resolve dependenc
**Modularity:**
Project references create stronger boundaries by treating each package as an independent TypeScript program. This enforces better isolation and ensures dependencies are type-checked at the package level.

**Performance :**
**Performance:**
This approach introduces incremental builds, where only modified packages are recompiled. TypeScript generates `.tsbuildinfo` files to track changes, reducing memory usage and speeding up type checking and compilation. This is particularly beneficial for large workspaces or CI pipelines.

From a TypeScript program structure we now don't have a single TypeScript program, but multiple ones.
Expand Down Expand Up @@ -399,9 +399,9 @@ This approach **eliminates the need for TypeScript path aliases for module resol
}
```

Instead, the package manager's workspaces feature makes sure to link the packages properly s.t. they can be resolved correctly at build and runtime. This doesn't have any impact on our TypeScript project references setup which cares about type checking and resolves dependencies via the `references` property.
Instead, the package manager's workspaces feature makes sure to link the packages properly such that they can be resolved correctly at build and runtime. This doesn't have any impact on our TypeScript project references setup which cares about type checking and resolves dependencies via the `references` property.

> Note, setting up package resolving with workspaces is the generally recommended approach. More on that later.
> Note, setting up package resolution with workspaces is the generally recommended approach. More on that later.
In an NPM/Yarn/PNPM workspace packages tend to be more self-contained. As such it is common to have the output directly in a `dist` folder within the package itself. We also adjust the `baseUrl` to be at the package root.

Expand Down Expand Up @@ -607,9 +607,9 @@ Here are some thoughts on which approach to use.
TypeScript path aliases have been a reliable way to manage package resolution, particularly before package managers introduced the workspaces feature. They're straightforward to set up, requiring only a global `tsconfig.json` without additional. However, there are limitations to consider as they require additional bundling support/alias resolvers at runtime and might come with some performance degradation in large workspaces.

{% callout type="deepdive" title="Isn't Nx using TS Path Aliases?" %}
Yes and no. Nx has been around before package managers introduced workspaces. As a result, the default setup in Nx traditionally leveraged a root-level `tsconfig.base.json` containing path aliases to link packages within the monorepo.
Yes and no. Nx has been around since before package managers introduced workspaces. As a result, the default setup in Nx traditionally leveraged a root-level `tsconfig.base.json` containing path aliases to link packages within the monorepo.

That said, Nx can also be used in combination with the NPM/Yarn/PNPM/Bun workspaces, as [shown here](/recipes/adopting-nx/adding-to-monorepo). This led to two distinct setups for monorepos with Nx: one using TypeScript path aliases and the other leveraging workspaces. To address the confusion this created, the Nx team has spent the last year enhancing Nx to unify these approaches. The goal is to align with "the platform" by adopting and promoting the workspaces, while updating Nx plugins to fully support it, preserving the developer experience (DX) benefits Nx users have come to love.
That said, Nx can also be used in combination with NPM/Yarn/PNPM/Bun workspaces, as [shown here](/recipes/adopting-nx/adding-to-monorepo). This led to two distinct setups for monorepos with Nx: one using TypeScript path aliases and the other leveraging workspaces. To address the confusion this created, the Nx team has spent the last year enhancing Nx to unify these approaches. The goal is to align with "the platform" by adopting and promoting package manager workspaces, while updating Nx plugins to fully support it, preserving the developer experience (DX) benefits Nx users have come to love.

If you're currently using the TypeScript path aliases approach, there's no need to worry. The Nx team is working on comprehensive documentation and semi-automated tools to help with migration. Additionally, it's possible to migrate manually and even incrementally, allowing you to adopt the workspaces at your own pace.
{% /callout %}
Expand All @@ -618,7 +618,7 @@ If you're currently using the TypeScript path aliases approach, there's no need

With widespread support in modern package managers (NPM, PNPM, Yarn, Bun), the workspaces feature has become the preferred method for managing package resolution. It aligns closely with the Node.js platform, leveraging native package resolution mechanisms that also work at runtime. This eliminates the portability issues inherent to TypeScript path aliases.

When combined with **TypeScript project references**, this method becomes even more powerful. Workspaces handles package linking s.t. Node can resolve them properly, while TypeScript project references optimize type-checking and enable incremental builds (for TypeScript). Together, they improve performance, reduce memory usage, and simplify dependency management in larger workspaces. This combination is the recommended way to structure and manage TypeScript packages in a monorepo.
When combined with **TypeScript project references**, this method becomes even more powerful. Workspaces handles package linking such that Node can resolve them properly, while TypeScript project references optimize type-checking and enable incremental builds (for TypeScript). Together, they improve performance, reduce memory usage, and simplify dependency management in larger workspaces. This combination is the recommended way to structure and manage TypeScript packages in a monorepo.

**To Prebuild or Not to Prebuild?**

Expand Down Expand Up @@ -647,7 +647,7 @@ If you want to try these approaches, check out the companion GitHub repository a
npx create-nx-workspace mymonorepo --workspaces
```

> Note the `--workspaces` is a temporary flag to instruct Nx to generate a workspaces based monorepo setup.
> Note `--workspaces` is a temporary flag to instruct Nx to generate a workspaces based monorepo setup.
**TODO LINK TO DOCS**

Expand Down

0 comments on commit e9dd93c

Please sign in to comment.