Skip to content

build.chunkImportMap drops module preload dependency lists when base is not / #23350

Description

@MichalJZ

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:

  1. 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.
  2. 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

  • Follow our Code of Conduct
  • Read the Contributing Guidelines.
  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
  • Make sure this is a Vite issue and not a framework-specific issue.
  • Check that this is a concrete bug.
  • The provided reproduction is a minimal reproducible example of the bug.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions