From f7e56398f142a5d7f571d7fd734db9b44d5c8984 Mon Sep 17 00:00:00 2001 From: xusd320 Date: Fri, 15 May 2026 16:05:34 +0800 Subject: [PATCH] feat(turbopack): support auto public path --- .../src/browser/runtime/base/runtime-base.ts | 7 ++- .../js/src/shared/runtime/runtime-types.d.ts | 2 +- .../js/src/shared/runtime/runtime-utils.ts | 44 ++++++++++++++++++- turbopack/crates/turbopack-static/src/ecma.rs | 11 +++++ 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/runtime-base.ts b/turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/runtime-base.ts index 990662e26087..4658ff1812c3 100644 --- a/turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/runtime-base.ts +++ b/turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/runtime-base.ts @@ -36,11 +36,14 @@ declare var ASSET_SUFFIX: string declare var CROSS_ORIGIN: 'anonymous' | 'use-credentials' | null declare var WORKER_FORWARDED_GLOBALS: string[] -// Support runtime public path from window.publicPath +// Support runtime public path modes. function getRuntimeChunkBasePath(basePath: string = CHUNK_BASE_PATH): string { - if (CHUNK_BASE_PATH === '__RUNTIME_PUBLIC_PATH__') { + if (basePath === '__RUNTIME_PUBLIC_PATH__') { return contextPrototype.p() } + if (basePath === '__AUTO_PUBLIC_PATH__') { + return contextPrototype.p('auto') + } return basePath } diff --git a/turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime/runtime-types.d.ts b/turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime/runtime-types.d.ts index 650339ef6d97..7a59c75aed9e 100644 --- a/turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime/runtime-types.d.ts +++ b/turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime/runtime-types.d.ts @@ -104,7 +104,7 @@ type GetWorkerURL = ( shared: boolean ) => URL -type GetPublicPath = () => string +type GetPublicPath = (mode?: 'auto') => string type ExternalRequire = ( id: DependencySpecifier, diff --git a/turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime/runtime-utils.ts b/turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime/runtime-utils.ts index 8a1502cd4013..de52a66973cf 100644 --- a/turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime/runtime-utils.ts +++ b/turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime/runtime-utils.ts @@ -834,11 +834,53 @@ contextPrototype.z = requireStub // Make `globalThis` available to the module in a way that cannot be shadowed by a local variable. contextPrototype.g = globalThis +let cachedAutomaticPublicPath: string | undefined + +function getAutomaticPublicPath(): string { + if (cachedAutomaticPublicPath !== undefined) { + return cachedAutomaticPublicPath + } + + let scriptUrl: string | undefined + if (typeof document === 'object') { + const currentScript = document.currentScript as HTMLScriptElement | null + scriptUrl = currentScript?.src + + if (!scriptUrl) { + const scripts = document.getElementsByTagName('script') + const script = scripts[scripts.length - 1] + scriptUrl = script?.src + } + } + + if ( + !scriptUrl && + typeof (globalThis as any).importScripts === 'function' && + (globalThis as any).location + ) { + scriptUrl = String((globalThis as any).location) + } + + cachedAutomaticPublicPath = scriptUrl + ? scriptUrl + .replace(/^blob:/, '') + .replace(/#.*$/, '') + .replace(/\?.*$/, '') + .replace(/\/[^/]*$/, '/') + : '' + + return cachedAutomaticPublicPath +} + /** * Gets the public path for runtime assets. * Checks globalThis.publicPath and falls back to empty string. */ -function getPublicPath(): string { +function getPublicPath(mode?: 'auto'): string { + if (mode === 'auto') { + return getAutomaticPublicPath() + } + if ( typeof globalThis !== 'undefined' && typeof (globalThis as any).publicPath === 'string' diff --git a/turbopack/crates/turbopack-static/src/ecma.rs b/turbopack/crates/turbopack-static/src/ecma.rs index 3e3880524257..67f36179d4ff 100644 --- a/turbopack/crates/turbopack-static/src/ecma.rs +++ b/turbopack/crates/turbopack-static/src/ecma.rs @@ -117,6 +117,17 @@ impl EcmascriptChunkPlaceable for StaticUrlJsModule { } .cell()); } + if let Some(asset_path) = url.strip_prefix("__AUTO_PUBLIC_PATH__") { + let code = format!( + "{TURBOPACK_EXPORT_VALUE}({TURBOPACK_PUBLIC_PATH}(\"auto\") + {path});", + path = StringifyJs(asset_path) + ); + return Ok(EcmascriptChunkItemContent { + inner_code: code.into(), + ..Default::default() + } + .cell()); + } let url_behavior = chunking_context.url_behavior(this.tag.clone()).await?;