๐ก Have a mode or configuration option that allows for monorepos that install deps at the root
Closed this issue ยท 5 comments
Suggest an idea for this project
My preferred style of monorepo is one in which deps are installed only at the root. (This is the "Google-style" of monorepo, which ensures that the whole company uses the same versions of dependencies.) Unfortunately, it seems that Knip does not support this style of monorepo.
Example
monorepo/
โโโ package.json (containing `"react": "^18.0.0"` and `"angular": "^18.0.0"`)
โโโ node_modules/
| โโโ [etc]
โโโ packages/
โโโ foo/
| โโโ package.json (containing `"react": "^18.0.0",`)
โโโ bar/
โโโ package.json (containing `"react": "^18.0.0",`)
In this example, Knip will report both "react" and "angular" as being unused, because it doesn't understand that dependencies are supposed to be installed at the root of the monorepo.
However, if we just tell Knip to ignore all dependencies at the root of the monorepo, that kind of sucks, because now there is no way to find that the "angular" dependency is completely unused.
Thus, this is a feature request for Knip to support monorepo format.
Duplicate of #345.
My preferred style of monorepo is one in which deps are installed only at the root. (This is the "Google-style" of monorepo, which ensures that the whole company uses the same versions of dependencies.)
How is that ensured?
And what happens if a dependency is installed in one of the workspaces' package.json
, but not in the root package.json
?
How is that ensured?
It's ensured because dependencies are installed at the root. In other words, a "package.json" file can't both have React 17 and React 18, it can only have one or the other. Hopefully that makes sense.
And what happens if a dependency is installed in one of the workspaces' package.json, but not in the root package.json?
By "workspace", do you mean "package subdirectory"? There is no concept of a workspace in a Google-style monorepo. So I think you are asking what would happen if someone new to the monorepo accidentally types "npm install foo --save" inside of a package subdirectory, which would create a duplicate "node_modules" folder, which would be a mistake because now two "node_modules" directories would exist, one at the root and one inside of the package subdirectory. I think what would happen at that point is that everything would work fine for the local dev who made the mistake. But as soon as they pushed a commit, CI would fail to build the project, because CI only runs npm install
at the root of the monorepo and not the package subdirectory, so when CI goes to build the project, TypeScript would complain that the new dependency does not exist. Thus, it would be obvious at that point for the developer that they made a mistake, and they would fix the problem.
Thanks for your explanations.
I was asking, since I'd expect the dependency versions can get out of sync (even though the root package.json
is leading). Also, dependencies can be removed from a package subdirectory package.json
- while it's still in use in that directory - and CI wouldn't complain? Would there be something to point out such issues?
Overall it feels brittle to do package management this way. Maybe I'm missing something, I would expected there to be more checks or linting in place? Perhaps your approach is documented somewhere?
My point is: before I would start to consider a feature like this I need to understand the value and use case of your approach better. Sorry, I still fail to see it. We've discussed the exact same thing almost a year ago, what has changed?
since I'd expect the dependency versions can get out of sync (even though the root package.json is leading)
Indeed! To prevent this, this style of monorepo uses tools like syncpack
. So as part of your monorepo linting, you run npx syncpack list-mismatches
, and it reports anything that is out of sync, and will fail the lint run. (syncpack
is really nice because you can also just run syncpack fix-mismatches
and it fixes everything automatically.)
dependencies can be removed from a package subdirectory package.json - while it's still in use in that directory - and CI wouldn't complain? Would there be something to point out such issues?
Good question. This problem is automatically detected by ESLint. Specifically, the rule of import-x/no-extraneous-dependencies
. (It correctly finds the problem by using the base rule without any additional options.)
Overall it feels brittle to do package management this way.
With the combination of the syncpack list-mismatches
and the import-x/no-extraneous-dependencies
rule, I don't think it is brittle. On the contrary, I think that when your monorepo uses the same versions of dependencies, your code becomes more robust, because you are less likely to run into issues where e.g. using two monorepo libraries together ends up failing in weird and seemingly random ways when upstream libs of different versions are mixed together.
We've discussed the exact same thing almost a year ago, what has changed?
I mostly forgot about the last issue when opening this one, since it has been a while. My apologies. If you like, we can close this one too.
With the combination of the
syncpack list-mismatches
and theimport-x/no-extraneous-dependencies
rule, I don't think it is brittle.
Indeed, that certainly are great options. I guess I was trying to figure this out with my questions. Thanks for clearing that up. Going to close this one as well then.