Babylon/materials and babylon/loaders resolve babylon/core ^5.4.0 as a sub dependency

Wanting to use babylonjs 5.4.0 in a project, but I get two instances of babylonjs core: 5.4.0 and 5.7.0, which obviously is troublesome.

The Problem is that babylon/materials and babylon/loaders resolve core ^5.4.0 as a sub dependency and that makes the package manager load core 5.7.0 because of the ^.

Resolved this by introducing a resolutions block in package.json, but I don’t think this should be happening.

This is the resolution block:
“resolutions”: {
@babylonjs/core”: “5.4.0”,
@babylonjs/loaders”: “5.4.0”,
@babylonjs/materials”: “5.4.0”

I guess the solution here is to move the dependencies to be peer dependencies. Otherwise we could set a fixed version in dependencies which has other consequences.
It’s not recommended, but in our current package structure it is possible to have different leakage versions work together. But as you say, the package.json should be constructed differently.

Thanks for the post :blush:

1 Like

Just wanted to update that all babylon dependencies are now peer dependencies! starting next version (5.12.0 will be released on Thursday).

Would it be possible to reconsider this change (and related changes to package.json files in this pr)?

Currently using yarn, running yarn add -D @babylonjs/inspector to a project (that previously only depended on @babylonjs/core) results in:

warning " > @babylonjs/inspector@5.22.1" has unmet peer dependency "@babylonjs/gui@^5.22.0".
warning " > @babylonjs/inspector@5.22.1" has unmet peer dependency "@babylonjs/gui-editor@^5.22.0".
warning " > @babylonjs/inspector@5.22.1" has unmet peer dependency "@babylonjs/loaders@^5.22.0".
warning " > @babylonjs/inspector@5.22.1" has unmet peer dependency "@babylonjs/materials@^5.22.0".
warning " > @babylonjs/inspector@5.22.1" has unmet peer dependency "@babylonjs/serializers@^5.22.0".
warning " > @babylonjs/inspector@5.22.1" has unmet peer dependency "@types/react@>=16.7.3".
warning " > @babylonjs/inspector@5.22.1" has unmet peer dependency "@types/react-dom@>=16.0.9".

If the inspector is then used in the project, it will fail build, as the inspector does need those dependencies installed.

npm doesn’t fail as it installs peer dependencies automatically (see pr here for discussion, including reasoning behind yarn not doing this).

I can fix this for my project by adding all of those as devDependencies, but it seems like this shouldn’t have to be the case (and if it is, then it should probably be documented somewhere).

Could the original problem in this thread be solved by keeping them in dependencies, and using ~5.4.0 instead of ^5.4.0, or even using exact version numbers (though @RaananW you had concerns regarding the consequences of doing that)? I think it’s reasonable to assume that users will want to use the same version of all babylonjs packages, not try and mix and match core/inspector/loader etc. versions.

Related, but slightly different:

Why are those @type dependencies in peerDependencies at all? Shouldn’t they be in devDependencies, as they’re not needed unless developing the inspector?

It seems the location of these have an odd history, initially being in dependencies, then being moved to devDependencies (apparently an issue I raised), before being put back into dependencies (for unstated reasons), and then being moved to peerDependencies.

No, they are dependencies and are needed for the package to work. @babylonjs/gui depends on @babylonjs/core. Same thing for the inspector. They are peer dependencies instead of fixed dependencies so that you as a developer can decide what version you want to use. So, let’s say you want to upgrade only core but stay with the old inspector version for some reason - peer dependencies will work correctly. If we will define it as a dependency you will have 2 different packages of babylonjs - the version you want, and the version the inspector requires. And we don’t want that :slight_smile:

While yes I can see in the inspector types that it makes use of the react types, the issue is that in doing so, it pollutes the global JSX namespace with the react versions of JSX types, which for me (using inferno) causes type errors in any tsx/jsx file. These types can’t be ignored (tsconfig excludes don’t work for types, and the types array doesn’t stop another package (i.e. the inspector) pulling in the types), so the only way I can see for me to fix it in my project is to patch the Inspector type definitions. What is the use case for the inspector needing to expose the react components to users anyway? Could the react types be moved to optional dependencies if it’s determined such a use case exists.

Regarding the other peer dependencies, again I don’t see the use case for mixing versions, as this inevitably leads to errors due to functions/classes etc changing (indeed I assume this was the issue that prompted this thread in the first case). Babylon.js is developed such that all these packages are updated at the same time anyway, so why not just use absolute versions, and have them listed in dependencies? As it stands, yes I can just manually add all the needed peer dependencies to my own package.json, but this seems like a lot of clutter, especially for what I imagine is the most common use case of wanting @babylonjs/core and @babylonjs/inspector installed.

What’s worse though, is that even npm doesn’t work (with automatically installing peer dependencies), with the way peer dependencies are used in all the @babylonjs packages, unless using the most up to date version (of babylonjs). Old versions of babylonjs combined with the same version of the inspector cannot be installed, unless all the peer dependencies are specified (with the same version) in your package.json.

e.g. a project with this package.json

  "name": "npmtest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "@babylonjs/core": "5.15.0",
    "@babylonjs/inspector": "5.15.0"

Gets this output from running npm i

npm ERR! While resolving: npmtest@1.0.0
npm ERR! Found: @babylonjs/core@5.15.0
npm ERR! node_modules/@babylonjs/core
npm ERR!   @babylonjs/core@"5.15.0" from the root project
npm ERR!   peer @babylonjs/core@"^5.0.0" from @babylonjs/inspector@5.15.0
npm ERR!   node_modules/@babylonjs/inspector
npm ERR!     @babylonjs/inspector@"5.15.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @babylonjs/core@"^5.22.0" from @babylonjs/gui@5.23.0
npm ERR! node_modules/@babylonjs/gui
npm ERR!   peer @babylonjs/gui@"^5.0.0" from @babylonjs/inspector@5.15.0
npm ERR!   node_modules/@babylonjs/inspector
npm ERR!     @babylonjs/inspector@"5.15.0" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

I really think that just putting everything in dependencies, with a fixed version, and telling users that all @babylonjs packages included in a projects package.json should be the same version, would be the simplest and clearest way to solve this (and this threads original) issue.

Peer dependencies should only really be used if you expect the user to already have those dependencies installed (and specified in their package.json), which in this case, should probably only be @babylonjs/core. (The react types especially fall foul of this, and would ideally be in dependencies, if that didn’t cause issues due to global types).

This is how it was for a long time. The issue here was that if you installed one dependency’s new version and didn’t update the other you would have two versions of the same package. And this caused interesting issues.

I think this is not 100% accurate. Peer dependencies are there to define things we expect the user to install on their own. I know it’s semantics, but I feel like it can make a difference when talking about it :slight_smile: . npm will take care of that for you or will show you a warning if you haven’t, but the idea is - want a different version for some reason? you can use it without having two versions of the same package. The inspector has so many dependencies and is therefore very apparent when it fails this way. If you look at packages a bit more used than us, you will see that a lot are using peer dependencies instead of dependencies. Best example is react-dom which has a peer dependency on react.

There are benefits (and pitfalls) for both definitions. And there are ways to override the side effects of both types on your side. I will be happy to hear other opinions and (re-)consider what to do in the future.