Summary
There's a designed-for mechanism for modules to declare extra npm deps (sm host sync-js-deps reads each module wheel's package.jsondependencies, then npm install --workspaces them), but in the published 0.0.7 packages it doesn't work end-to-end:
- Every built-in module's wheel ships a
package.json with \"dependencies\": {}, even when its .tsx files clearly import third-party packages. - The scaffold's
Makefile doesn't call sync-js-deps from make install or make dev. Even if (1) were fixed, a fresh-clone-to-running-host flow would still skip the install.
Net effect: a fresh sm new host on 0.0.7 errors at vite resolution time on lucide-react and sonner, with no built-in path to fix it short of hand-editing client_app/package.json.
Reproduction
uvx --from simple_module_cli sm new my-app --db sqlite --preset standard -y --no-install
cd my-app && cp .env.example .env && make install && make migrate && make gen-pages
cd client_app && npm run dev
Vite output (relevant lines):
Error: The following dependencies are imported but could not be resolved:
lucide-react (imported by .../site-packages/users/components/RolesTab.tsx)
sonner (imported by .../site-packages/users/pages/Users/Edit.tsx)
Confirming the mechanism exists but finds nothing to install:
$ uv run python -m simple_module_hosting sync-js-deps --dry-run
INFO: Discovered module: Permissions (v1.0.0)
INFO: Discovered module: Users (v1.0.0)
INFO: Discovered module: Settings (v1.0.0)
INFO: Discovered module: Dashboard (v1.0.0)
INFO: Discovered module: Auth (v1.0.0)
No module JS dependencies declared.
collect_module_js_deps() only reads dependencies (per its docstring: "peerDependencies are host-provided singletons and must not be installed from modules") — and every module wheel has it empty.
Evidence — what users ships vs. what it imports
Module's wheel package.json (.venv/lib/python3.12/site-packages/users/package.json):
{
"name": "@simple-module-py/users",
"version": "0.1.0",
"private": true,
"peerDependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"@inertiajs/react": "^2.0.0",
"@simple-module-py/ui": "*"
},
"devDependencies": {
"@simple-module-py/tsconfig": "*"
},
"dependencies": {}
}But the wheel's source imports:
users/components/RolesTab.tsx → lucide-reactusers/pages/Users/Edit.tsx → sonner
Neither is in peerDependencies (so it's not "the host must supply them"), nor in dependencies (so sync-js-deps doesn't pick them up). They're effectively un-tracked.
Same shape in dashboard/package.json, permissions/package.json, auth/package.json — all with \"dependencies\": {}.
Proposed fix
Two edits, ideally landed together:
A. Modules declare what they import
Either:
A1. Have each module's package.json list the third-party packages it imports directly:
{
"name": "@simple-module-py/users",
..."dependencies": {
"lucide-react": "^X.Y.Z",
"sonner": "^X.Y.Z"
}
}…and let sync-js-deps install them into the host workspace.
A2. (cleaner long-term) — Re-export the icons/toasts the modules need from @simple-module-py/ui so module .tsx files don't import upstream packages directly. Then modules only depend on @simple-module-py/ui (which they already do as a peer), and #114's missing-deps fix on the UI package solves this for free.
A2 is more in line with how the framework already treats @simple-module-py/ui as the canonical UI surface — and avoids version skew (one source of truth for which lucide-react is shipped).
B. Wire sync-js-deps into the standard install flow
Update the scaffolded Makefile:
install:
uv sync
cd client_app && npm install
+ $(MAKE) sync-js-deps
dev: gen-pages
@echo "Starting API and UI dev servers..."
$(MAKE) -j2 dev-api dev-ui
+sync-js-deps:+ uv run python -m simple_module_hosting sync-js-deps --host-client-app=client_app+
gen-pages:
uv run python -m simple_module_hosting gen-pages --host-dir=client_app
Without (B), even a perfect (A1) doesn't help on a fresh clone — users hit the same vite error and have to know that an undocumented python -m simple_module_hosting sync-js-deps exists.
Workaround
cd client_app && npm install lucide-react sonner --save=false
Won't survive a lockfile regen.
Related
Environment
simple_module_cli 0.0.7simple_module_users, simple_module_dashboard, simple_module_permissions, simple_module_auth 0.0.7simple_module_hosting 0.0.7 (provides sync-js-deps)
Summary
There's a designed-for mechanism for modules to declare extra npm deps (
sm host sync-js-depsreads each module wheel'spackage.jsondependencies, thennpm install --workspaces them), but in the published 0.0.7 packages it doesn't work end-to-end:package.jsonwith\"dependencies\": {}, even when its.tsxfiles clearly import third-party packages.Makefiledoesn't callsync-js-depsfrommake installormake dev. Even if (1) were fixed, a fresh-clone-to-running-host flow would still skip the install.Net effect: a fresh
sm newhost on 0.0.7 errors at vite resolution time onlucide-reactandsonner, with no built-in path to fix it short of hand-editingclient_app/package.json.Reproduction
Vite output (relevant lines):
Confirming the mechanism exists but finds nothing to install:
collect_module_js_deps()only readsdependencies(per its docstring: "peerDependenciesare host-provided singletons and must not be installed from modules") — and every module wheel has it empty.Evidence — what
usersships vs. what it importsModule's wheel
package.json(.venv/lib/python3.12/site-packages/users/package.json):{ "name": "@simple-module-py/users", "version": "0.1.0", "private": true, "peerDependencies": { "react": "^19.0.0", "react-dom": "^19.0.0", "@inertiajs/react": "^2.0.0", "@simple-module-py/ui": "*" }, "devDependencies": { "@simple-module-py/tsconfig": "*" }, "dependencies": {} }But the wheel's source imports:
users/components/RolesTab.tsx→lucide-reactusers/pages/Users/Edit.tsx→sonnerNeither is in
peerDependencies(so it's not "the host must supply them"), nor independencies(sosync-js-depsdoesn't pick them up). They're effectively un-tracked.Same shape in
dashboard/package.json,permissions/package.json,auth/package.json— all with\"dependencies\": {}.Proposed fix
Two edits, ideally landed together:
A. Modules declare what they import
Either:
A1. Have each module's
package.jsonlist the third-party packages it imports directly:{ "name": "@simple-module-py/users", ..."dependencies": { "lucide-react": "^X.Y.Z", "sonner": "^X.Y.Z" } }…and let
sync-js-depsinstall them into the host workspace.A2. (cleaner long-term) — Re-export the icons/toasts the modules need from
@simple-module-py/uiso module .tsx files don't import upstream packages directly. Then modules only depend on@simple-module-py/ui(which they already do as a peer), and #114's missing-deps fix on the UI package solves this for free.A2 is more in line with how the framework already treats
@simple-module-py/uias the canonical UI surface — and avoids version skew (one source of truth for whichlucide-reactis shipped).B. Wire
sync-js-depsinto the standard install flowUpdate the scaffolded
Makefile:Without (B), even a perfect (A1) doesn't help on a fresh clone — users hit the same vite error and have to know that an undocumented
python -m simple_module_hosting sync-js-depsexists.Workaround
Won't survive a lockfile regen.
Related
@simple-module-py/ui's own missing deps. If A2 is taken, @simple-module-py/ui imports 14+ npm packages but declares only @simple-module-py/i18n in dependencies #114's fix subsumes most of this.@simple-module-py/ui.Environment
simple_module_cli0.0.7simple_module_users,simple_module_dashboard,simple_module_permissions,simple_module_auth0.0.7simple_module_hosting0.0.7 (providessync-js-deps)