Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issues building a TypeScript monorepo project

I have a fairly simple mono repo. It is available on GitLab here. This uses yarn workspaces, TypeScript, Jest, ts-jest and ESLint with eslint-plugin-import.

I am trying to properly build the project packages using TypeScript. Previously I was just publishing the TypeScript files alongside their JavaScript code in the same directory.

My attempt to build the project is available in a GitLab merge request here

Now the repository follows the following layout:

 |- example/
 |   |- index.ts
 |   |- package.json
 |   `- tsconfig.json
 |- packages/
 |   |- koas-core/
 |   |   |- src/
 |   |   |   `- index.ts
 |   |   |- package.json
 |   |   `- tsconfig.json
 |   |- koas-status-code/
 |   |   |- src/
 |   |   |   `- index.ts
 |   |   |- package.json
 |   |   `- tsconfig.json
 |   `- more similar workspaces…
 |- package.json
 |- tsconfig.json
 `- more configuration files…

Some packages depend on each other. I have managed to get Jest tests and eslint-plugin-import to work with this setup, but I’m having trouble building the project.

The root tsconfig.json looks like this:

{
  "compilerOptions": {
    "baseUrl": ".",
    "composite": true,
    "declaration": true,
    "module": "commonjs",
    "noEmit": true,
    "resolveJsonModule": true,
    "target": "esnext",
    "paths": {
      "koas-*": ["packages/koas-*/src"]
    }
  },
  "exclude": ["**/*.test.ts"]
}

The workspace tsconfig.json files look like this:

{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "lib"
  }
}

Each workspace has a prepack script defined in package.json that looks like this:

{
  "scripts": {
    "prepack": "tsc --noEmit false"
  }
}

The main field refers to lib.

If I run yarn workspace koas-status-code prepack, I get the following error:

$ tsc --noEmit false
error TS6059: File 'koas/packages/koas-core/src/SchemaValidationError.ts' is not under 'rootDir' 'koas/packages/koas-status-code'. 'rootDir' is expected to contain all source files.

error TS6059: File 'koas/packages/koas-core/src/SchemaValidationError.ts' is not under 'rootDir' 'koas/packages/koas-status-code/src'. 'rootDir' is expected to contain all source files.

error TS6059: File 'koas/packages/koas-core/src/createDefaultValidator.ts' is not under 'rootDir' 'koas/packages/koas-status-code'. 'rootDir' is expected to contain all source files.

error TS6059: File 'koas/packages/koas-core/src/createDefaultValidator.ts' is not under 'rootDir' 'koas/packages/koas-status-code/src'. 'rootDir' is expected to contain all source files.

error TS6059: File 'koas/packages/koas-core/src/createMatcher.ts' is not under 'rootDir' 'koas/packages/koas-status-code'. 'rootDir' is expected to contain all source files.

error TS6059: File 'koas/packages/koas-core/src/createMatcher.ts' is not under 'rootDir' 'koas/packages/koas-status-code/src'. 'rootDir' is expected to contain all source files.

error TS6059: File 'koas/packages/koas-core/src/index.ts' is not under 'rootDir' 'koas/packages/koas-status-code'. 'rootDir' is expected to contain all source files.

error TS6059: File 'koas/packages/koas-core/src/index.ts' is not under 'rootDir' 'koas/packages/koas-status-code/src'. 'rootDir' is expected to contain all source files.

error TS6307: File 'koas/packages/koas-core/src/SchemaValidationError.ts' is not listed within the file list of project 'koas/packages/koas-status-code/tsconfig.json'. Projects must list all files or use an 'include' pattern.

error TS6307: File 'koas/packages/koas-core/src/createDefaultValidator.ts' is not listed within the file list of project 'koas/packages/koas-status-code/tsconfig.json'. Projects must list all files or use an 'include' pattern.

error TS6307: File 'koas/packages/koas-core/src/createMatcher.ts' is not listed within the file list of project 'koas/packages/koas-status-code/tsconfig.json'. Projects must list all files or use an 'include' pattern.

error TS6307: File 'koas/packages/koas-core/src/index.ts' is not listed within the file list of project 'koas/packages/koas-status-code/tsconfig.json'. Projects must list all files or use an 'include' pattern.


Found 12 errors.

I have also tried this tsconfig.json for koas-status-code:

{
  "extends": "../../tsconfig.json",
  "include": ["src"],
  "references": [{ "path": "../koas-core" }],
  "compilerOptions": {
    "outDir": "lib"
  }
}

This builds the workspace, but still gives me the following error:

$ tsc --noEmit false
src/index.ts:1:23 - error TS6305: Output file '/home/remco/Projects/koas/packages/koas-core/lib/src/index.d.ts' has not been built from source file '/home/remco/Projects/koas/packages/koas-core/src/index.ts'.

1 import * as Koas from 'koas-core';
                        ~~~~~~~~~~~


Found 1 error.

How do I fix this?

like image 678
Remco Haszing Avatar asked Oct 24 '19 13:10

Remco Haszing


1 Answers

I have found a solution for this problem based on https://github.com/NiGhTTraX/lerna-ts.

The project now contains a file named tsconfig.build.ts in the project root. This files basically just specifies the compiler options and that test and build files should be excluded from the build process.

{
  "compilerOptions": {
    "declaration": true,
    "module": "commonjs",
    "resolveJsonModule": true,
    "target": "esnext"
  },
  "exclude": ["**/*.test.ts", "**/lib"]
}

Another file in the root is tsconfig.json. This file is used for type checking outside of the build process, e.g. by Jest and VSCode. This file extends the build configuration. It includes tests by overriding the extended exclude configuration. It also contains noEmit: true, because processes using TypeScript while developing shouldn’t emit anything. Also it contains the baseUrl and paths compiler options that are needed to resolve the TypeScript source files at runtime. This is because the main field in the packages’ package.json files refer the lib, which contains the output files.

{
  "extends": "./tsconfig.build.json",
  "compilerOptions": {
    "baseUrl": ".",
    "noEmit": true,
    "paths": {
      "koas-*": ["packages/koas-*/src"]
    }
  },
  "exclude": ["**/lib"]
}

Each workspace contains a tsconfig.build.json file. This is needed, because it requires the src and outDir options need to be relative to the tsconfig file. That is used to build the project. It is important this file is not named tsconfig.json.

{
  "extends": "../../tsconfig.build.json",
  "include": ["src"],
  "compilerOptions": {
    "outDir": "lib"
  }
}

Each workspace also contains a tsconfig.json. This can be used to override compiler options for type checking, for example if one repository would use the dom typings. This could be omitted.

{
  "extends": "../../tsconfig.json"
}

Each workspace has the following scripts section in package.json. This causes the TypeScript to be compiled when the package is built.

  // …
  "scripts": {
    "prepack": "tsc --project tsconfig.build.json"
  }

There are two CI jobs for typechecking. One runs tsc to make sure type checking still works in tools using these types in development, the other makes sure building the packages doesn’t break.

tsc:
  script:
    - yarn --frozen-lockfile
    - yarn workspaces run tsc

pack:
  script:
    - yarn --frozen-lockfile
    - yarn workspaces run pack
    - find packages -name '*.tgz' -exec mv {} ./ +
  artifacts:
    name: packages
    paths:
      - '*.tgz'
like image 132
Remco Haszing Avatar answered Sep 28 '22 17:09

Remco Haszing