Skip to content
Merged
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ All notable changes to this project are documented in this file. The format is b

## [Unreleased]

### Fixed
- Vite's dev-mode dependency pre-bundling now resolves cross-package bare
imports (e.g. `maplibre-gl`, `pmtiles`) from module pages whose importers sit
outside the host's `client_app/` — including wheel-installed modules and
workspace modules shipping their own JS deps. The scaffold template (Vite 6)
seeds `optimizeDeps.esbuildOptions.nodePaths` and the framework repo (Vite 8)
seeds `optimizeDeps.rolldownOptions.resolve.modules` with the workspace
`node_modules/` as a NODE_PATH-style fallback for the dep scanner (GH issue #152).

## [0.0.1] — 2026-04-21

Initial public release. All 12 Python packages publish to PyPI and all 3 JS packages publish to npm under the `@simple-module-py` scope.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,16 @@ export default defineConfig({
optimizeDeps: {
entries: ['main.tsx', 'pages/**/*.tsx', ...moduleOptimizeEntries],
include: collectOptimizeIncludes(),
// Vite's dep scanner runs esbuild against every entry above. When the
// entry sits outside the workspace (a wheel-installed module's
// pages/, or sometimes even a workspace module's pages/), esbuild's
// upward node_modules walk from the importer does not always reach
// the hoisted node_modules at fsRoot. Seeding it as NODE_PATH-style
// fallback ensures bare specifiers like `maplibre-gl` resolve during
// scan-imports. See GitHub issue #152.
esbuildOptions: {
nodePaths: [path.join(fsRoot, 'node_modules')],
},
},
build: {
outDir: '../static/dist',
Expand Down
35 changes: 35 additions & 0 deletions framework/cli/tests/test_scaffolding_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,38 @@ async def test_cli_create_host_runs_end_to_end(self, tmp_path):
assert "simple_module_dashboard" in (tmp_path / "out" / "pyproject.toml").read_text(
encoding="utf-8"
)

async def test_scaffold_vite_config_includes_node_paths_fallback(self, tmp_path):
"""vite.config.ts must seed optimizeDeps.esbuildOptions.nodePaths
with the workspace node_modules so esbuild's scan-imports pass can
resolve cross-package bare imports from module pages whose importers
sit outside the host's client_app (e.g. wheel-installed modules).

Regression test for GitHub issue #152.
"""
from simple_module_cli.scaffolding import create_host

dest = tmp_path / "demo"
create_host(name="demo", dest=dest, modules=[])

vite_config = (dest / "client_app" / "vite.config.ts").read_text(encoding="utf-8")

# The scanner fallback must be configured under optimizeDeps so it
# applies to both dev pre-bundling and `vite build`'s pre-bundle pass.
assert "esbuildOptions" in vite_config, (
"vite.config.ts must configure optimizeDeps.esbuildOptions"
)
assert "nodePaths" in vite_config, (
"vite.config.ts must seed optimizeDeps.esbuildOptions.nodePaths "
"with the workspace node_modules (GH issue #152)."
)
# The seeded path must reference fsRoot — the dir that contains the
# hoisted node_modules — not a hardcoded literal that breaks in
# flat-vs-workspace layouts.
assert "fsRoot" in vite_config, (
"nodePaths must reference fsRoot (not a hardcoded literal) so the "
"fallback works in both flat and workspace layouts (GH issue #152)."
)
assert "node_modules" in vite_config, (
"nodePaths entry must include 'node_modules' (GH issue #152)."
)
12 changes: 12 additions & 0 deletions host/client_app/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,18 @@ export default defineConfig({
'react/jsx-dev-runtime',
...moduleDecls,
],
// Add the hoisted workspace node_modules to Rolldown's resolve search
// so the dev-mode scan resolves bare specifiers from module pages
// whose importer paths sit outside host/client_app (e.g.
// `modules/<name>/pages/*.tsx` shipping their own JS deps). Rolldown's
// default `modules: ['node_modules']` walks upward from the importer,
// which doesn't always reach the workspace root; adding the absolute
// path provides a NODE_PATH-style fallback. See GitHub issue #152.
rolldownOptions: {
resolve: {
modules: ['node_modules', path.join(projectRoot, 'node_modules')],
},
},
},
root: __dirname,
build: {
Expand Down
Loading