Skip to content

Build fails when the HTML entry is a symlink to a file outside root (Bazel sandbox) #23585

Open

Description

@u9g

Describe the bug

When the HTML entry inside root is a symlink to a file outside root, vite build fails:

[plugin vite:build-html]
RolldownError: The "fileName" or "name" properties of emitted chunks and assets must be strings that are neither absolute nor relative paths, received "../index.html".

This is the layout of a Bazel sandbox (rules_js): the working directory is a real directory, and every input file in it is a symlink to the real file elsewhere. #21955 reported it from Bazel and was closed as fixed by #22832, but that fix only realpaths root itself. Here root is already a real path; the entry file is what points elsewhere. The resolver (now the Rust vite resolve plugin in rolldown) turns <root>/index.html into its real path, and vite:build-html then names the asset with path.relative(config.root, id), which starts with ../:

const shortEmitName = normalizePath(
path.relative(config.root, normalizedId),
)
this.emitFile({
type: 'asset',
originalFileName: normalizedId,
fileName: shortEmitName,
source: result,

Vite 7 (rollup) fails the same way outside Bazel; it worked inside Bazel only because rules_js patches fs.realpath in Node, which the Rust resolver bypasses.

Workarounds that build fine:

  • resolve: { preserveSymlinks: true }
  • root: fs.realpathSync(dirname(vite.config)) plus build.outDir: path.resolve(process.cwd(), 'dist'), so the output still lands in the sandbox

Both change resolution for the whole project to fix the name of one output file. I think the HTML output name should come from the entry's input path (<root>/index.html), not from the resolved module id. Either the vite resolve plugin could leave HTML entries unresolved to their real path, or vite:build-html could map the resolved id back to the configured input before computing the relative path. Happy to send a PR for whichever you prefer.

Reproduction

https://github.com/u9g/vite-symlinked-entry-repro

Steps to reproduce

npm install
npm run repro

repro.sh creates sandbox/ containing a symlink to each project file and runs vite build from there. No Bazel needed.

System Info

  System:
    OS: macOS 27.0
    CPU: (8) arm64 Apple M1
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 24.19.0
    npm: 11.17.0
  npmPackages:
    vite: ^8.3.1 => 8.3.1 (rolldown 1.2.11)

Used Package Manager

npm

Logs

vite v8.3.1 building client environment for production...
transforming...
✓ 4 modules transformed.
rendering chunks...
✗ Build failed in 1.11s
error during build:
Build failed with 1 error:

[plugin vite:build-html]
RolldownError: The "fileName" or "name" properties of emitted chunks and assets must be strings that are neither absolute nor relative paths, received "../index.html".
    at error (node_modules/rolldown/dist/shared/logs-D6uA606S.mjs:166:24)
    at PluginContextImpl.emitFile (node_modules/rolldown/dist/shared/bindingify-input-options-XrReX_BJ.mjs:1353:82)
    at PluginContextImpl.generateBundle (node_modules/vite/dist/node/chunks/node.js:31808:10)

Validations

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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