Skip to content

Commit 75a08e1

Browse files
fix: avoid npm reinstall for empty devDependencies (#7566)
* fix: avoid npm reinstall for empty devDependencies * docs: address review feedback for npm manifest normalization * ci: install greenlet for the Reflex 0.8.23 smoke test * fix: add frontend dev packages with -D so npm saves them as devDependencies npm reads -d as --loglevel info, not --save-dev, so the framework's dev packages landed in dependencies and devDependencies was never written. The rendered package.json then differed from the npm-written one on every reload, which cleared the install cache and reinstalled packages. bun reads -D as --dev too. Replace the absent-vs-empty devDependencies normalization with the flag fix. --------- Co-authored-by: Farhan Ali Raza <62690310+FarhanAliRaza@users.noreply.github.com> Co-authored-by: Farhan <www.mfarvirus@gmail.com>
1 parent d8cb464 commit 75a08e1

3 files changed

Lines changed: 38 additions & 13 deletions

File tree

‎news/7566.bugfix.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add development frontend packages with `-D`, so npm saves them under `devDependencies` and source-only hot reloads no longer reinstall frontend packages.

‎reflex/utils/js_runtimes.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,7 @@ def _install_frontend_packages(
804804
primary_package_manager,
805805
"add",
806806
"--legacy-peer-deps",
807-
"-d",
807+
"-D",
808808
*dev_deps_to_add,
809809
],
810810
show_status_message="Installing frontend development dependencies",

‎tests/units/test_prerequisites.py‎

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -959,7 +959,7 @@ def test_react_compiler_dependencies_toggle(install_packages_env: InstallPackage
959959
env.install()
960960
assert len(calls) == 1
961961
assert "add" in calls[0]
962-
assert "-d" in calls[0]
962+
assert "-D" in calls[0]
963963
assert {f"{name}@{version}" for name, version in compiler_deps.items()} <= set(
964964
calls[0]
965965
)
@@ -1102,7 +1102,7 @@ def get_frontend_development_dependencies(self):
11021102

11031103
env.install()
11041104

1105-
dev_add_calls = [c for c in calls if "add" in c and "-d" in c]
1105+
dev_add_calls = [c for c in calls if "add" in c and "-D" in c]
11061106
assert len(dev_add_calls) == 1
11071107
dev_call = dev_add_calls[0]
11081108
assert "fresh-dev" in dev_call
@@ -1145,7 +1145,7 @@ def test_install_frontend_packages_moves_misplaced_unpinned_dep_to_deps(
11451145
assert len(add_calls) == 1
11461146
add_call = add_calls[0]
11471147
assert "some-pkg" in add_call
1148-
assert "-d" not in add_call
1148+
assert "-D" not in add_call
11491149

11501150

11511151
def test_install_frontend_packages_moves_misplaced_unpinned_dev_dep_to_dev(
@@ -1174,11 +1174,11 @@ def get_frontend_development_dependencies(self):
11741174
assert len(remove_calls) == 1
11751175
assert "some-dev" in remove_calls[0]
11761176

1177-
dev_add_calls = [c for c in calls if "add" in c and "-d" in c]
1177+
dev_add_calls = [c for c in calls if "add" in c and "-D" in c]
11781178
assert len(dev_add_calls) == 1
11791179
assert "some-dev" in dev_add_calls[0]
11801180

1181-
deps_add_calls = [c for c in calls if "add" in c and "-d" not in c]
1181+
deps_add_calls = [c for c in calls if "add" in c and "-D" not in c]
11821182
assert deps_add_calls == []
11831183

11841184

@@ -1204,7 +1204,7 @@ def test_install_frontend_packages_moves_misplaced_pinned_framework_dep(
12041204
assert len(add_calls) == 1
12051205
add_call = add_calls[0]
12061206
assert "react@19.2.5" in add_call
1207-
assert "-d" not in add_call
1207+
assert "-D" not in add_call
12081208

12091209

12101210
def test_install_frontend_packages_conflict_prefers_regular_section(
@@ -1230,7 +1230,7 @@ def get_frontend_development_dependencies(self):
12301230
assert len(add_calls) == 1
12311231
add_call = add_calls[0]
12321232
assert "shared-pkg" in add_call
1233-
assert "-d" not in add_call
1233+
assert "-D" not in add_call
12341234

12351235

12361236
def test_install_frontend_packages_dev_deps_added_before_regular_deps(
@@ -1254,9 +1254,9 @@ def get_frontend_development_dependencies(self):
12541254

12551255
add_calls = [c for c in calls if "add" in c]
12561256
assert len(add_calls) == 2
1257-
assert "-d" in add_calls[0]
1257+
assert "-D" in add_calls[0]
12581258
assert "some-dev" in add_calls[0]
1259-
assert "-d" not in add_calls[1]
1259+
assert "-D" not in add_calls[1]
12601260
assert "some-pkg" in add_calls[1]
12611261

12621262

@@ -1289,7 +1289,7 @@ def get_frontend_development_dependencies(self):
12891289
add_calls = [c for c in calls if "add" in c]
12901290
assert len(add_calls) == 1
12911291
assert "shared-pkg" in add_calls[0]
1292-
assert "-d" not in add_calls[0]
1292+
assert "-D" not in add_calls[0]
12931293

12941294

12951295
def test_install_frontend_packages_does_not_move_correctly_placed_packages(
@@ -1338,11 +1338,11 @@ def test_install_frontend_packages_pins_framework_dependencies(
13381338
add_calls = [c for c in calls if "add" in c]
13391339
pin_deps_call = next(c for c in add_calls if "react@19.2.5" in c)
13401340
assert "isbot@5.1.39" in pin_deps_call
1341-
assert "-d" not in pin_deps_call
1341+
assert "-D" not in pin_deps_call
13421342
assert "--only-missing" not in pin_deps_call
13431343

13441344
pin_dev_deps_call = next(c for c in add_calls if "vite@8.0.9" in c)
1345-
assert "-d" in pin_dev_deps_call
1345+
assert "-D" in pin_dev_deps_call
13461346
assert "--only-missing" not in pin_dev_deps_call
13471347

13481348

@@ -1367,6 +1367,30 @@ def run_package_manager(args, **kwargs):
13671367
return calls
13681368

13691369

1370+
@pytest.mark.parametrize("package_manager", ["bun", "npm"])
1371+
def test_install_frontend_packages_saves_dev_deps_to_dev_section(
1372+
install_packages_env: InstallPackagesEnv,
1373+
monkeypatch,
1374+
package_manager: str,
1375+
):
1376+
"""Dev deps are added with ``-D``, the save-dev flag of both bun and npm.
1377+
1378+
npm reads ``-d`` as ``--loglevel info``, not as save-dev.
1379+
1380+
Args:
1381+
install_packages_env: The isolated install environment.
1382+
monkeypatch: The pytest monkeypatch fixture.
1383+
package_manager: The primary package manager path.
1384+
"""
1385+
env = install_packages_env
1386+
monkeypatch.setattr(constants.PackageJson, "DEV_DEPENDENCIES", {"vite": "1.0.0"})
1387+
calls = _record_calls_with_pm(env, package_manager)
1388+
1389+
env.install()
1390+
1391+
assert calls == [[package_manager, "add", "--legacy-peer-deps", "-D", "vite@1.0.0"]]
1392+
1393+
13701394
def test_install_frontend_packages_npm_skips_frozen_lockfile(
13711395
install_packages_env: InstallPackagesEnv,
13721396
):

0 commit comments

Comments
 (0)