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

Unable to get Knip to respect tsconfig compilerOptions.paths #546

Closed
ecleary opened this issue Mar 14, 2024 · 7 comments
Closed

Unable to get Knip to respect tsconfig compilerOptions.paths #546

ecleary opened this issue Mar 14, 2024 · 7 comments
Labels
bug Something isn't working

Comments

@ecleary
Copy link

ecleary commented Mar 14, 2024

After extensive testing and reading through Knip's documentation, I have been unable to find any more than a workaround for the following issue. In checking to see if this issue has been reported before, the closest I could find was #388, but that seems to be a bit different. Apologies if there was another report that I missed.

I haven't managed to create a minimal reproduction, but please let me know if that would be necessary here. Unfortunately I'm unable to link to the source files as this is a company project.


My project consists of three workspaces:

  • root, which contains the Knip config and the other two workspaces.
  • workspace-1, which contains several exports used by both workspace-1 and workspace-2.
  • workspace-2, which uses some exports from workspace-1, but which shares none of its own exports with other workspaces.

Here is a simplified representation of the folder structure:

root
├── workspace-1
│   ├── src
│   │   ├── entry-1.tsx
│   │   ├── foo.tsx
│   │   └── shared
│   │       └── bar.ts
│   └── package.json
├── workspace-2
│   ├── src
│   │   ├── entry-2.tsx
│   │   └── baz.ts
│   ├── package.json
│   └── tsconfig.json
├── knip.ts
└── package.json

workspace-2 uses exports from workspace-1 by way of the following config in workspace-2/tsconfig.json:

{
  "include": ["src"],
  "compilerOptions": {
    "baseUrl": "src",
    "paths": {
      "*": ["../../workspace-1/src/*"]
    }
  }
}

workspace-1/src/shared/bar.ts contains an enum like the following:

export enum Plants {
  TREE = "tree",
  BUSH = "bush",
  FLOWER = "flower",
}

The exported Plants enum is imported in both workspaces:

  • workspace-1/src/foo.tsx imports the Plants enum and uses it as a type but does not access any of the enum members.
  • workspace-2/src/baz.ts imports the Plants enum and accesses all of the enum members.

When I run Knip, the Plants enum members get reported as unused:

> @org/repo@0.0.0 knip /file/path/root
> knip

Unused exported enum members (3)
TREE    Plants  workspace-1/src/shared/bar.ts
BUSH    Plants  workspace-1/src/shared/bar.ts
FLOWER  Plants  workspace-1/src/shared/bar.ts
 ELIFECYCLE  Command failed with exit code 9.

Is there any way to configure Knip to respect the compilerOptions.paths setting in workspace-2/tsconfig.json so that the enum members aren't reported as unused?

I have scoured the Knip docs and tried every seemingly related suggestion I could find, including the suggestion to not explicitly set compilerOptions.baseUrl, to no avail. The only suggestion that has actually silenced the report is prepending the exported enum with /** @public */, but that feels like more of a workaround than a solution.

Apologies for the long post. If I can provide clarification, please just let me know. Thank you!

@ecleary ecleary added the bug Something isn't working label Mar 14, 2024
@webpro
Copy link
Collaborator

webpro commented Mar 14, 2024

Apologies for the time lost, I need to document this. You're not the first to face this strictness of Knip, and it's indeed not clear what's off.

My guess is that workspace-1 doesn't have workspace-2 listed as a dependency in package.json (and/or vice versa). The setup you're explaining works in both realms of TypeScript and the package manager separately. Yet when it comes together in Knip, it's (currently) more restrictive in the sense that internal workspaces should be listed in package.json, and the import specifiers should use those package names (and not rely on TS path aliases to cross workspace boundaries).

Overall, I'm inclined to think path aliases shouldn't be used to cross workspace boundaries. Happy to hear counter arguments.

@ecleary
Copy link
Author

ecleary commented Mar 14, 2024

Thank you for the quick feedback, and no problem.

