[Typescript] TypeScript Project References

Consider this package.json file:

{
  "name": "exercise",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "run-p dev:*",
    "dev:client": "tsc --project ./src/client/tsconfig.json --watch",
    "dev:server": "tsc --project ./src/server/tsconfig.json --watch"
  }
}

There are scripts for running the client and server TypeScript configurations, and a dev script runs both of them in parallel.

This is a lot of plumbing to get TypeScript to work. We would need to do the same for build scripts and any other scripts that involve TypeScript.

A better way to organize this is by using TypeScript project references.

 

Solution 1 (code)

In this solution, we have a new tsconfig.json file that has references to src/client/tsconfig.json and src/server/tsconfig.json. Unfortunately, there's no way to use wildcards in the references, so you have to manually list each tsconfig.json:

{
  "references": [
    {
      "path": "./src/client/tsconfig.json"
    },
    {
      "path": "./src/server/tsconfig.json"
    }
  ],
  "files": []
}

Note that there is also an empty files array. This is because the tsconfig.json file in the root directory is not responsible for type checking any files. Instead, it serves as a reference tsconfig.json to run the client and server tsconfig.json files in a specific order.

Inside of the package.json file, the dev script uses the -b flag. This tells TypeScript to run in build mode, which means it runs all the project references as well. This allows us to type check the entire repo with a single command:

// package.json
{
  "name": "exercise",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "tsc -b --watch"
  }
}

Inside of the tsconfig.base.json file, we've added the composite: true property. This enables constraints, allowing a TypeScript project to be used with project references. In other words, it tells TypeScript that this is a child project and needs to be run with project references.

// tsconfig.base.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "esModuleInterop": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true,
    "isolatedModules": true,
    "composite": true
  },
}

When TypeScript runs in build mode, it emits tsconfig.tsbuildinfo files, which are large and should not be committed to your repository. These files cache the results of type checking, which makes subsequent checks much faster.

To ignore these files, you can add *.tsbuildinfo to your root .gitignore file.

This first solution is an example of how you can organize your TypeScript configurations using project references.

However, there are several tsconfig files present in different directories.

 

Solution 2 (Code)

In this solution, we move all the tsconfig files to the root directory. This makes it clear that the tsconfig.json file belongs to the entire project, not just a specific package:

tsconfig.json
tsconfig.base.json
tsconfig.client.json
tsconfig.server.json

Inside of the tsconfig.client.json file, we can use the extends keyword to inherit the compiler options from tsconfig.base.json. Then, we can specify the include paths for the client packages:

// tsconfig.client.json

{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "lib": [
      "ES2022",
      "DOM",
      "DOM.Iterable"
    ]
  },
  "include": [
    "src/client"
  ]
}

The tsconfig.server.json configuration is similar, but won't include the DOM-related libraries:

{
  "extends": "./tsconfig.base.json",
  "compilerOptions": {
    "lib": [
      "ES2022"
    ]
  },
  "include": [
    "src/server"
  ]
}

Both of the client and server tsconfig files are referenced by the tsconfig.json file in the root directory:

{
  "references": [
    {
      "path": "./tsconfig.client.json"
    },
    {
      "path": "./tsconfig.server.json"
    }
  ],
  "files": []
}

This solution also works, but it can feel like a bit much to have four tsconfig files in the root directory.

 

Solution 3 (Code)

In this solution, we create a .config folder in the project root.

Inside of the .config directory we'll add the tsconfig.base.json file along with the tsconfig.client.json and tsconfig.server.json files.

Then inside of the root directory of the project, the tsconfig.json file will reference the other configurations.

This solution is becoming a more common pattern for storing configuration files.

 

Wrapping Up

Project references are a great feature for configuration. They allow for efficient organization and speed up type checking by caching the results. Whether you keep your configurations in the root directory, each package, or a separate configuration folder, choose what makes the most sense for your project's structure and complexity.

posted @ 2024-09-04 14:41  Zhentiw  阅读(24)  评论(0)    收藏  举报