Skip to content

Static absolute src in Vue SFC is bundled as an import despite transformAssetUrls's documented includeAbsolute: false default #22889

Description

@JK-Effects

Describe the bug

Per Vite's Static Asset Handling docs, referencing an asset with an absolute path (e.g. <img src="/icon.png">) should never be included in the build — it's meant to be resolved at runtime against the app's public directory, and left completely untouched at build time.

@vitejs/plugin-vue's template.transformAssetUrls option also documents includeAbsolute: false as the default, meaning absolute urls should not be processed into imports.

In practice, a static src="/icon.png" attribute is still converted into import _imports_0 from '/icon.png', and Rollup/Rolldown then tries to resolve it as a real module:

  • If no matching file exists anywhere resolvable, the build fails with [UNRESOLVED_IMPORT] Could not resolve '/icon.png'.
  • In a build.lib + output.preserveModules: true setup (common for component libraries), the same behavior instead surfaces as:

Invalid substitution "/icon" for placeholder "[name]" in "entryFileNames" pattern, can be neither absolute nor relative path.

This happens because the absolute module id ends up being used to compute the [name] placeholder for what Rollup treats as an emitted "entry" chunk (since every module becomes its own chunk under preserveModules).

Expected behavior
The static, absolute src="/icon.png" should be left as a literal string in the compiled render function — no import generated, no attempt to resolve or bundle it — matching both Vite's public-directory convention and @vitejs/plugin-vue's documented includeAbsolute: false default.

Actual behavior
The compiler still emits an import for the absolute path, which either fails to resolve outright, or (in preserveModules library builds) crashes the build with an "Invalid substitution ... entryFileNames" error.

Workaround
Rewriting the static attribute as a bound expression avoids the SFC compiler's asset-url transform (which only processes static string attributes):

-<img src="/icon.png" alt="icon" />
+<img :src="'/icon.png'" alt="icon" />

This works, but shouldn't be necessary given the documented default.

Additional context

Originally hit while migrating a component-library build config from Vite 7 to Vite 8, using build.lib with multiple entries and output.preserveModules: true + preserveModulesRoot: "src". The library references an icon meant to be provided by the consuming application's public directory (src="/icon.png"), which is a standard pattern for component libraries.


If further context is required from the original repository that caused the error during migration, I can also share that here if needed.

Reproduction

https://github.com/JK-Effects/vite-icon-build-bug/tree/main

Steps to reproduce

npm install
npm run build

System Info

System:
    OS: Windows 11 10.0.26200
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
    Memory: 492.21 MB / 15.68 GB
Binaries:
    Node: 24.16.0 - C:\Program Files\nodejs\node.EXE
    npm: 11.18.0 - C:\Users\jkrau\node_modules\.bin\npm.CMD
    pnpm: 7.5.0 - C:\Users\jkrau\AppData\Roaming\npm\pnpm.CMD
Browsers:
    Edge: Chromium (150.0.4078.48)
    Firefox: 152.0.4 - C:\Program Files\Mozilla Firefox\firefox.exe
    Internet Explorer: 11.0.26100.8115
npmPackages:
    @vitejs/plugin-vue: ^6.0.7 => 6.0.7
    vite: ^8.1.3 => 8.1.3

Used Package Manager

npm

Logs

vite v8.1.3 building client environment for production...
✓ 5 modules transformed.
✗ Build failed in 306ms
error during build:
Build failed with 1 error:

[INVALID_OPTION] Invalid substitution "/favicon" for placeholder "[name]" in "entryFileNames" pattern, can be neither absolute nor relative paths.

at aggregateBindingErrorsIntoJsError (file:///C:/Users/jkrau/Downloads/vite-repro/vite-repro/node_modules/rolldown/dist/shared/error-BlQ0-ek7.mjs:48:18)
at unwrapBindingResult (file:///C:/Users/jkrau/Downloads/vite-repro/vite-repro/node_modules/rolldown/dist/shared/error-BlQ0-ek7.mjs:18:128)
at #build (file:///C:/Users/jkrau/Downloads/vite-repro/vite-repro/node_modules/rolldown/dist/shared/rolldown-build-aV0QeeTW.mjs:3256:34)
at async buildEnvironment (file:///C:/Users/jkrau/Downloads/vite-repro/vite-repro/node_modules/vite/dist/node/chunks/node.js:32622:66)
at async Object.build (file:///C:/Users/jkrau/Downloads/vite-repro/vite-repro/node_modules/vite/dist/node/chunks/node.js:33044:19)
at async Object.buildApp (file:///C:/Users/jkrau/Downloads/vite-repro/vite-repro/node_modules/vite/dist/node/chunks/node.js:33041:153)
at async CAC.<anonymous> (file:///C:/Users/jkrau/Downloads/vite-repro/vite-repro/node_modules/vite/dist/node/cli.js:777:3) {

errors: [Getter/Setter]
}

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug: upstreamBug in a dependency of Vitep3-minor-bugAn edge case that only affects very specific usage (priority)regressionThe issue only appears after a new releasewindows only

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions