I think the issue is with how pnpm resolves dependencies in a monorepo with isolated installs.
My use case:
Rootnode_modules/.pnpm:
contains rescript
contains @rescript/runtime
some/apppackage.json:
"devDependencies": {
"rescript": "^12.0.0"
},
some/appnode_modules:
contains rescript
does not contain@rescript/runtime
Vite import fails because the compiled source file contains import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js"
With pnpm’s isolated installs, a package can only import modules that appear in its own dependencies (or devDependencies), so from pnpm’s point of view some/app directly depends on @rescript/runtime and must declare it.
Adding rescript to dependencies does not solve the issue; you get the same error. Even if rescript itself depends on @rescript/runtime, pnpm will not expose @rescript/runtime as a direct dependency of some/app, so Node/Vite still cannot resolve it from some/app’s node_modules.
Yup, this sounds about right.
It is only @rescript/runtime code that will end up in your bundle so it does make sense to add that to “dependencies” and the compiler to “devDependencies”.
This does highlight a DX problem, I suppose.
Your need two packages in practice and those can conflict. Similar to how you can mix react 18 with react-dom 19. You want those in sync, a mismatch can lead to headaches.
This problem only really surfaces more clearly when you are using isolated installs.
wouldn’t this be sort of trivial to mitigate by having the compiler emit a warning if the two packages exist in package.json and are of different versions?
I think it’s the app developer’s responsibility to reconcile dependency versions. Pushing it over to maintainers of these dependencies just adds development and maintenance overhead. Maybe it’s a bit forced example, but I can’t remember any better one now. Take Svelte and SvelteKit. When making a typical “Svelte app” you usually need both packages. @sveltejs/kit has svelte as a dev dependency but in your package.json you need to include both, and thus the responsibility of maintaining and reconciling their versions lies on you, the app developer.
What I’m trying to say is that I think including both packages explicitly shouldn’t be considered a DX problem or some shortcoming of library/framework.
i think including one in deps and one in devDeps should be the recommended approach for any real-world scenario.
if you deploy with node-externals there’s no reason to include the compiler
you shouldn’t be depending on implicitly included packages
the compiler should only include dependencies that it actually needs, not include subdeps just because it’s convenient for the user of the lib
semantically, it’s more correct to have rescript (tooling) under devDeps and runtime under deps.
i honestly think this is just a bad over-simplification, although it’s not even a big issue - now that i know about this, as a more experience rescript user, i’ll just have both installed. but i still feel the recommendation to only have rescript under deps is not just bad, it’s also incorrect