Skip to content

[Bug]: this.resolve() returns null for bare relative paths (e.g. await this.resolve("src/index.ts")) without importer #9027

@maiieul

Description

@maiieul

Reproduction link or steps

https://repl.rolldown.rs/#eNp1kU1PhDAQhv/KpBfYBOtHPNXsyZ/gUTxUGLBapoSW3TWk/922gCyJ9kCZj/eZyduJNUxMTFGNF+5s/CcmtrhgVQjx0pvBQWXIOmiMgSM8PoQaMuGGEX3BBqN1bc7EQ0+j2ivUH5UZqroEnaDGRhE+pzJ4aAbTQbbKspJKWuaHRjnqdP8K8qkkAEX96ATMSN6hkzyliljs9dgqsgJeYwSQFPGQ7FCEUWiNPuGNQ+uypIhH2m+q4H1Uun5xcnD5YRPCYkVQxn2OIM9SOXAfyvKFlmd2qG5XH7PD015rNHJt2jwOj4isWGBbo19Wme+38PUHFqzuZfUlW+Sf1gR/Z5N3udnetGzJauwxLEGVQlsyAZMPnJIi6HrBFbTL/fv493fMB8ApVLWMtjH/A5Y3wBI=

  • edit the console.log to see the logs in devtools

What is expected?

this.resolve('src/index.ts') returns { id: '<cwd>/src/index.ts', ... } (matching Rollup).

What is actually happening?

await this.resolve('src/index.ts') returns null.

System Info

System:
    OS: macOS 26.2
    CPU: (12) arm64 Apple M4 Pro
    Memory: 152.89 MB / 48.00 GB
    Shell: 3.7.1 - /opt/homebrew/bin/fish
  Binaries:
    Node: 24.11.1 - /Users/maieul/.local/state/fnm_multishells/83512_1775227721787/bin/node
    npm: 11.6.2 - /Users/maieul/.local/state/fnm_multishells/83512_1775227721787/bin/npm
    pnpm: 10.17.1 - /usr/local/bin/pnpm
  Browsers:
    Chrome: 146.0.7680.178
    Safari: 26.2

Any additional comments?

We hit this in the Qwik framework's Vite plugin. Input paths like src/entry.preview.tsx are passed without ./ prefix in user projects and validated via this.resolve() during buildStart. This worked with Rollup but broke with Rolldown.

AI findings:

When calling this.resolve('src/index.ts') (bare relative path, no ./ prefix) from a plugin hook without an importer, Rolldown returns null. Rollup resolves it against CWD.

In Rollup's built-in resolver (resolveId.ts#L49-L60), bare specifiers are only skipped when there is an importer:

if (importer !== undefined && !isAbsolute(source) && source[0] !== '.') return null;

return addJsExtensionIfNecessary(
  importer ? resolve(dirname(importer), source) : resolve(source),
  ...
);

So for entry-like resolution (no importer), src/index.ts falls through to path.resolve('src/index.ts')<cwd>/src/index.ts. Rolldown doesn't do this fallback.

Metadata

Metadata

Type

Priority

Medium

Effort

Medium

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions