fix(vite): resolve cross-package bare imports from out-of-workspace modules - #154
Merged
Conversation
…odules (#152) When a module's pages live under .venv/.../site-packages/ (wheel install) or otherwise sit outside the workspace root, Vite's resolver walks up from the importer looking for node_modules and never reaches <repo>/node_modules where npm hoists deps. Bare imports like `maplibre-gl`, `pmtiles`, or even host-provided peers (`@inertiajs/react`, `@simple-module-py/ui`) fail with "Failed to resolve import … Does the file exist?". The fix adds a `pre` resolveId Vite plugin that catches bare imports from any registered module-pages dir and re-resolves them as if the importer lived at the workspace root, putting <repo>/node_modules back on the resolver's path. Combined with pre-bundling module-declared deps and peer deps via `optimizeDeps.include`, dev server, scan-imports, and production build all converge on the host's hoisted copy. Tested by pointing the manifest at a copy of the dashboard module outside the workspace; without the fix `vite dev`/`vite build` fail with the issue's error, with it both succeed and pages render normally.
Deploying simple-module-python with
|
| Latest commit: |
8bdf314
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://4e3b2133.simple-module-python.pages.dev |
| Branch Preview URL: | https://claude-fix-issue-152-xpar9.simple-module-python.pages.dev |
Three quality fixes from /simplify review: - moduleBareImportResolver now guards on pagesDir prefixes (modulePagesPrefixes), not pkgDir — so only files actually under `pages/` trigger the workspace re-resolution, not arbitrary files in the module package. - Precompute the workspace-prefix string + fakeWorkspaceImporter path once at config load, instead of rebuilding them inside the resolveId hot path on every import. - Drop three inline comments that narrated the guard logic; the block comment above the function already explains the why. Test side: extend fake_module_factory to write peerDependencies and assert read_module_package_json surfaces them — the TS-side optimizeDeps walk reads both blocks and was previously uncovered.
antosubash
marked this pull request as ready for review
May 15, 2026 20:12
antosubash
added a commit
that referenced
this pull request
May 18, 2026
…modules (#156) The moduleBareImportResolver plugin added in #154 short-circuits when the importer path sits under fsRoot/projectRoot, which was meant to skip host-internal files but ends up skipping workspace-member module pages too. In an npm-workspaces scaffold (`workspaces: ["host/client_app", "modules/*"]`) deps hoist to the workspace root, so fsRoot resolves to the workspace root — and workspace-member modules at `modules/<name>/...` sit *under* it. The early-return excluded the very modules that need workspace-root re-resolution, so bare imports like `maplibre-gl` / `pmtiles` failed with "could not be resolved" during dev resolveId. Drop the fsRoot/projectRoot containment check; the `modulePagesPrefixes` guard already pins the plugin to module-page importers regardless of whether they live inside or outside the workspace tree. Apply the fix to both the scaffold template (Vite 6) and the framework's host config (Vite 8). Add a content-level regression test ensuring the bad early- return doesn't reappear.
4 tasks
antosubash
added a commit
that referenced
this pull request
May 18, 2026
…modules (#156) (#157) * test(cli): add failing test for vite scan-imports nodePaths fallback (#152) * test(cli): split assertion into separate fsRoot/node_modules checks (#152) * fix(scaffold): seed esbuild nodePaths so vite scan-imports resolves cross-package bare imports from module pages (#152) * fix(host): seed esbuild nodePaths for module-page scan-imports (#152) * docs(changelog): note fix for vite scan-imports cross-package resolution (#152) * fix(host): use rolldownOptions.resolve.modules instead of deprecated esbuildOptions.nodePaths for Vite 8 (#152) * docs(changelog): correct scope — dep pre-bundling is dev-only, note Vite 6 vs 8 paths (#152) * fix(vite): cross-package bare imports also fail for workspace-member modules (#156) The moduleBareImportResolver plugin added in #154 short-circuits when the importer path sits under fsRoot/projectRoot, which was meant to skip host-internal files but ends up skipping workspace-member module pages too. In an npm-workspaces scaffold (`workspaces: ["host/client_app", "modules/*"]`) deps hoist to the workspace root, so fsRoot resolves to the workspace root — and workspace-member modules at `modules/<name>/...` sit *under* it. The early-return excluded the very modules that need workspace-root re-resolution, so bare imports like `maplibre-gl` / `pmtiles` failed with "could not be resolved" during dev resolveId. Drop the fsRoot/projectRoot containment check; the `modulePagesPrefixes` guard already pins the plugin to module-page importers regardless of whether they live inside or outside the workspace tree. Apply the fix to both the scaffold template (Vite 6) and the framework's host config (Vite 8). Add a content-level regression test ensuring the bad early- return doesn't reappear.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #152.
Summary
When a module's pages live outside the workspace root — under
.venv/.../site-packages/<pkg>/pages/for wheel installs — Vite's resolver walks up from the importer looking fornode_modulesand never reaches<repo>/node_moduleswhere npm hoists deps. Bare imports likemaplibre-gl,pmtiles, or even host-provided peers (@inertiajs/react,@simple-module-py/ui) fail with:Fix
Adds a
preresolveIdVite plugin that:<repo>/node_modulesback on the resolver's path.skipSelf: trueto avoid an infinite recursion.Combined with pre-bundling module-declared
dependencies+peerDependenciesviaoptimizeDeps.include, dev server, scan-imports, and production build all converge on the host's hoisted copy.Also accepts the module's
package.jsonin either of the two locations the framework supports (next to the Python package for wheel installs, one level up for editable/workspace installs), matchingread_module_package_jsoninsimple_module_hosting.manifest.Test plan
make test-py— 215 passednpx biome check host/client_app/— cleannpx tsc --noEmit -p host/client_app/tsconfig.json— cleanmodules/dashboardto/tmp/fake-wheel-dashboard, pointedmodules.manifest.jsonat it (simulating a wheel-installed module outside the workspace), and addednanoid(not in host'spackage.json) to its deps + Home.tsxvite devreturnsFailed to resolve import "@inertiajs/react" / "@simple-module-py/i18n" / "nanoid"for the out-of-workspace page.nanoid/@inertiajs/react/lucide-reactgo through the pre-bundle cache, workspace packages (@simple-module-py/i18n,@simple-module-py/ui) resolve via@fs/paths to their workspace sources.vite buildalso succeeds end-to-end (✓ built in 600ms).framework/hosting/tests/test_manifest.pyexerciseread_module_package_jsonfor both layouts (wheel + source-tree) andcollect_module_js_depsaggregation, locking in the contract thevite.config.tswalks rely on.Files
host/client_app/vite.config.ts— AddmoduleBareImportResolverplugin, walk modulepackage.json(wheel + source layouts) fordependencies+peerDependencies.framework/cli/simple_module_cli/templates/host/client_app/vite.config.ts— Same fix for newly scaffolded projects (smpy new/create-host).framework/hosting/tests/test_manifest.py— New tests forread_module_package_json/collect_module_js_deps.Generated by Claude Code