Files
Tobias KoppersGitHubv-work-app[bot] <262237222+v-work-app[bot]@users.noreply.github.com>ClaudeTobias Koppers
859c4edcf0 Produce valid file URLs for import.meta.url on Windows in Turbopack (#94179)
### What?

`import.meta.url` evaluated in a Turbopack-compiled module on Windows
produced
an invalid file URI: the path portion contained backslashes (`\`) and
was not
URL-encoded, e.g.

```
file://C:\Users\me\project\apps\web\app\page.tsx
```

This affects any code that hands the value to `URL`, `fileURLToPath`,
source
maps, dev tools, or anything else that expects a [valid file
URI](https://en.wikipedia.org/wiki/File_URI_scheme).

This PR makes `import.meta.url` return a correct, percent-encoded file
URI on
all platforms, e.g. `file:///C:/Users/me/project/apps/web/app/page.tsx`.

### Why?

The existing codegen in `references/esm/meta.rs` emitted

```js
`file://${__turbopack_context__.P("<rel/path>")}`
```

where `__turbopack_context__.P` is the runtime helper
`resolveAbsolutePath`.
On the Node-side runtime (`shared-node/node-externals-utils.ts`) that
helper
returns `path.join(ABSOLUTE_ROOT, modulePath)`, which is OS-native — so
on
Windows it returns a backslash-separated path with no percent-encoding.
The
result was then concatenated into a `file://...` template literal,
producing
an invalid URI.

The initial hint that `turbopack-core/src/source_map/utils.rs` was the
culprit
turned out to be a false lead: that code path uses
`FileSystemPath::try_join`, which already normalizes `\` to `/` on
Windows.
The bug is in the codegen + runtime helper for `import.meta.url`, not in
source-map handling.

### How?

- Introduce a new runtime function `__turbopack_resolve_file_url__`
(shortcut `F`) whose contract is to return a complete `file://` URI for
a
  given relative module path.
  - Node implementation (`shared-node/node-externals-utils.ts`): uses
`url.pathToFileURL(resolveAbsolutePath(modulePath)).href`.
`pathToFileURL`
    handles drive letters (`file:///C:/...`), normalizes slashes, and
    percent-encodes path segments.
- Browser implementation (`browser/runtime/base/runtime-base.ts`):
returns
    `` `file:///ROOT/${modulePath ?? ''}` `` — the browser runtime
intentionally does not expose the real filesystem path, so it returns
the
same stable placeholder as before, just with a valid `file:///` prefix
    instead of having callers concatenate one.
- Change the `import.meta.url` codegen in `references/esm/meta.rs` to
call
  `__turbopack_resolve_file_url__($formatted)` directly instead of
concatenating a `file://` prefix to the absolute path. The pre-existing
  `encode_path` is kept only to keep the embedded JS string literal safe
  (the runtime helper is responsible for the URI-level encoding).
- Update `TurbopackBaseContext` and add a `ResolveFileUrl` type alias in
  `runtime-types.d.ts` so the new shortcut is typed.
- Register the new shortcut in `TURBOPACK_RUNTIME_FUNCTION_SHORTCUTS` so
user
code can also reference `__turbopack_resolve_file_url__` (mirroring the
existing `__turbopack_resolve_absolute_path__`). `P` is left in place
and
  unchanged because it's still used elsewhere.
- Regenerate the affected Turbopack snapshot fixtures (`import-meta/*`,
`comptime/typeof`, `runtime/default_*_runtime`, `workers/*`,
`debug-ids/*`,
  etc.). The functional change in the generated code is uniform:
  `` `file://${__turbopack_context__.P(<rel>)}` `` →
  `__turbopack_context__.F(<rel>)`.
- Drop the `// TODO: These file URIs are wrong on turbopack+windows`
comment
  and the `.replaceAll('\\', '/')` workarounds from

`test/e2e/app-dir/non-root-project-monorepo/non-root-project-monorepo.test.ts`,
so the assertion now verifies that the URI is correctly slashed and
encoded
  on all platforms.

### Verification

- `cargo clippy --workspace --all-targets` — clean
- `cargo fmt --check` — clean
- `cargo test -p turbopack-tests --test snapshot` — 87/87 pass
- `cargo test -p turbopack-tests --test execution` — 219/219 pass (1
ignored)
- `pnpm test-dev-turbo
test/e2e/app-dir/non-root-project-monorepo/non-root-project-monorepo.test.ts`
— 9/9 pass
- `pnpm test-start-turbo
test/e2e/app-dir/non-root-project-monorepo/non-root-project-monorepo.test.ts`
— 6/6 pass
- `pnpm test-dev-webpack
test/e2e/app-dir/non-root-project-monorepo/non-root-project-monorepo.test.ts`
— 9/9 pass (verifying webpack path still works)

Windows itself can't be exercised in the sandbox, but the new code path
no
longer depends on `path.sep` or any OS-native string manipulation for
the
URI: `url.pathToFileURL` is the canonical Node API for producing a file
URI
from any OS-native path, and the test assertion has been tightened so
that a
regression on Windows would fail in CI rather than be papered over.

<!-- NEXT_JS_LLM_PR -->

---------

Co-authored-by: v-work-app[bot] <262237222+v-work-app[bot]@users.noreply.github.com>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Tobias Koppers <[email protected]>
2026-05-29 07:34:41 +00:00
..
…