-
-
Notifications
You must be signed in to change notification settings - Fork 971
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
Ensure/check single version of a dependency package throughout workspace #2713
Comments
What if we will add something like a linter for module.exports = {
lintPackage (pkg) {
if (pkg.dependencies?.mongodb) {
pkg.dependencies.mongodb = '^3.0.0'
}
return pkg
}
} pnpm can use this for two things.
Yarn v2 has something similar. It is called constraints and they use Prolog for describing these rules. cc @pnpm/collaborators Also, I am not sure it should be part of pnpm. It can be probably a separate project that supports pnpm, npm, yarn. it is not a linter, but for pnpm I have created this script that normalizes package.json files: https://github.com/pnpm/pnpm/blob/master/utils/updater/src/index.ts |
Can't |
The changes of readPackage are not saved to the file system |
Another possible approach:
|
I think such logic should be out of scope of concern of
But does it prevent one package from having |
pnpm is a... package manager. Which excels at working with monorepos. How is managing package versions across the monorepo out of the scope of pnpm? |
Basic logic of |
It's a little too late for that. 😂 |
Well what things does pnpm do which could be actually (potentially) achivable by user using avaialbe API, but not innner pnpm logic? |
Didn’t resolution-strategy = fewer-dependencies |
We need two things:
|
no. The change introduces by fewer-dependencies was that when dependencies were resolved, versions of already resolved packages from the parent packages were preferred. |
I've found It would be great if it had first-party support for |
Thanks for the tip! |
I'm working on pnpm support for syncpack, @zkochan one thing I want to be clear on: does pnpm search each entry in pnpm-workspaces.yaml recursively, even if it doesn't end with |
maybe you can use this: https://github.com/Thinkmill/manypkg/tree/master/packages/get-packages
no |
That may be just what I'm looking for, thanks. |
@zkochan My modified version of syncpack is ready if you want to try it. git clone https://github.com/aparajita/syncpack.git
cd syncpack
pnpm install
pnpm build
cd /path/to/pnpm-source
/path/to/syncpack/dist/bin.js list-mismatches You may find the results interesting. |
I see. There are a few issues. |
Good incentive to implement package syncing in pnpm. 😁 |
My PR to add pnpm support to syncpack has been merged and is now available via |
Just chiming in that the linter idea would be great for @grouparoo! On incoming PRs we could fail a test if the version of a dependency doens't match the rest of the monorepo. |
@remorses #2713 (comment) Im contemplating if adding a marker to package.json that we can pick up, would be a good solution. |
@zkochan did anything like However this isn't a great setup for keeping package versions in sync that are not required in the root workspace |
Gradle does this with a "version catalog" file: https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format A similar approach for pnpm might be: versions.yaml or versions.toml: versions:
react: ^18.0.2
packages:
# react and react-dom versions should align
react: react
react-dom: react
typescript: ^8.4.0 apps/myapp/package.json: {
"dependencies": {
"react": "catalog:*"
},
"devDependencies": {
"typescript": "catalog:*"
}
} Where the |
Hello fellow pnpm users! 👋 I wanted to share pnpm/rfcs#1, which has a lot of the same ideas here. The RFC proposes a new The RFC adds a few features on top of a consistent root versions catalog.
The RFC got stalled a bit because of the complexity of the extra mile efforts above, but is something I'm still very invested in. Please feel free to drop ideas on the RFC or give suggestions. (Disclaimer: I'm not a pnpm maintainer. Just a user that's submitted pull requests in the past.) |
In Bit there is a concept known as environments (cc @GiladShoham). I think we can support something similar in pnpm. It would be not as powerful as in Bit but it could allow to sync dependencies between projects (even if they don't stay in the same project). For Bit it would also be beneficial as we would mention that the idea was borrowed from Bit and for more powerful envs people can use bit cli. This is how I think it could work. In {
"name": "foo",
"version": "1.0.0",
"pnpm": {
"environment": "@comp/react-env@1.0.0"
}
} This field would contain the exact name and version of a package called an "environment package". This package would be a regular package with dependencies and peer dependencies in its package.json. Then we could add some fields to inherit fields from this env package. For instance: {
"name": "foo",
"version": "1.0.0",
"pnpm": {
"environment": "@comp/react-env@1.0.0",
"dependenciesFromEnv": ["react"],
"devDependenciesFromEnv": ["eslint"],
"peerDependenciesFromEnv": ["react-dom"]
}
} pnpm would then lookup the versions of these dependencies in the env package.json and place them to regular dependencies fields. This is the package.json file of the {
"name": "@comp/react-env",
"version": "1.0.0",
"dependencies": {
"react": "16",
"eslint": "4",
"react-dom": "17",
"jest": "22"
},
"peerDependencies": {
"react-dom": "17"
"react": "16"
}
} In memory, this is out project's package.json that will be updated with selected dependencies from the env: {
"name": "foo",
"version": "1.0.0",
"dependencies": {
"react": "16"
},
"devDependencies": {
"eslint": "4"
},
"peerDependencies": {
"react-dom": "17"
},
"pnpm": {
"environment": "@comp/react-env@1.0.0",
"dependenciesFromEnv": ["react"],
"devDependenciesFromEnv": ["eslint"],
"peerDependenciesFromEnv": ["react-dom"]
}
} |
@zkochan Heck ya now this is starting to look good. Could we use the the reference package name as a key though, so there could be multiple? Something like this. {
"name": "foo",
"version": "1.0.0",
"pnpm": {
"environment": {
"@comp/react-env@1.0.0": {
"dependencies": ["react"],
"devDependencies": ["eslint"],
"peerDependencies": ["react-dom"]
}
}
}
} If someone adds the same dependency from two different reference packages I would say we just use a "last in wins" strategy. |
I don't know if it makes sense to support multiple. This is inspired by Bit, which supports one env per component. I think one env should be enough because you can create envs that inherit other envs. |
I would think multiple would be handy in a larger monorepo when I want my front end projects to all share a vue version, but then a few of them share some packages with the backend or the root. If I am following you would solve this by creating new packages in the mono repo that are just used as a environment for other packages? Just a collection of all the packages within the monorepo that should have consistent versioning? |
yes, I think so |
Alright I am following ya now. That's not bad. I think my issue is personal aesthetics, which clearly is not a solid reason to change anything haha. Something about 4 sibling properties in an object all with "env" attached to them to indicate they are related vs keeping them all tucked away inside a "env" property. 🤷♂️ Either way getting a feature like this would help a lot, whichever way you prefer to configure it :) |
@aphex it feels a little odd at first because in most setups there's a lot of friction to adding new packages in a monorepo but having separate packages for envrionments required by your other packages is exactly what Bit does. After spending some time with it I think I can say it's a very useful pattern, especially with Bit since it reduces that friction to near zero. Bringing some of that funcionality into pnpm IMO would be great. |
@evelant No I get it, I am onboard and definitely want to see the functionality. If Bit has a solid pattern it should be followed. My aesthetic thoughts on the config design are not critical here. |
I don't know how this will be configured and how the properties will be named. It is just an example to explain the concept. Bit doesn't have such properties at all because it can automatically detect what packages from the env are used by the component. |
Until there is an automatic way to find out duplicated packages I listed some steps that helped me: #6055 (reply in thread) |
I've recently started to use PNPM in a monorepo and it solves a lot of problems but at the same time I'm experiencing this issue with singleton packages. I modified the |
@remorses's solution is great, but unfortunately only allows checking for the entire workspace. Sometimes you care about individual projects in the workspace having singleton packages (eg. |
This feature is close to completion thanks to @gluxon. You can already try it using the branch from the next PR: #8122 Just place your versions in the catalog section of catalog:
react: 16 Then in your {
"dependencies": {
"react": "catalog:"
}
} If you check it out please leave your experiences. We want to release it soon. |
Catalogs don't really solve this problem, usually i get multiple instances of For example when i update Here is an example of next getting duplicated because babel-plugin-macros resolves to different versions: next@14.2.4(@babel/core@7.24.6)(@playwright/test@1.43.1)(babel-plugin-macros@2.8.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@next/env': 14.2.4
'@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001638
graceful-fs: 4.2.11
postcss: 8.4.31
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
styled-jsx: 5.1.1(@babel/core@7.24.6)(babel-plugin-macros@2.8.0)(react@18.3.1)
optionalDependencies:
'@next/swc-darwin-arm64': 14.2.4
'@next/swc-darwin-x64': 14.2.4
'@next/swc-linux-arm64-gnu': 14.2.4
'@next/swc-linux-arm64-musl': 14.2.4
'@next/swc-linux-x64-gnu': 14.2.4
'@next/swc-linux-x64-musl': 14.2.4
'@next/swc-win32-arm64-msvc': 14.2.4
'@next/swc-win32-ia32-msvc': 14.2.4
'@next/swc-win32-x64-msvc': 14.2.4
'@playwright/test': 1.43.1
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
next@14.2.4(@playwright/test@1.43.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies:
'@next/env': 14.2.4
'@swc/helpers': 0.5.5
busboy: 1.6.0
caniuse-lite: 1.0.30001638
graceful-fs: 4.2.11
postcss: 8.4.31
react: 18.3.1
react-dom: 18.3.1(react@18.3.1)
styled-jsx: 5.1.1(babel-plugin-macros@3.1.0)(react@18.3.1)
optionalDependencies:
'@next/swc-darwin-arm64': 14.2.4
'@next/swc-darwin-x64': 14.2.4
'@next/swc-linux-arm64-gnu': 14.2.4
'@next/swc-linux-arm64-musl': 14.2.4
'@next/swc-linux-x64-gnu': 14.2.4
'@next/swc-linux-x64-musl': 14.2.4
'@next/swc-win32-arm64-msvc': 14.2.4
'@next/swc-win32-ia32-msvc': 14.2.4
'@next/swc-win32-x64-msvc': 14.2.4
'@playwright/test': 1.43.1
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros It would be great if there was a way to tell pnpm to install next only once and ignore different peer dependencies resolutions |
@remorses your issue is unrelated to this issue. |
I think it is quite a common issue, if you have multiple packages/app in you monorepo that may depend on the same packge dependency (for as common example
mongodb
), it is reasonable to have only single version thought the project (though there maybe need for exeptions sometimes). But eventually you may add this dep to new package, and it will install newer version, but you may not notice this and forget to update the rest.What is the best way to approach this issue? I thought about using hook, to check lockfile after resolution. Another approach would be declare such dep in the root of the project, so everyone will use it, but even if all your packages/apps (which is rare case) depend on this, this still doesn't seem a nice, clean and lean solution.
The text was updated successfully, but these errors were encountered: