Skip to content

EPBDS-16211 Fix the npm peer conflict the dev-server bump left behind - #130

Merged
AlexSamBY merged 1 commit into
masterfrom
fix-react-refresh-peer
Sep 30, 2026
Merged

AlexSamBY merged 1 commit into
masterfrom
fix-react-refresh-peer

Conversation

@AlexSamBY

Copy link
Copy Markdown
Member

The problem, introduced by #128

#128 moved webpack-dev-server to 6. @pmmmwh/react-refresh-webpack-plugin 0.5.17 declares it as an optional peer only up to 5.x:

peerOptional webpack-dev-server@"3.x || 4.x || 5.x" from @pmmmwh/react-refresh-webpack-plugin@0.5.17

npm ci installs the lock regardless, which is why #128's and #129's CI stayed green. But every npm install <package> since then aborts with ERESOLVE. It was found while adding a devDependency for the React 19 leg.

The fix

@pmmmwh/react-refresh-webpack-plugin ^0.5.16 → ^0.6.3. 0.6.3 (2026-08-27) adds webpack-dev-server 6.x to that peer range (#1046 upstream). The one breaking release between them, 0.6.0, raised minimums we already exceed (Node 18.12, webpack 5.2, webpack-dev-server 4.8). It also removed overlay.sock* options we never set: the demo uses new ReactRefreshWebpackPlugin() with no options.

Checked

  • The install that failed now succeeds, run as npm install --dry-run --save-dev <the same packages>.
  • npm ls --all reports no invalid peer, and npm audit stays at 0.
  • Fast refresh works on the new plugin. In the running demo (npm start), the refresh runtime is injected (__reactRefreshInjected). A temporary edit to NavTabs.jsx, reverted after, is hot-applied: [HMR] Updated modules: ./src/demo/components/NavTabs.jsx and [HMR] App is up to date. A marker set on window beforehand survives, so the page did not reload.
  • The published package is unchanged. All 282 files build-lib publishes are byte-identical to master's; the plugin is demo-only.

Gates

All exited 0:

  • lint:js, lint:css, typecheck;
  • test:env-flags, test:coverage, build, build-lib;
  • test:react16 and test:react17, 2907 tests on each;
  • the manifest contract.

🤖 Generated with Claude Code

#128 moved webpack-dev-server to 6, and @pmmmwh/react-refresh-webpack-plugin
0.5.17 declares it as an optional peer only up to 5.x. `npm ci` installs the
lock regardless, so CI stayed green. But every `npm install <package>` since
then aborts with ERESOLVE, found while adding a devDependency.

0.6.3 (2026-08-27) adds webpack-dev-server 6.x to that peer range. Its one
breaking release, 0.6.0, raised minimums we already exceed (Node 18.12,
webpack 5.2, webpack-dev-server 4.8) and removed `overlay.sock*` options we
never set.

Checked:
- The install that failed now succeeds as a dry run.
- `npm ls` reports no invalid peer, and `npm audit` stays at 0.
- In the running demo the refresh runtime is injected, and a component edit
  is hot-applied ("[HMR] App is up to date") without a reload: a marker set
  on `window` survives it.
- The 282 files build-lib publishes are byte-identical to master's.
@AlexSamBY
AlexSamBY merged commit 844e601 into master Sep 30, 2026
5 checks passed
@AlexSamBY
AlexSamBY deleted the fix-react-refresh-peer branch September 30, 2026 12:34
AlexSamBY added a commit that referenced this pull request Sep 30, 2026
On master since #130 merged, which fixed the `npm install` peer conflict
this change needed gone to add a devDependency. The rebased tree is
identical to the one the local gates below ran on.

## The flip

`peerDependencies`: `react` and `react-dom` now read **`^16.14.0 ||
^17.0.0 || ^18.0.0 || ^19.0.0`**. The range is widened additively, so
hosts on 16.14, 17 and 18 change nothing. This closes §8's fast path:
- gates 1 (Semantic UI React gone) and 3 (`defaultProps`, then the
automatic JSX runtime in #129) were met;
- gate 2 (the form stack) lapsed when `dependencies` was emptied (#128
records why);
- this PR is gate 4.

## How 19 is gated, in three matrices

| | 16.14 | 17 | 18 | 19 |
|---|---|---|---|---|
| whole jest suite | `test:react16` | `test:react17` | `npx jest` /
`test:coverage` | **`test:react19` (new)** |
| packed artifact server-rendered | `test:pack:peers` |
`test:pack:peers` | `test:pack:consumer` | **`test:pack:peers` (added
19.3.0)** |
| published `.d.ts` compiled | `test:types` | `test:types` |
`test:types` | **`test:types` (added `@types/react` 19.3.0)** |

- **The suite on React 19 is a fixture leg, like 16.14 and 17.**
`scripts/fixtures/react19` is an install-only package pinning
`react`/`react-dom` 19.3.0. Plain `npm ci` nests it, it is mapped in at
resolve time, and `npm run test:react19` runs it locally too. The
harness still asserts the loaded React (19.3.0) and scheduler (0.28) in
every worker.
- **What differs for 19.** React 19 has no legacy root and ships
`react-dom/client`, so the leg renders through `createRoot` as the
default suite does. `floors.js` records `legacyRoot: false`, which skips
three things that exist only for 16/17: the RTL `legacyRoot` patch, the
`ReactDOM.render` assertion and the `react-dom/client` stub.
- **CI.** The new `react-19` job replaces the `continue-on-error`
`react-19-advisory` job, which installed React 19 over the lock with
`--legacy-peer-deps`; the new job needs neither. No required checks are
configured on master today, so `react-19` gates exactly as
`react-16-floor` and `react-17` do. If branch protection ever named
`react-19-advisory`, it should name `react-19` now.
- **Types.** The published declarations compile against `@types/react`
19, with both the interop default import and the direct CommonJS import.
That matters because 19 removed the global `JSX` namespace. `gen-ts`
stays on the dev tree's 18; the plan's "pin `@types/react@19` for
`gen-ts`" item was written assuming the dev tree would move to 19, and
it does not.

## Docs

- README and the demo's docs page state the new range.
- The demo's changelog (Unreleased) says React 19 is supported and how
it is tested. It also records #129's change: the bundle imports
`react/jsx-runtime` from the host's React, which a host that aliases
`react` to one copy has to alias too. Two older Unreleased paragraphs
that said the range was not widened yet are updated, so the section does
not contradict itself.
- `CLAUDE.md` lists the three React legs.
- The plan closes §8's gate 4, the CI-coverage row, the `gen-ts` row,
the Appendix C "React 19 flip" checklist and §10's Phase 7 React 19
item.

## Gates

All exited 0:
- `lint:js`, `lint:css`, `typecheck`, `typecheck:contract`;
- `css:fixture:check`, `docs:props:check`, `docs:views:check`;
- `test:env-flags`, `test:types`, `test:coverage`, `build`;
- `test:pack`, `test:pack:peers` (16.14.0, 17.0.2, 19.3.0);
- `test:react16`, `test:react17`, `test:react19`, 2907 tests on each, as
on 18;
- `test:e2e`, 41 Playwright tests;
- the manifest contract.

Two first runs lost a jest worker to `SIGSEGV`, each killing one suite
before its tests ran: `test:react19` once and `test:react17` once. That
is the Node 24 V8 garbage-collector crash
([nodejs/node#62393](nodejs/node#62393)),
fixed on `v24.x-staging` but not in a release yet. Both passed 2907/2907
on rerun. CI runs Linux, where it has not been seen.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant