From 0d8764ada800d2c6276f4a222e022bea0df04509 Mon Sep 17 00:00:00 2001 From: fireairforce <1344492820@qq.com> Date: Tue, 20 Jan 2026 11:07:17 +0800 Subject: [PATCH] chore: compitable --- crates/pack-api/src/project.rs | 51 +++++++++++++++++----------- crates/pack-api/src/source_map.rs | 56 ++++++++++++++++++++----------- crates/pack-core/src/util.rs | 30 +++++++++++++++-- 3 files changed, 95 insertions(+), 42 deletions(-) diff --git a/crates/pack-api/src/project.rs b/crates/pack-api/src/project.rs index 606f30916..e5ef69e4c 100644 --- a/crates/pack-api/src/project.rs +++ b/crates/pack-api/src/project.rs @@ -6,12 +6,12 @@ use pack_core::{ config::{Config, ModuleIds as ModuleIdStrategyConfig}, emit_assets, mode::Mode, - util::{Runtime, convert_to_project_relative}, + util::{Runtime, convert_to_project_relative, strip_leading_separator, to_unix_path}, }; use serde::Deserialize; use std::{ fs, - path::{MAIN_SEPARATOR, Path, PathBuf}, + path::{Path, PathBuf}, time::Duration, }; use tracing::Instrument; @@ -25,7 +25,7 @@ use turbo_tasks_fs::{ DirectoryContent, DirectoryEntry, DiskFileSystem, FileContent, FileSystem, FileSystemEntryType, FileSystemPath, VirtualFileSystem, invalidation, }; -use turbo_unix_path::normalize_path; +use turbo_unix_path::{join_path, normalize_path, unix_to_sys}; use turbopack::global_module_ids::get_global_module_id_strategy; use turbopack_core::{ file_source::FileSource, @@ -584,7 +584,7 @@ impl Project { if self.pack_path.starts_with(&*self.root_path) { let relative_pack_path = self.pack_path.strip_prefix(&*self.root_path).unwrap(); - let relative_pack_path = relative_pack_path.trim_start_matches(MAIN_SEPARATOR); + let relative_pack_path = strip_leading_separator(relative_pack_path); let turbopack_path = Path::new(relative_pack_path).join(".turbopack"); if let Some(path_str) = turbopack_path.to_str() { let turbopack_path_normalized = @@ -619,6 +619,24 @@ impl Project { DiskFileSystem::new(rcstr!("output"), self.root_path.clone()) } + #[turbo_tasks::function] + pub async fn dist_dir_absolute(self: Vc) -> Result> { + let this = self.await?; + let dist_dir = self.dist_dir().await?; + Ok(Vc::cell( + format!( + "{}{}{}", + this.root_path, + std::path::MAIN_SEPARATOR, + unix_to_sys( + &join_path(&this.project_path, dist_dir.as_str()) + .context("expected project_path to be inside of root_path")? + ) + ) + .into(), + )) + } + #[turbo_tasks::function] pub async fn project_root(self: Vc) -> Result> { Ok(self.project_fs(self.dist_dir()).root()) @@ -635,10 +653,14 @@ impl Project { .clone() .unwrap_or("dist".into()); - let relative_dist_path = convert_to_project_relative(&dist_path, &this.project_path)?; - let relative_dist_path = relative_dist_path + let mut relative_dist_path = convert_to_project_relative(&dist_path, &this.project_path)?; + // Strip "./" or ".\" prefix before converting to unix path (Windows compatibility) + relative_dist_path = relative_dist_path .strip_prefix("./") - .unwrap_or(&relative_dist_path); + .or_else(|| relative_dist_path.strip_prefix(".\\")) + .unwrap_or(&relative_dist_path) + .into(); + let relative_dist_path = to_unix_path(&relative_dist_path); Ok(Vc::cell(relative_dist_path.into())) } @@ -651,10 +673,7 @@ impl Project { } else { "./" }; - let pack_relative = pack_relative - .strip_prefix(MAIN_SEPARATOR) - .unwrap_or(pack_relative) - .replace(MAIN_SEPARATOR, "/"); + let pack_relative = to_unix_path(strip_leading_separator(pack_relative)); Ok(self .output_fs() @@ -671,10 +690,7 @@ impl Project { let dist_dir = self.dist_dir().await?; let project_relative = this.project_path.strip_prefix(&*this.root_path).unwrap(); - let project_relative = project_relative - .strip_prefix(MAIN_SEPARATOR) - .unwrap_or(project_relative) - .replace(MAIN_SEPARATOR, "/"); + let project_relative = to_unix_path(strip_leading_separator(project_relative)); Ok(self .output_fs() @@ -705,10 +721,7 @@ impl Project { let this = self.await?; let root = self.project_root().await?; let project_relative = this.project_path.strip_prefix(&*this.root_path).unwrap(); - let project_relative = project_relative - .strip_prefix(MAIN_SEPARATOR) - .unwrap_or(project_relative) - .replace(MAIN_SEPARATOR, "/"); + let project_relative = to_unix_path(strip_leading_separator(project_relative)); Ok(root.join(&project_relative)?.cell()) } diff --git a/crates/pack-api/src/source_map.rs b/crates/pack-api/src/source_map.rs index 656098d04..75ba6d2af 100644 --- a/crates/pack-api/src/source_map.rs +++ b/crates/pack-api/src/source_map.rs @@ -2,6 +2,7 @@ use anyhow::{Result, bail}; use turbo_rcstr::RcStr; use turbo_tasks::Vc; use turbo_tasks_fs::FileContent; +use turbo_unix_path::sys_to_unix; use url::Url; use crate::project::ProjectContainer; @@ -9,12 +10,21 @@ use crate::project::ProjectContainer; #[turbo_tasks::function] pub async fn get_source_map_rope( container: Vc, - file_path: RcStr, + source_url: RcStr, ) -> Result> { - let (file, module) = match Url::parse(&file_path) { + let (file_path_sys, module) = match Url::parse(&source_url) { Ok(url) => match url.scheme() { "file" => { - let path = urlencoding::decode(url.path())?.to_string(); + #[cfg(not(all(target_family = "wasm", target_os = "unknown")))] + let path: String = match url.to_file_path() { + Ok(path) => path.to_string_lossy().into(), + Err(_) => { + bail!("Failed to convert file URL to file path: {url}"); + } + }; + #[cfg(all(target_family = "wasm", target_os = "unknown"))] + let path: String = urlencoding::decode(url.path())?.into_owned(); + let module = url.query_pairs().find(|(k, _)| k == "id"); ( path, @@ -24,36 +34,42 @@ pub async fn get_source_map_rope( }, ) } - _ => bail!("Unknown url scheme"), + _ => bail!("Unknown url scheme '{}'", url.scheme()), }, - Err(_) => (file_path.to_string(), None), + Err(_) => (source_url.to_string(), None), }; - let Some(chunk_base) = file.strip_prefix( - &(format!( - "{}/{}/", - container.project().await?.project_path, - container.project().dist_dir().await? - )), - ) else { - // File doesn't exist within the dist dir - return Ok(FileContent::NotFound.cell()); - }; + let chunk_base_unix = + match file_path_sys.strip_prefix(container.project().dist_dir_absolute().await?.as_str()) { + Some(relative_path) => sys_to_unix(relative_path), + None => { + // File doesn't exist within the dist dir + return Ok(FileContent::NotFound.cell()); + } + }; - let server_path = container.project().node_root().await?.join(chunk_base)?; + let server_path = container + .project() + .node_root() + .await? + .join(&chunk_base_unix)?; - let client_path = container.project().client_root().await?.join(chunk_base)?; + let client_path = container + .project() + .client_root() + .await? + .join(&chunk_base_unix)?; let mut map = container.get_source_map(server_path, module.clone()); - if map.await?.is_content() { + if !map.await?.is_content() { // If the chunk doesn't exist as a server chunk, try a client chunk. // TODO: Properly tag all server chunks and use the `isServer` query param. // Currently, this is inaccurate as it does not cover RSC server // chunks. map = container.get_source_map(client_path, module); - if map.await?.is_content() { - bail!("chunk/module '{}' is missing a sourcemap", file_path); + if !map.await?.is_content() { + bail!("chunk/module '{}' is missing a sourcemap", source_url); } } diff --git a/crates/pack-core/src/util.rs b/crates/pack-core/src/util.rs index d1a94573b..9d1afbf7e 100644 --- a/crates/pack-core/src/util.rs +++ b/crates/pack-core/src/util.rs @@ -1,8 +1,9 @@ -use std::path::{MAIN_SEPARATOR, Path}; +use std::{borrow::Cow, path::Path, sync::LazyLock}; use anyhow::{Context, Result}; use bincode::{Decode, Encode}; use dunce::{canonicalize, simplified}; +use regex::Regex; use serde::Deserialize; use turbo_rcstr::RcStr; use turbo_tasks::{NonLocalValue, TaskInput, Vc, trace::TraceRawVcs}; @@ -11,6 +12,29 @@ use turbopack::{condition::ContextCondition, module_options::RuleCondition}; use crate::config::Config; +static WINDOWS_PATH: LazyLock = + LazyLock::new(|| Regex::new(r"^[A-Za-z]:[/\\]|^\\\\").unwrap()); + +pub fn is_absolute_path(path: &str) -> bool { + if Path::new(path).is_absolute() { + return true; + } + + WINDOWS_PATH.is_match(path) +} + +pub fn to_unix_path(path: &str) -> Cow<'_, str> { + if path.contains('\\') { + Cow::Owned(path.replace('\\', "/")) + } else { + Cow::Borrowed(path) + } +} + +pub fn strip_leading_separator(path: &str) -> &str { + path.trim_start_matches(['/', '\\']) +} + #[derive( Default, PartialEq, @@ -91,10 +115,10 @@ pub async fn internal_assets_conditions() -> Result { } pub fn convert_to_project_relative(project_inside_path: &str, project_path: &str) -> Result { - if project_inside_path.starts_with(MAIN_SEPARATOR) { + if is_absolute_path(project_inside_path) { pathdiff::diff_paths( simplified(Path::new(project_inside_path)), - canonicalize(if project_path.starts_with(MAIN_SEPARATOR) { + canonicalize(if is_absolute_path(project_path) { project_path.into() } else { let current_dir = std::env::current_dir().unwrap();