Produce valid file URLs for import.meta.url on Windows in Turbopack#94179
Merged
Conversation
`import.meta.url` was emitted as `` `file://${__turbopack_context__.P(...)}` ``,
where `P` (`resolveAbsolutePath`) returned an OS-native absolute path. On
Windows that contained backslashes and was not URL-encoded, producing an
invalid file URI.
Introduce a new runtime helper `F` (`__turbopack_resolve_file_url__`) that
delegates to `url.pathToFileURL` in Node (handles drive letters, slash
normalization, and percent-encoding) and returns a stable
`file:///ROOT/...` placeholder in the browser runtime. The `import.meta.url`
codegen now calls this helper directly instead of concatenating a
`file://` prefix to the absolute path.
Drop the `.replaceAll('\\', '/')` workaround and the Windows TODO from the
`non-root-project-monorepo` e2e test.
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Tobias Koppers <sokra@users.noreply.github.com>
Contributor
Tests PassedCommit: 77ecc73 |
Contributor
Stats skippedCommit: 77ecc73 |
mischnic
reviewed
May 28, 2026
mischnic
reviewed
May 28, 2026
- Percent-encode path segments in the browser runtime's `resolveFileUrl` so the placeholder URI is a valid file URI even when the module path contains non-URL-safe characters. - Add fixture pages whose source file (`with space.ts`) contains a space in the filename, and assert that the resulting `import.meta.url` contains `with%20space.ts` for RSC, SSR, and client-side. Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Tobias Koppers <sokra@users.noreply.github.com>
lukesandberg
approved these changes
May 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
import.meta.urlevaluated in a Turbopack-compiled module on Windows producedan invalid file URI: the path portion contained backslashes (
\) and was notURL-encoded, e.g.
This affects any code that hands the value to
URL,fileURLToPath, sourcemaps, dev tools, or anything else that expects a valid file URI.
This PR makes
import.meta.urlreturn a correct, percent-encoded file URI onall platforms, e.g.
file:///C:/Users/me/project/apps/web/app/page.tsx.Why?
The existing codegen in
references/esm/meta.rsemitted`file://${__turbopack_context__.P("<rel/path>")}`where
__turbopack_context__.Pis the runtime helperresolveAbsolutePath.On the Node-side runtime (
shared-node/node-externals-utils.ts) that helperreturns
path.join(ABSOLUTE_ROOT, modulePath), which is OS-native — so onWindows it returns a backslash-separated path with no percent-encoding. The
result was then concatenated into a
file://...template literal, producingan invalid URI.
The initial hint that
turbopack-core/src/source_map/utils.rswas the culpritturned 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 insource-map handling.
How?
__turbopack_resolve_file_url__(shortcut
F) whose contract is to return a completefile://URI for agiven relative module path.
shared-node/node-externals-utils.ts): usesurl.pathToFileURL(resolveAbsolutePath(modulePath)).href.pathToFileURLhandles drive letters (
file:///C:/...), normalizes slashes, andpercent-encodes path segments.
browser/runtime/base/runtime-base.ts): returns`file:///ROOT/${modulePath ?? ''}`— the browser runtimeintentionally does not expose the real filesystem path, so it returns the
same stable placeholder as before, just with a valid
file:///prefixinstead of having callers concatenate one.
import.meta.urlcodegen inreferences/esm/meta.rsto call__turbopack_resolve_file_url__($formatted)directly instead ofconcatenating a
file://prefix to the absolute path. The pre-existingencode_pathis kept only to keep the embedded JS string literal safe(the runtime helper is responsible for the URI-level encoding).
TurbopackBaseContextand add aResolveFileUrltype alias inruntime-types.d.tsso the new shortcut is typed.TURBOPACK_RUNTIME_FUNCTION_SHORTCUTSso usercode can also reference
__turbopack_resolve_file_url__(mirroring theexisting
__turbopack_resolve_absolute_path__).Pis left in place andunchanged because it's still used elsewhere.
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>).// TODO: These file URIs are wrong on turbopack+windowscommentand the
.replaceAll('\\', '/')workarounds fromtest/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— cleancargo fmt --check— cleancargo test -p turbopack-tests --test snapshot— 87/87 passcargo 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 passpnpm test-start-turbo test/e2e/app-dir/non-root-project-monorepo/non-root-project-monorepo.test.ts— 6/6 passpnpm 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.sepor any OS-native string manipulation for theURI:
url.pathToFileURLis the canonical Node API for producing a file URIfrom 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.