Describe the bug
build.chunkImportMap drops every module preload dependency list when base is not /. __vite__mapDeps is not emitted at all, so nothing requests the stylesheet of a lazily imported chunk and no chunk is preloaded.
The cause is that Vite injects one baseUrl when it calls rolldown and reads a different one back. Building the rolldown options, it adds the base:
chunkImportMap: options.chunkImportMap ? {
...(typeof options.rolldownOptions.experimental?.chunkImportMap === "object"
? options.rolldownOptions.experimental?.chunkImportMap
: {}),
baseUrl: base,
} : options.rolldownOptions.experimental?.chunkImportMap
so rolldown correctly writes the map keys prefixed with base. But reading them back, Vite looks at the user's rolldownOptions, where that value was never written, and falls back to /:
function getImportMapBaseUrl(options) {
const chunkImportMap = options.build.rolldownOptions.experimental?.chunkImportMap;
if (typeof chunkImportMap === "object" && chunkImportMap.baseUrl) return chunkImportMap.baseUrl;
return "/";
}
// getImportMap()
mapping: Object.fromEntries(
Object.entries(content.imports).map(([k, v]) => [k.slice(baseUrl.length), v.slice(baseUrl.length)]),
)
The keys are therefore base + fileName while the mapping strips "/". With base: '/sub/' the keys become sub/assets/x.js, which never matches a bundle key (assets/x.js), so importMapMapping?.[rawFilename] misses, deps stays empty, and the preload marker is replaced with [].
Two visible symptoms, both from that one lookup:
- No dependency lists.
__vite__mapDeps is absent, so a lazy chunk's CSS is never requested - the asset is emitted, mapped, and referenced by nothing. The component renders unstyled. Lazy chunks also lose modulepreload, which makes every lazy boundary serial.
- The CSS entry key is derived from the wrong name. With
base: '/' the key is the stable id (lazy-BwY0iVaq.css); with base: '/sub/' it is the real file's hash (lazy-DBM4GDuH.css), because the same reverse lookup falls back to chunk.fileName.
Changing that one line to return options.base ?? "/" fixes both in the reproduction: __vite__mapDeps comes back, the CSS is requested, and the key becomes the stable id again.
Reproduction
https://github.com/MichalJZ/vite-chunkimportmap-base-repro
Steps to reproduce
npm install
npx vite build
vite.config.mjs is { base: '/sub/', build: { chunkImportMap: true } }, and src/lazy.js (reached only through import()) imports lazy.css.
Then, in dist:
grep -rl __vite__mapDeps assets prints nothing, and no file references lazy-*.css,
importmap.json carries "/sub/assets/lazy-<real-js-hash>.css" as the key.
Set base: '/' and build again: __vite__mapDeps appears in the entry chunk, the CSS id is referenced, and the map key is the stable id.
System Info
System:
OS: macOS 26.6.2
Binaries:
Node: 24.18.0
npm: 11.16.0
npmPackages:
vite: ^8.2.2 => 8.2.2
Reproduced on 8.2.1 as well. Build-only - vite build, any browser.
Used Package Manager
npm
Logs
vite build --debug prints nothing about the import map or the preload helper; the output is silent on this.
Validations
Describe the bug
build.chunkImportMapdrops every module preload dependency list whenbaseis not/.__vite__mapDepsis not emitted at all, so nothing requests the stylesheet of a lazily imported chunk and no chunk is preloaded.The cause is that Vite injects one
baseUrlwhen it calls rolldown and reads a different one back. Building the rolldown options, it adds the base:so rolldown correctly writes the map keys prefixed with
base. But reading them back, Vite looks at the user'srolldownOptions, where that value was never written, and falls back to/:The keys are therefore
base + fileNamewhile the mapping strips"/". Withbase: '/sub/'the keys becomesub/assets/x.js, which never matches a bundle key (assets/x.js), soimportMapMapping?.[rawFilename]misses,depsstays empty, and the preload marker is replaced with[].Two visible symptoms, both from that one lookup:
__vite__mapDepsis absent, so a lazy chunk's CSS is never requested - the asset is emitted, mapped, and referenced by nothing. The component renders unstyled. Lazy chunks also losemodulepreload, which makes every lazy boundary serial.base: '/'the key is the stable id (lazy-BwY0iVaq.css); withbase: '/sub/'it is the real file's hash (lazy-DBM4GDuH.css), because the same reverse lookup falls back tochunk.fileName.Changing that one line to
return options.base ?? "/"fixes both in the reproduction:__vite__mapDepscomes back, the CSS is requested, and the key becomes the stable id again.Reproduction
https://github.com/MichalJZ/vite-chunkimportmap-base-repro
Steps to reproduce
vite.config.mjsis{ base: '/sub/', build: { chunkImportMap: true } }, andsrc/lazy.js(reached only throughimport()) importslazy.css.Then, in
dist:grep -rl __vite__mapDeps assetsprints nothing, and no file referenceslazy-*.css,importmap.jsoncarries"/sub/assets/lazy-<real-js-hash>.css"as the key.Set
base: '/'and build again:__vite__mapDepsappears in the entry chunk, the CSS id is referenced, and the map key is the stable id.System Info
System: OS: macOS 26.6.2 Binaries: Node: 24.18.0 npm: 11.16.0 npmPackages: vite: ^8.2.2 => 8.2.2Reproduced on 8.2.1 as well. Build-only -
vite build, any browser.Used Package Manager
npm
Logs
vite build --debugprints nothing about the import map or the preload helper; the output is silent on this.Validations