azu / monorepo-utils

A collection of utilities for monorepo/lerna. Tools for TypeScript project references etc..
164 stars 10 forks source link

`workspaces-to-typescript-project-references` does not handle references to config files correctly #83

Open suin opened 5 months ago

suin commented 5 months ago

The path property of each reference in a TypeScript project can point to a directory containing a tsconfig.json file or directly to the config file itself (which may have any name).

The path property of each reference can point to a directory containing a tsconfig.json file, or to the config file itself (which may have any name). -- TypeScript Handbook

I am reporting an issue where workspaces-to-typescript-project-references does not work as expected in this context.

Consider a monorepo with the following structure:

.
├── package.json
└── packages
    ├── a
    │   ├── package.json
    │   ├── tsconfig.json
    │   └── tsconfig.types.json
    ├── b
    │   ├── package.json
    │   ├── tsconfig.json
    │   └── tsconfig.types.json
    └── c
        ├── package.json
        ├── tsconfig.json
        └── tsconfig.types.json

Focusing on the a package:

packages/a/tsconfig.json:

{
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "lib"
  },
  "references": [
    {
      "path": "./tsconfig.types.json"
    }
  ]
}

This configuration file emits JavaScript code to the lib directory.

packages/a/tsconfig.types.json:

{
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "types",
    "composite": true,
    "emitDeclarationOnly": true
  }
}

This configuration file emits TypeScript declaration files to the types directory.

The relationship between these two files is expressed using project references:

graph LR;
tsconfig.json -->|references| tsconfig.types.json;

Therefore, running tsc -b in the a package should compile both tsconfig.json and the referenced tsconfig.types.json, emitting files to the lib and types directories, respectively.

While specifying the config file in the path property may not be common, tools like moonrepo consider this approach as a valid use case, as described here.

For the entire monorepo, the relationship between the config files is as follows:

graph TB;
subgraph /packages/a
a/tsconfig.json("tsconfig.json")
a/tsconfig.types.json("tsconfig.types.json")
end
subgraph /packages/b
b/tsconfig.json("tsconfig.json")
b/tsconfig.types.json("tsconfig.types.json")
end
subgraph /packages/c
c/tsconfig.json("tsconfig.json")
c/tsconfig.types.json("tsconfig.types.json")
end
a/tsconfig.json -->|references| a/tsconfig.types.json;
b/tsconfig.json -->|references| /packages/a;
b/tsconfig.json -->|references| b/tsconfig.types.json;
c/tsconfig.json -->|references| /packages/a;
c/tsconfig.json -->|references| /packages/b;
c/tsconfig.json -->|references| c/tsconfig.types.json;

For the complete code, please refer to this repository: https://github.com/suinplayground/monorepo-utils-1/tree/master/packages/%40monorepo-utils/workspaces-to-typescript-project-references/test/fixtures/yarn-workspaces-pointing-to-config-file

In this monorepo structure, I found that using workspaces-to-typescript-project-references results in references to tsconfig.types.json being removed:

 Error: [packages/a] Expected values to be strictly deep-equal:
 + actual - expected
+ [
+   {
+     path: './tsconfig.types.json'
+   }
+ ]

 Error: [packages/b] Expected values to be strictly deep-equal:
 + actual - expected
    [
    {
        path: '../a'
+   },
+   {
+     path: './tsconfig.types.json'
    }
    ]

 Error: [packages/c] Expected values to be strictly deep-equal:
 + actual - expected ... Lines skipped
    [
    {
...
    {
        path: '../b'
+   },
+   {
+     path: './tsconfig.types.json'
    }

 workspaces-to-typescript-project-references found 3 errors.
 Please update your tsconfig.json via following command.
 $ workspaces-to-typescript-project-references

See the full error log here: https://github.com/suinplayground/monorepo-utils-1/actions/runs/9474724661/job/26104870429#step:6:60

The expected outcome is that references to tsconfig.types.json within the same package remain intact, while only inter-package references are managed.

I would appreciate it if this issue could be resolved. Thank you for your attention to this matter.

azu commented 5 months ago
"path": "./tsconfig.types.json"

Probably, this pattern (path to tsconfig.json directory) is unexpected. I believe the current implementation assumes that a directory is specified.

https://github.com/azu/monorepo-utils/blob/7d1996763e7986e97f6cde22158e3b8f11c15a5b/packages/%40monorepo-utils/workspaces-to-typescript-project-references/src/index.ts#L255-L257

If path: “. /tsconfig.type.json" is allowed, I think an implementation change is needed to fix this problem.

mjpowersjr commented 2 months ago

I ran into this issue as well, when using vite to create a new package. Vite's tsconfig structure looks like:

...

"references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.node.json" }
  ],