Repository navigation
Description
written by claude
Summary
Under any non-root Vite base (e.g. base: "/repo/" for a GitHub Pages subpath deploy), @solidjs/[email protected].* produces SSR HTML whose <script>, <link rel="modulepreload">, and <link rel="stylesheet"> tags are root-absolute (/_build/...) instead of base-prefixed (/repo/_build/...). The page returns 200 from the right URL, but every asset 404s, hydration never starts, and the app appears blank.
There's also a secondary papercut: @solidjs/vite-plugin-nitro-2 defaults Nitro's baseURL to / regardless of Vite's base, so users have to write the prefix twice — once as base in their Vite config and again as nitroV2Plugin({ baseURL: "/repo/" }) — to get Nitro to prerender and serve at the right path.
Reproduction
- Scaffold a SolidStart 2.0 project, set
base: "/sub/"invite.config.ts. pnpm build→node .output/server/index.mjs.curl http://localhost:3000/sub/→ HTML returns, but every asset reference is/_build/...instead of/sub/_build/....
Where the URLs are emitted
packages/start/src/server/manifest/prod-ssr-manifest.ts:path(id)→join("/", viteManifestEntry.file)getAssets(id)→href: "/" + assetjson()→output: join("/", ...)
packages/start/src/server/manifest/dev-client-manifest.ts:import(join("/", id))(same bug in dev under a base)
packages/start-nitro-v2-vite-plugin/src/index.ts:resolvedNitroConfighas nobaseURL, so Nitro defaults to/.
The dev-ssr manifest already does the right thing (normalize(join(import.meta.env.BASE_URL, id))), which is the pattern to copy.
v1 comparison
In v1, Vinxi owned the build manifest and emitted output.path with the router base already prefixed, so StartServer could read it raw and it Just Worked. The v2 migration off Vinxi dropped that wiring. The fix isn't new API — it's restoring base-awareness in the two spots that lost it.
Proposed fix
PR linked below. Three small commits:
- Failing unit tests for
prod-ssr-manifest. - Replace
"/"withimport.meta.env.BASE_URLin the prod SSR manifest and the dev client manifest (usingpathe.join, which collapses to/foowhen base is/). - Default
nitroConfig.baseURLto the resolved Viteconfig.basein the nitro-2 plugin. User-suppliedbaseURLstill wins.
Out of scope (follow-up)
<Router> in the user's app.tsx still requires manual base={import.meta.env.BASE_URL.replace(/\/$/, "")}. Auto-passing it from StartClient/StartServer would close the loop but touches the router integration and is worth a separate discussion.
Activity
birkskyum commentedon Jul 16, 2026
The custom nitro v2 vite plugin has been deprecated in favor of the official Nitro v3 vite plugin
tanukihee commentedon Aug 7, 2026
I am using the official Nitro v3 Vite plugin, but the remaining issue still reproduces.
Environment:
@solidjs/[email protected][email protected][email protected]solidStart({ ssr: false })After
vite build, the generated.output/public/index.htmlstill contains framework-emitted root-absolute asset URLs:Expected:
This is not the deprecated
@solidjs/vite-plugin-nitro-2baseURL propagation issue.nitro/vitereceivesbaseURL: "/foo/", but SolidStart emits the HTML URLs before Nitro can affect them.The installed
@solidjs/startproduction manifest still has the root-path hardcoding:This also happens with
ssr: false, because the static SPA document still uses this production manifest to emit its stylesheet, modulepreload, and entry-script tags.PR #2152 appears to contain the relevant SolidStart-side fix: replace the hard-coded
"/"withimport.meta.env.BASE_URLinprod-ssr-manifest.ts. The old Nitro v2 plugin portion can be omitted, but the manifest fix still seems necessary for the official Nitro v3 integration.Could this issue be reopened, or should I open a new issue scoped specifically to
@solidjs/startproduction/static manifest URLs under a non-root Vitebase?birkskyum commentedon Aug 7, 2026
@tanukihee A new SolidStart v2 issue with modern pacakges would be helpful.