Hoisting breaks `require` semantics
See original GitHub issueHoisting is intended as a runtime optimization that doesn’t affect program correctness. But it’s easy to accidentally a write a package that only works when hoisting is in effect that then breaks if deployed as a normal package.
Expected Behavior
Each package should have access to the exact same set of dependencies, whether or not hoisting is applied.
Current Behavior
Hoisted dependencies leak into packages that otherwise should not have access to them.
Possible Solution
Move the hoisted dependencies out of the natural node module resolution path and instead link them explicitly into the packages where they are appropriate.
For example, assume that first
and second
share my-hoisted-dep
. Today we will get this, which leaks my-hoisted-dep
into third
:
├── node_modules
│ └── my-hoisted-dep
└── packages
├── first
├── second
└── third
Instead we could move the hoisted deps off the module resolution path:
├── lerna-common
│ └── node_modules
│ └── my-hoisted-dep
└── packages
├── first
│ └── node_modules
│ └── my-hoisted-dep -> ../../../lerna-common/node_modules/my-hoisted-dep
├── second
│ └── node_modules
│ └── my-hoisted-dep -> ../../../lerna-common/node_modules/my-hoisted-dep
└── third
This would also eliminate the need for npm --global-style
, which is an incomplete solution to this same general problem (it replaces wrong versions with correct versions, but won’t replace wrong versions with “no version”).
Context
Moving a piece of code between packages is a reasonably common thing to do. If you do that while using hoisting, it’s easy to produce packages that no longer work standalone without realizing it. For this reason, IMO it’s not currently safe to use --hoist
, especially in environments like CI, since it will let this class of bug escape.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:8
- Comments:6 (1 by maintainers)
I would argue that’s what eslint-plugin-import is for (specifically
import/no-unresolved
).That’s not true, you can import nearly every transitive dependency regardless of whether you depend on it directly just look in node_modules on a single package and try, yes Lerna theoretically adds more you can accidentally require but it’s not more unsafe than any project that uses npm or yarn