Skip to content

Commit 9b46ef7

Browse files
xusd320fireairforce
andcommitted
feat(turbopack): apply utoo patches to canary (#27)
* feat(turbopack): apply utoo patches to canary * chore: update external code --------- Co-authored-by: zoomdong <1344492820@qq.com>
1 parent 999035c commit 9b46ef7

File tree

13 files changed

+269
-111
lines changed

13 files changed

+269
-111
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/next/src/build/swc/generated-native.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function lightningCssTransformStyleAttribute(
2828

2929
/* auto-generated by NAPI-RS */
3030

31-
export declare class ExternalObject<T> {
31+
export class ExternalObject<T> {
3232
readonly '': {
3333
readonly '': unique symbol
3434
[K: symbol]: T

turbopack/crates/turbopack-browser/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ serde_json = { workspace = true }
2727
serde_qs = { workspace = true }
2828
tracing = { workspace = true }
2929
urlencoding = { workspace = true }
30-
30+
regex = { workspace = true }
31+
qstring = { workspace = true }
3132
turbo-rcstr = { workspace = true }
3233
turbo-tasks = { workspace = true }
3334
turbo-tasks-fs = { workspace = true }

turbopack/crates/turbopack-browser/src/chunking_context.rs

Lines changed: 122 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
use std::{cmp::min, sync::LazyLock};
2+
13
use anyhow::{Context, Result, bail};
4+
use qstring::QString;
5+
use regex::Regex;
26
use serde::{Deserialize, Serialize};
37
use tracing::Instrument;
48
use turbo_rcstr::{RcStr, rcstr};
@@ -174,6 +178,16 @@ impl BrowserChunkingContextBuilder {
174178
self
175179
}
176180

181+
pub fn filename(mut self, filename: RcStr) -> Self {
182+
self.chunking_context.filename = Some(filename);
183+
self
184+
}
185+
186+
pub fn chunk_filename(mut self, chunk_filename: RcStr) -> Self {
187+
self.chunking_context.chunk_filename = Some(chunk_filename);
188+
self
189+
}
190+
177191
pub fn build(self) -> Vc<BrowserChunkingContext> {
178192
BrowserChunkingContext::cell(self.chunking_context)
179193
}
@@ -238,6 +252,10 @@ pub struct BrowserChunkingContext {
238252
export_usage: Option<ResolvedVc<ExportUsageInfo>>,
239253
/// The chunking configs
240254
chunking_configs: Vec<(ResolvedVc<Box<dyn ChunkType>>, ChunkingConfig)>,
255+
/// Evaluate chunk filename template
256+
filename: Option<RcStr>,
257+
/// Non evaluate chunk filename template
258+
chunk_filename: Option<RcStr>,
241259
}
242260

243261
impl BrowserChunkingContext {
@@ -277,6 +295,8 @@ impl BrowserChunkingContext {
277295
module_id_strategy: ResolvedVc::upcast(DevModuleIdStrategy::new_resolved()),
278296
export_usage: None,
279297
chunking_configs: Default::default(),
298+
filename: Default::default(),
299+
chunk_filename: Default::default(),
280300
},
281301
}
282302
}
@@ -422,32 +442,76 @@ impl ChunkingContext for BrowserChunkingContext {
422442
extension.starts_with("."),
423443
"`extension` should include the leading '.', got '{extension}'"
424444
);
425-
let root_path = self.chunk_root_path.clone();
426-
let name = match self.content_hashing {
427-
None => {
428-
ident
429-
.output_name(self.root_path.clone(), extension)
430-
.owned()
431-
.await?
432-
}
433-
Some(ContentHashing::Direct { length }) => {
434-
let Some(asset) = asset else {
435-
bail!("chunk_path requires an asset when content hashing is enabled");
445+
446+
let output_name = ident
447+
.output_name(self.root_path.clone(), extension.clone())
448+
.owned()
449+
.await?;
450+
451+
let mut filename = match asset {
452+
Some(asset) => {
453+
let ident = ident.await?;
454+
455+
let mut evaluate = false;
456+
let mut dev_chunk_list = false;
457+
ident.modifiers.iter().for_each(|m| {
458+
if m.contains("evaluate") {
459+
evaluate = true;
460+
}
461+
if m.contains("dev chunk list") {
462+
dev_chunk_list = true;
463+
}
464+
});
465+
let query = QString::from(ident.query.as_str());
466+
let name = if dev_chunk_list {
467+
output_name.as_str()
468+
} else {
469+
query.get("name").unwrap_or(output_name.as_str())
436470
};
437-
let content = asset.content().await?;
438-
if let AssetContent::File(file) = &*content {
439-
let hash = hash_xxh3_hash64(&file.await?);
440-
let length = length as usize;
441-
format!("{hash:0length$x}{extension}").into()
471+
472+
let filename_template = if evaluate {
473+
&self.filename
442474
} else {
443-
bail!(
444-
"chunk_path requires an asset with file content when content hashing is \
445-
enabled"
446-
);
475+
&self.chunk_filename
476+
};
477+
478+
match filename_template {
479+
Some(filename) => {
480+
let mut filename = filename.to_string();
481+
482+
if match_name_placeholder(&filename) {
483+
filename = replace_name_placeholder(&filename, name);
484+
}
485+
486+
if match_content_hash_placeholder(&filename) {
487+
let content = asset.content().await?;
488+
if let AssetContent::File(file) = &*content {
489+
let content_hash = hash_xxh3_hash64(&file.await?);
490+
filename = replace_content_hash_placeholder(
491+
&filename,
492+
&format!("{content_hash:016x}"),
493+
);
494+
} else {
495+
bail!(
496+
"chunk_path requires an asset with file content when content \
497+
hashing is enabled"
498+
);
499+
}
500+
};
501+
502+
filename
503+
}
504+
None => name.to_string(),
447505
}
448506
}
507+
None => output_name.to_string(),
449508
};
450-
Ok(root_path.join(&name)?.cell())
509+
510+
if !filename.ends_with(extension.as_str()) {
511+
filename.push_str(&extension);
512+
}
513+
514+
self.chunk_root_path.join(&filename).map(|p| p.cell())
451515
}
452516

453517
#[turbo_tasks::function]
@@ -739,3 +803,40 @@ impl ChunkingContext for BrowserChunkingContext {
739803
}
740804
}
741805
}
806+
807+
pub fn clean_separators(s: &str) -> String {
808+
static SEPARATOR_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r".*[/#?]").unwrap());
809+
SEPARATOR_REGEX.replace_all(s, "").to_string()
810+
}
811+
812+
static NAME_PLACEHOLDER_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\[name\]").unwrap());
813+
814+
pub fn match_name_placeholder(s: &str) -> bool {
815+
NAME_PLACEHOLDER_REGEX.is_match(s)
816+
}
817+
818+
pub fn replace_name_placeholder(s: &str, name: &str) -> String {
819+
NAME_PLACEHOLDER_REGEX.replace_all(s, name).to_string()
820+
}
821+
822+
static CONTENT_HASH_PLACEHOLDER_REGEX: LazyLock<Regex> =
823+
LazyLock::new(|| Regex::new(r"\[contenthash(?::(?P<len>\d+))?\]").unwrap());
824+
825+
pub fn match_content_hash_placeholder(s: &str) -> bool {
826+
CONTENT_HASH_PLACEHOLDER_REGEX.is_match(s)
827+
}
828+
829+
pub fn replace_content_hash_placeholder(s: &str, hash: &str) -> String {
830+
CONTENT_HASH_PLACEHOLDER_REGEX
831+
.replace_all(s, |caps: &regex::Captures| {
832+
let len = caps.name("len").map(|m| m.as_str()).unwrap_or("");
833+
let len = if len.is_empty() {
834+
hash.len()
835+
} else {
836+
len.parse().unwrap_or(hash.len())
837+
};
838+
let len = min(len, hash.len());
839+
hash[..len].to_string()
840+
})
841+
.to_string()
842+
}

turbopack/crates/turbopack-browser/src/ecmascript/evaluate/chunk.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use crate::{
3636
/// * Contains the Turbopack browser runtime code; and
3737
/// * Evaluates a list of runtime entries.
3838
#[turbo_tasks::value(shared)]
39-
pub(crate) struct EcmascriptBrowserEvaluateChunk {
39+
pub struct EcmascriptBrowserEvaluateChunk {
4040
chunking_context: ResolvedVc<BrowserChunkingContext>,
4141
ident: ResolvedVc<AssetIdent>,
4242
other_chunks: ResolvedVc<OutputAssets>,
@@ -68,13 +68,33 @@ impl EcmascriptBrowserEvaluateChunk {
6868
}
6969

7070
#[turbo_tasks::function]
71-
async fn chunks_data(&self) -> Result<Vc<ChunksData>> {
71+
pub async fn chunks_data(&self) -> Result<Vc<ChunksData>> {
7272
Ok(ChunkData::from_assets(
7373
self.chunking_context.output_root().await?.clone_value(),
7474
*self.other_chunks,
7575
))
7676
}
7777

78+
#[turbo_tasks::function]
79+
pub fn ident(&self) -> Vc<AssetIdent> {
80+
*self.ident
81+
}
82+
83+
#[turbo_tasks::function]
84+
pub fn evaluatable_assets(&self) -> Vc<EvaluatableAssets> {
85+
*self.evaluatable_assets
86+
}
87+
88+
#[turbo_tasks::function]
89+
pub fn module_graph(&self) -> Vc<ModuleGraph> {
90+
*self.module_graph
91+
}
92+
93+
#[turbo_tasks::function]
94+
pub fn chunking_context(&self) -> Vc<Box<dyn ChunkingContext>> {
95+
Vc::upcast(*self.chunking_context)
96+
}
97+
7898
#[turbo_tasks::function]
7999
async fn code(self: Vc<Self>) -> Result<Vc<Code>> {
80100
let this = self.await?;

turbopack/crates/turbopack-browser/src/ecmascript/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ pub(crate) mod version;
99

1010
pub use chunk::EcmascriptBrowserChunk;
1111
pub use content::EcmascriptBrowserChunkContent;
12+
pub use evaluate::chunk::EcmascriptBrowserEvaluateChunk;

turbopack/crates/turbopack-browser/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![feature(arbitrary_self_types)]
44
#![feature(arbitrary_self_types_pointers)]
55

6-
pub(crate) mod chunking_context;
6+
pub mod chunking_context;
77
pub mod ecmascript;
88
pub mod react_refresh;
99

turbopack/crates/turbopack-core/src/ident.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,10 +415,10 @@ impl AssetIdent {
415415
// We need to make sure that `.json` and `.json.js` doesn't end up with the same
416416
// name. So when we add an extra extension when want to mark that with a "._"
417417
// suffix.
418-
if !removed_extension {
419-
name += "._";
420-
}
421-
name += &expected_extension;
418+
// if !removed_extension {
419+
// name += "._";
420+
// }
421+
// name += &expected_extension;
422422
Ok(Vc::cell(name.into()))
423423
}
424424
}
@@ -429,5 +429,5 @@ fn clean_separators(s: &str) -> String {
429429
}
430430

431431
fn clean_additional_extensions(s: &str) -> String {
432-
s.replace('.', "_")
432+
s.replace('.', "_").replace("[root-of-the-server]", "")
433433
}

0 commit comments

Comments
 (0)