Reuse installed framework pins after a lockfile install
Split out of #7054. Stacked on #7451 (the npm --save-dev fix), so it targets that branch; only the last commit is this PR.
Changes
After a successful install from the persisted lockfile, framework dependencies from constants.PackageJson.DEPENDENCIES / DEV_DEPENDENCIES whose exact version already sits in the right package.json section are dropped from the follow-up add. npm saves caret ranges, so for npm the declaration is also checked against the package-lock.json entry and the installed package's own package.json before the pin counts as satisfied. Anything that does not verify (non-exact framework specs, explicit conflicting pins, changed overrides, links, aliases, missing manifests) keeps today's add.
Measurement
This is the one from the set I would not merge on the numbers. The add calls still run, because the Radix Themes and Tailwind plugins contribute pinned packages that are always re-added; the PR only shortens their argument lists:
fresh .web, persisted lockfile | main | this PR |
|---|---|---|
bun: packages in the two add calls | 10 dev + 30 | 3 dev + 15 |
| bun: compile phase (includes install) | 1.15 s | 1.08 s |
| npm: compile phase (includes install) | 8.2 s | 8.0 s |
| package-manager commands | 3 | 3 |
That is within run-to-run noise on this app, for ~190 lines of new logic in js_runtimes.py. The speedup #7054 attributed to this piece on npm was really the --save-dev bug fixed in #7451. I am opening it so the split is complete and the measurement is on record; closing it is a fine outcome.
Measurement setup
Five-page app from the blank template (Radix Themes + Tailwind v4 plugins), Linux x86_64, 4 vCPU, Python 3.14, Node 22.22, npm 10.9, bun 1.4.2. Each run is a fresh interpreter calling reflex.utils.export.export() the same way reflex export does; durations are the phase timings the export already reports to telemetry (compile includes the dependency install). Medians of 3 runs unless noted. Vite dominates every export (~6.5 s); these numbers isolate the part this PR touches.
Type of change
- Performance improvement (non-breaking)
Checklist
- Tests added for the change; the full
tests/unitssuite passes locally except the 14reflex_bench/drivers/test_browser.pycases that need a Playwright browser launch, which fail identically on untouchedmainin this sandbox -
ruff check,ruff format --check,codespell, andpyright reflex testspass locally - News fragment added for every package touched
https://claude.ai/code/session_018nWB9r2HcC5tkT72UxWgGj
Generated by Claude Code