You are indeed correct that the workspace dependency is configured in tsconfig.json only, not in package.json. I have now tested:

  • Adding the dependency relationship to package.json in workspace-1 and workspace-2 (both individually and together).
  • Replacing the TS path alias with the package name in the import specifier in workspace-2/src/baz.ts (where Plants is being imported).

TypeScript seems pleased with these changes, but I'm afraid that the output from Knip remains the same.

It seems clear to me now that we would need a minimal reproduction in order to investigate further. I think it is unlikely I'll find the time to prepare that anytime soon, but if I'm wrong then I'll come back with an update.

No problem to close this issue so it doesn't hang around open in your queue.

@webpro
Copy link
Collaborator

webpro commented Mar 15, 2024

Just to be sure:

  • Did you re-install dependencies? So the symlinks are there in node_modules.
  • Maybe try without the * in compilerOptions.paths?

We can leave this open until I've documented it somewhere.

@ecleary
Copy link
Author

ecleary commented Mar 15, 2024

  • Did you re-install dependencies? So the symlinks are there in node_modules.

Yes, I reinstalled dependencies after adding the workspace dependency configuration to package.json.

  • Maybe try without the * in compilerOptions.paths?

Oh, I'm glad you asked. I just tried this, and the result is not what I expected.

When I remove the * line from compilerOptions.paths and then run Knip, the output includes a long list of "Unlisted dependencies" that doesn't appear when the * line is present. This change in output suggests that actually Knip has been respecting the tsconfig compilerOptions.paths all along.

It seems there is something about enums, or about the specific enum in my project, that causes the enum members to be reported as unused despite the workspace dependency configuration that otherwise seems to function as expected.

@webpro
Copy link
Collaborator

webpro commented Mar 17, 2024

  • Maybe try without the * in compilerOptions.paths?

Oh, I'm glad you asked. I just tried this, and the result is not what I expected.

When I remove the * line from compilerOptions.paths and then run Knip, the output includes a long list of "Unlisted dependencies" that doesn't appear when the * line is present. This change in output suggests that actually Knip has been respecting the tsconfig compilerOptions.paths all along.

There's two notes I should make here:

  1. For module resolution, the compilerOptions.paths are required. I made this suggestion for you to verify whether it would help with the original issue. But it would mess up everything else relying on those paths. Should've added that right away.
  2. later in the process, after the module resolution is done and dependency graph is created, Knip assigns unused things to workspaces, based on workspace package.json#name and package.json#[dev]dependencies, which it is currently unable to do in your situation, because of this.

It seems there is something about enums, or about the specific enum in my project, that causes the enum members to be reported as unused despite the workspace dependency configuration that otherwise seems to function as expected.

Based on the above, I don't think enums are the issues here.

@ecleary
Copy link
Author

ecleary commented Mar 18, 2024

  1. For module resolution, the compilerOptions.paths are required. I made this suggestion for you to verify whether it would help with the original issue. But it would mess up everything else relying on those paths. Should've added that right away.

Ah I see, makes sense. I think we have been able to confirm that modifying compilerOptions.paths has no effect on the original issue, so good thing we tried that.

  1. later in the process, after the module resolution is done and dependency graph is created, Knip assigns unused things to workspaces, based on workspace package.json#name and package.json#[dev]dependencies, which it is currently unable to do in your situation, because of this.

Well, following your advice, I have added the workspace dependency to package.json and have modified the enum's import specifier to use the package name instead of the TS path alias. With these two changes in place, I have tested running Knip both with compilerOptions.paths in its original state and with compilerOptions.paths modified as discussed in point 1. In all cases the report from Knip indicates the enum members as unused.

If I ever manage to put together a minimal reproduction, then I'll be sure to let you know.

@webpro
Copy link
Collaborator

webpro commented May 5, 2024

Closing this. Feel free to open a new issue with a minimal reproduction.

Related/potential fix: #611

@webpro webpro closed this as completed May 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants