Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for multiple tsconfig.xxx.json per app/library #42

Open
Papooch opened this issue Oct 23, 2024 · 6 comments
Open

Support for multiple tsconfig.xxx.json per app/library #42

Papooch opened this issue Oct 23, 2024 · 6 comments

Comments

@Papooch
Copy link

Papooch commented Oct 23, 2024

I have a monorepo setup (pnpm workspaces), where each package has essentially three tsconfigs

  • tsconfig.build.json - for the build options
  • tsconfig.spec.json - for test-specific options (e.g. including test files)
  • tsconfig.json - which ties them together via references with the content:
{
    "extends": "../../tsconfig.base.json",
    "files": [],
    "include": [],
    "references": [
        {
            "path": "./tsconfig.build.json"
        },
        {
            "path": "./tsconfig.spec.json"
        }
    ]
}

Where tsconfig.base.json is the very root one.

When I run this script in the project, it removes those references completely, leaving me with this:

{
    "extends": "../../tsconfig.base.json",
    "files": [],
    "include": [],
+    "compilerOptions": {}
-    "references": [
-        {
-            "path": "./tsconfig.build.json"
-        },
-        {
-            "path": "./tsconfig.spec.json"
-        }
-    ]
}

which I don't want, because it breaks editor support.

I just want it to add references to libraries that this one depends on. Is there any way of achieving that?

@MKruschke
Copy link
Member

Hi @Papooch

could you please give me a better picture how your project is setup and also how you use the tool against it.

From what I read it is like that or? If not please correct it and add the execution command and/or the update-ts-reference.yml to your answer.

├── 📂 packages                                             
│   ├── 📂 package-a                               
│   │   ├── 📄 tsconfig.spec.json
│   │   ├── 📄 tsconfig.build.json
│   │   ├── 📦 package.json
│   ├── 📂 package-b                               
│   │   ├── 📄 tsconfig.spec.json
│   │   ├── 📄 tsconfig.build.json
│   │   ├── 📦 package.json
├ 📄 tsconfig.base.json
├ 📄 tsconfig.spec.json
├ 📄 tsconfig.build.json
├ 📄 tsconfig.json
├ 📦 package.json

@Papooch
Copy link
Author

Papooch commented Nov 18, 2024

Thank you for the reply, the structure looks almost like what you show, but with the exception that each lib has one tsconfig.json (that references the root one). that is referenced by spec and build

├── 📂 packages                                             
│   ├── 📂 package-a                               
│   │   ├── 📄 tsconfig.spec.json  // extends  ⬇️⬇️
│   │   ├── 📄 tsconfig.build.json // extends  ⬇️
│   │   ├── 📄 tsconfig.json       // extends "base", references "spec" and "build", possibly "package-b/tsconfig.json"
│   │   ├── 📦 package.json
│   ├── 📂 package-b                               
│   │   ├── 📄 tsconfig.spec.json  // extends ⬇️⬇️
│   │   ├── 📄 tsconfig.build.json // extends ⬇️
│   │   ├── 📄 tsconfig.json       //extends "base", references "spec" and "build",
│   │   ├── 📦 package.json
├ 📄 tsconfig.base.json  // extends/referencs nothing
├ 📄 tsconfig.json       // extends "base", references all root tsconfigs in packages (for editor support)
├ 📦 package.json

Basically the same setup as described here: https://moonrepo.dev/docs/guides/javascript/typescript-project-refs, but with a slightly different naming conventions

@MKruschke
Copy link
Member

When I understand correctly the approach this build config is also used for local development which in my eyes isn't necessary I even would say this an antipattern, because it abused project references to trigger a additional build step for the same package. In your case I assume it does two for spec and build under the hood.

@Papooch
Copy link
Author

Papooch commented Nov 20, 2024

The build tsconfig (sometimes called tsconfig.app.ts or tsconfig.lib.ts) is generally for files in the src subfolder. The tsconfig.spec.ts is for files in the test folder.

The reason two are needed is because test files generally also need the testing framework types, which are not exposed to the app. Also, in the test files, we might want to loosen the strictness of typescript to enable easier mocking. This is definitely not an exhaustive list, but separating these tsconfigs is by no means an anti pattern.


However, I am not sure where you're coming from with your question/remark?

@MKruschke
Copy link
Member

MKruschke commented Nov 20, 2024

However, I am not sure where you're coming from with your question/remark?

I was reading this below and this was pointing out to add them as project references to ensure that the lib folder is created to access the types.

However, there is a giant caveat with this approach! Because TypeScript utilizes Node.js's module resolution, it will reference the declarations defined by the package.json types or exports fields, instead of the outDir compiler option, and the other tsconfig.json does not guarantee these files will exist. This results in TypeScript failing to find the appropriate types! To solve this, add the tsconfig.build.json as a project reference to tsconfig.json.


To just underline my reasoning (without blaming or offending) here the explanation from the docs:

Project references allows you to structure your TypeScript programs into smaller pieces, available in TypeScript 3.0 and newer.
By doing this, you can greatly improve build times, enforce logical separation between components, and organize your code in new and better ways.

By giving TS the info via references it determines what to build first and in which order.

Now the example with reference two local tsconfigs and let's assume package a depends on package b and you want to build a

  1. it will look for references and finds the path to the tsconfig of package b
  2. in the package b tsconfig.json it will find the tsconfig.build.json so it will build/process your package a the first time
  3. as next it will find the second ref in the tsconfig called tsconfig.spec.json so it will build/process your package a the second time but with tests included
  4. afterwards it will continue with package a and build/process that one and if you have again to configs additional to the dependency it will build/process them to

If you have a huge repo with a lot of packages and dependency that advantage of having an improvement on the build time might turn to the opposite in my opinion.

@Papooch
Copy link
Author

Papooch commented Nov 21, 2024

I agree that it might not be the ideal solution, but there's no perfect setup for monorepos and TypeScript (this guy wrote a great sunnary).

As I said, I need these references for editor support (VSCode, but I would assume it's not the only one). If the references are not there, then go to source and name refactoring doesn't work (it instead goes to the built version)

I also need multiple tsconfigs per project for the reasons stated earlier.

I can solve both of my problems by adding those references, maybe at the expense of a slower builds, but since I also employ incremental build (composite: true), I don't see that as an issue at all.

What is also nice is that I can type-check the entire codebase at once instead of iterating over all projects and triggering the type-check for each one.


Currently I need to remember to add a new reference to the base when I add a new library, and to all the referenced libraries that it uses (which people forget a lot).

I was hoping to use this tool to automate the process, but unfortunately, it fell short for out setup (which is by no means unique).

The simplest solution I see would be to add a CLI flag that prevents removing existing references (--no-remove?), since that covers 99% of all cases. Otherwise, some heuristic (best-guess) would be probably needed - like, don't touch references to files in the same folder?


Is this something you'd consider adding?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants