Skip to content

Commit

Permalink
(docs) Fix Node.js subpath import guidance.
Browse files Browse the repository at this point in the history
  • Loading branch information
anthonyshew committed Aug 26, 2024
1 parent 875fd08 commit 503c4de
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 39 deletions.
2 changes: 1 addition & 1 deletion docs/repo-docs/core-concepts/internal-packages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ There are a few important things to notice in this `package.json`:
#### Limitations and tradeoffs

- **Only applicable when consumers do transpiling**: This strategy can only be used when the package is going to be used in tooling that uses a bundler or natively understands TypeScript. The consumer's bundler is responsible for transpiling the TypeScript packages to JavaScript. If your builds or other usages of the package are not able to consume TypeScript, you will need to move to the [Compiled Packages](#compiled-packages) strategy.
- **No TypeScript `paths`**: A library that is being transpiled by its consumer cannot use the `compilerOptions.paths` configuration because TypeScript assumes that source code is being transpiled in the package where it is written. If you're using Typescript 5.4 or later, we recommend [using Node.js subpath imports](https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/#auto-import-support-for-subpath-imports).
- **No TypeScript `paths`**: A library that is being transpiled by its consumer cannot use the `compilerOptions.paths` configuration because TypeScript assumes that source code is being transpiled in the package where it is written. If you're using Typescript 5.4 or later, we recommend [using Node.js subpath imports](https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/#auto-import-support-for-subpath-imports). To learn how, visit [our TypeScript page](/repo/docs/guides/tools/typescript#use-nodejs-subpath-imports-instead-of-typescript-compiler-paths).
- **Turborepo cannot cache a build for a Just-in-Time Package**: Because the package doesn't have its own `build` step, it can't be cached by Turborepo. This tradeoff may make sense for you if you want to keep configuration to a minimum and are okay with the build times for your applications.

### Compiled Packages
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -315,40 +315,7 @@ Using exports this way provides three major benefits:

#### `imports` (optional)

[The `imports` field](https://nodejs.org/api/packages.html#imports) gives you a way to create subpaths to other modules within your package. You can think of these like "shortcuts" to get to other modules within your package.

<Tabs items={["package.json", "add.ts", "multiply.ts"]}>
<Tab value="package.json">
```json title="./packages/ui/package.json"
{
"imports": {
"#*": "./*"
}
}
```
</Tab>
<Tab value="add.ts">
```ts title="./packages/math/src/add.ts"
export const add = (a: number, b: number) => a + b;
```
</Tab>

<Tab value="multiply.ts">
```ts title="./packages/math/src/multiply.ts"
import { add } from "#add";

export const multiply = (a: number, b: number) => {
let result = 0;
for (let i = 0; i < b; i++) {
result = add(result, a);
}
return result;
}
```
</Tab>
</Tabs>

This can be useful for concisely importing other modules within the package and can make refactors easier to manage.
[The `imports` field](https://nodejs.org/api/packages.html#imports) gives you a way to create subpaths to other modules within your package. You can think of these like "shortcuts" to write simpler import paths that are more resilient to refactors that move files. To learn how, visit [the TypeScript page](/repo/docs/guides/tools/typescript#use-nodejs-subpath-imports-instead-of-typescript-compiler-paths).

<Callout type="info">
You may be more familiar with TypeScript's `compilerOptions#paths` option, which accomplishes a similar goal. As of Typescript 5.4, TypeScript can infer subpaths from `imports`, making it a better option since you'll be working with Node.js conventions. For more information, visit [our Typescript guide](/repo/docs/guides/tools/typescript#use-nodejs-subpath-imports-instead-of-typescript-compiler-paths).
Expand Down
61 changes: 57 additions & 4 deletions docs/repo-docs/guides/tools/typescript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Learn how to use TypeScript in a monorepo.

import { Callout } from '#/components/callout';
import { File, Folder, Files } from '#/components/files';
import { PackageManagerTabs, Tab } from '#/components/tabs';
import { PackageManagerTabs, Tabs, Tab } from '#/components/tabs';
import { LinkToDocumentation } from '#/components/link-to-documentation';

TypeScript is an excellent tool in monorepos, allowing teams to safely add types to their JavaScript code. While there is some complexity to getting set up, this guide will walk you through the important parts of a TypeScript setup for most use cases.
Expand Down Expand Up @@ -221,11 +221,64 @@ For [Internal Packages](/repo/docs/core-concepts/internal-packages), we recommen

### Use Node.js subpath imports instead of TypeScript compiler `paths`

It's possible to create absolute imports in your packages using [the TypeScript compiler's `paths` option](https://www.typescriptlang.org/tsconfig#paths). However, [as of TypeScript 5.4](https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/#auto-import-support-for-subpath-imports), you can use [Node.js subpath imports](https://nodejs.org/api/packages.html#imports) instead.
It's possible to create absolute imports in your packages using [the TypeScript compiler's `paths` option](https://www.typescriptlang.org/tsconfig#paths), but these paths can cause failed compilation when using [Just-in-Time Packages](https://turbo.build/repo/docs/core-concepts/internal-packages#just-in-time-packages). [As of TypeScript 5.4](https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/#auto-import-support-for-subpath-imports), you can use [Node.js subpath imports](https://nodejs.org/api/packages.html#imports) instead for a more robust solution.

Additionally, Node.js subpath imports are usable in [Just-in-Time Packages](/repo/docs/core-concepts/internal-packages#just-in-time-packages) while TypeScript's `compilerOptions#paths` are not.
#### Just-in-Time packages

This strategy brings your Node.js and TypeScript configurations closer together, making your project's configuration simpler.
In [Just-in-Time packages](https://turbo.build/repo/docs/core-concepts/internal-packages#just-in-time-packages), `imports` must target the source code in the package, since build outputs like `dist` won't be created.

<Tabs storageKey="ts-imports-jit" items={["package.json", "Source code"]}>
<Tab value="package.json">
```json title="./packages/ui/package.json"
{
"imports": {
"#*": "./src/*"
}
}
```
</Tab>
<Tab value="Source code">
```tsx title="./packages/ui/button.tsx"
import { MY_STRING } from "#utils.ts" // Uses .ts extension // [!code highlight]
export const Button = () => {
return (
<button>{MY_STRING}</button>
)
}
```
</Tab>

</Tabs>

#### Compiled packages

In [Compiled packages](https://turbo.build/repo/docs/core-concepts/internal-packages#compiled-packages), `imports` target the built ouptuts for the package.

<Tabs storageKey="ts-imports-compiled" items={["package.json", "Source code"]}>
<Tab value="package.json">
```json title="./packages/ui/package.json"
{
"imports": {
"#*": "./dist/*"
}
}
```
</Tab>

<Tab value="Source code">
```tsx title="./packages/ui/button.tsx"
import { MY_STRING } from "#utils.js" // Uses .js extension // [!code highlight]
export const Button = () => {
return (
<button>{MY_STRING}</button>
)
}
```
</Tab>

</Tabs>

### You likely don't need a `tsconfig.json` file in the root of your project

Expand Down

0 comments on commit 503c4de

Please sign in to comment.