Commit d9290f8
fix: install pnpm deps in hoisted mode + declare @babel/types (#24288)
## Summary
The Vite dev server intermittently fails (or hangs) on `vite-basics` and
other Vite-using IT modules because transitive npm dependencies are not
consistently reachable from the project's root `node_modules`. Selenium
tests then wait for pages that never render, and the matrix shard times
out at the 30-minute job cap.
Two distinct symptoms observed:
1. **`Cannot find package '@babel/types'`** — the bundled Vite plugin
`react-function-location-plugin.js` does
`import * as t from '@babel/types';`, but `@babel/types` was only
present transitively via `@babel/core` and pnpm did not always hoist
it to the root.
2. **`Failed to resolve import "@lit/reactive-element/..."`,
`"cookie"`, `"set-cookie-parser"`, `"@preact/signals-react/runtime"`** —
all transitives of declared deps (`lit`, `react-router`,
`@preact/signals-react-transform`) — also not consistently hoisted.
Both are the same underlying problem: pnpm with `shamefully-hoist=true`
does not deterministically expose every transitive at the project root.
## Fix
Three commits, layered:
### 1. Declare `@babel/types` directly
Adds `"@babel/types": "7.29.0"` (matching `@babel/core`) to the bundled
`devDependencies` in
`flow-server/.../dependencies/vite/package.json`. Correct on its own
merits — the plugin imports the package, so the package should be a
real dependency. Updates `NodeUpdaterTest`'s expected-set accordingly.
### 2. Switch the bundled `.npmrc` template to `node-linker=hoisted`
Adds `node-linker=hoisted` to `flow-server/src/main/resources/npmrc`,
the template `TaskRunNpmInstall` writes to the project. This tells
pnpm to install in **flat npm-style mode** — every package (declared
or transitive) at the project root, no `.pnpm/` virtual store.
Resolutions become deterministic.
`shamefully-hoist=true` is left in the template alongside, so manual
`pnpm install` invocations from a developer shell still pick up at
least the legacy partial-hoist behavior if some user-level config
overrides our `node-linker`.
### 3. Pass `--config.node-linker=hoisted` on the pnpm CLI
The `.npmrc` change alone did not actually flip pnpm's install layout
in CI: `node_modules/.pnpm/...` paths kept appearing in error
messages, indicating pnpm was still using its default `isolated`
mode. The pre-existing `--shamefully-hoist=true` CLI flag added by
`FrontendTools.getPnpmExecutable()` likely took precedence and locked
pnpm to the isolated layout (where `shamefully-hoist` makes sense as
a partial-hoist heuristic).
Replace `--shamefully-hoist=true` with `--config.node-linker=hoisted`
on the CLI. CLI > `.npmrc` > defaults in pnpm's config precedence, so
the install is now unambiguously hoisted regardless of any project-
or user-level `.npmrc` content. `FrontendToolsTest` updated to assert
the new flag.
## Trade-offs
- **Disk/install time**: hoisted mode uses slightly more disk and is
a few seconds slower than the symlink store for fresh installs.
Acceptable for the determinism gain.
- **Loose isolation**: hoisted mode allows packages to import any
other package, declared or not. Flow's frontend code already relies
on this (e.g. plugins importing transitives), so this is the
current de-facto behavior — just made deterministic.
- **Behavioral change for downstream users**: anyone with a custom
`.npmrc` that lacks the auto-gen marker keeps their config (per
existing `TaskRunNpmInstall.createNpmRcFile()` logic), but the new
CLI flag still applies — they'll silently get hoisted mode for
Flow-driven installs. Worth flagging in release notes.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent a6c4ded commit d9290f8
6 files changed
Lines changed: 19 additions & 3 deletions
File tree
- flow-build-tools/src
- main/java/com/vaadin/flow/server/frontend
- test/java/com/vaadin/flow/server/frontend
- flow-server/src/main/resources
- com/vaadin/flow/server/frontend/dependencies/vite
Lines changed: 7 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
364 | 364 | | |
365 | 365 | | |
366 | 366 | | |
367 | | - | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
368 | 374 | | |
369 | 375 | | |
370 | 376 | | |
| |||
Lines changed: 3 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
379 | 379 | | |
380 | 380 | | |
381 | 381 | | |
382 | | - | |
383 | | - | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
384 | 385 | | |
385 | 386 | | |
386 | 387 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
169 | 169 | | |
170 | 170 | | |
171 | 171 | | |
| 172 | + | |
172 | 173 | | |
173 | 174 | | |
174 | 175 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
223 | 223 | | |
224 | 224 | | |
225 | 225 | | |
| 226 | + | |
226 | 227 | | |
227 | 228 | | |
228 | 229 | | |
| |||
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
6 | 12 | | |
7 | 13 | | |
0 commit comments