Skip to content

Commit 72ed19d

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 07a6e5b commit 72ed19d

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};
@@ -165,6 +169,16 @@ impl BrowserChunkingContextBuilder {
165169
self
166170
}
167171

172+
pub fn filename(mut self, filename: RcStr) -> Self {
173+
self.chunking_context.filename = Some(filename);
174+
self
175+
}
176+
177+
pub fn chunk_filename(mut self, chunk_filename: RcStr) -> Self {
178+
self.chunking_context.chunk_filename = Some(chunk_filename);
179+
self
180+
}
181+
168182
pub fn build(self) -> Vc<BrowserChunkingContext> {
169183
BrowserChunkingContext::cell(self.chunking_context)
170184
}
@@ -227,6 +241,10 @@ pub struct BrowserChunkingContext {
227241
module_id_strategy: ResolvedVc<Box<dyn ModuleIdStrategy>>,
228242
/// The chunking configs
229243
chunking_configs: Vec<(ResolvedVc<Box<dyn ChunkType>>, ChunkingConfig)>,
244+
/// Evaluate chunk filename template
245+
filename: Option<RcStr>,
246+
/// Non evaluate chunk filename template
247+
chunk_filename: Option<RcStr>,
230248
}
231249

232250
impl BrowserChunkingContext {
@@ -265,6 +283,8 @@ impl BrowserChunkingContext {
265283
manifest_chunks: false,
266284
module_id_strategy: ResolvedVc::upcast(DevModuleIdStrategy::new_resolved()),
267285
chunking_configs: Default::default(),
286+
filename: Default::default(),
287+
chunk_filename: Default::default(),
268288
},
269289
}
270290
}
@@ -410,32 +430,76 @@ impl ChunkingContext for BrowserChunkingContext {
410430
extension.starts_with("."),
411431
"`extension` should include the leading '.', got '{extension}'"
412432
);
413-
let root_path = self.chunk_root_path.clone();
414-
let name = match self.content_hashing {
415-
None => {
416-
ident
417-
.output_name(self.root_path.clone(), extension)
418-
.owned()
419-
.await?
420-
}
421-
Some(ContentHashing::Direct { length }) => {
422-
let Some(asset) = asset else {
423-
bail!("chunk_path requires an asset when content hashing is enabled");
433+
434+
let output_name = ident
435+
.output_name(self.root_path.clone(), extension.clone())
436+
.owned()
437+
.await?;
438+
439+
let mut filename = match asset {
440+
Some(asset) => {
441+
let ident = ident.await?;
442+
443+
let mut evaluate = false;
444+
let mut dev_chunk_list = false;
445+
ident.modifiers.iter().for_each(|m| {
446+
if m.contains("evaluate") {
447+
evaluate = true;
448+
}
449+
if m.contains("dev chunk list") {
450+
dev_chunk_list = true;
451+
}
452+
});
453+
let query = QString::from(ident.query.as_str());
454+
let name = if dev_chunk_list {
455+
output_name.as_str()
456+
} else {
457+
query.get("name").unwrap_or(output_name.as_str())
424458
};
425-
let content = asset.content().await?;
426-
if let AssetContent::File(file) = &*content {
427-
let hash = hash_xxh3_hash64(&file.await?);
428-
let length = length as usize;
429-
format!("{hash:0length$x}{extension}").into()
459+
460+
let filename_template = if evaluate {
461+
&self.filename
430462
} else {
431-
bail!(
432-
"chunk_path requires an asset with file content when content hashing is \
433-
enabled"
434-
);
463+
&self.chunk_filename
464+
};
465+
466+
match filename_template {
467+
Some(filename) => {
468+
let mut filename = filename.to_string();
469+
470+
if match_name_placeholder(&filename) {
471+
filename = replace_name_placeholder(&filename, name);
472+
}
473+
474+
if match_content_hash_placeholder(&filename) {
475+
let content = asset.content().await?;
476+
if let AssetContent::File(file) = &*content {
477+
let content_hash = hash_xxh3_hash64(&file.await?);
478+
filename = replace_content_hash_placeholder(
479+
&filename,
480+
&format!("{content_hash:016x}"),
481+
);
482+
} else {
483+
bail!(
484+
"chunk_path requires an asset with file content when content \
485+
hashing is enabled"
486+
);
487+
}
488+
};
489+
490+
filename
491+
}
492+
None => name.to_string(),
435493
}
436494
}
495+
None => output_name.to_string(),
437496
};
438-
Ok(root_path.join(&name)?.cell())
497+
498+
if !filename.ends_with(extension.as_str()) {
499+
filename.push_str(&extension);
500+
}
501+
502+
self.chunk_root_path.join(&filename).map(|p| p.cell())
439503
}
440504

441505
#[turbo_tasks::function]
@@ -715,3 +779,40 @@ impl ChunkingContext for BrowserChunkingContext {
715779
})
716780
}
717781
}
782+
783+
pub fn clean_separators(s: &str) -> String {
784+
static SEPARATOR_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r".*[/#?]").unwrap());
785+
SEPARATOR_REGEX.replace_all(s, "").to_string()
786+
}
787+
788+
static NAME_PLACEHOLDER_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\[name\]").unwrap());
789+
790+
pub fn match_name_placeholder(s: &str) -> bool {
791+
NAME_PLACEHOLDER_REGEX.is_match(s)
792+
}
793+
794+
pub fn replace_name_placeholder(s: &str, name: &str) -> String {
795+
NAME_PLACEHOLDER_REGEX.replace_all(s, name).to_string()
796+
}
797+
798+
static CONTENT_HASH_PLACEHOLDER_REGEX: LazyLock<Regex> =
799+
LazyLock::new(|| Regex::new(r"\[contenthash(?::(?P<len>\d+))?\]").unwrap());
800+
801+
pub fn match_content_hash_placeholder(s: &str) -> bool {
802+
CONTENT_HASH_PLACEHOLDER_REGEX.is_match(s)
803+
}
804+
805+
pub fn replace_content_hash_placeholder(s: &str, hash: &str) -> String {
806+
CONTENT_HASH_PLACEHOLDER_REGEX
807+
.replace_all(s, |caps: &regex::Captures| {
808+
let len = caps.name("len").map(|m| m.as_str()).unwrap_or("");
809+
let len = if len.is_empty() {
810+
hash.len()
811+
} else {
812+
len.parse().unwrap_or(hash.len())
813+
};
814+
let len = min(len, hash.len());
815+
hash[..len].to_string()
816+
})
817+
.to_string()
818+
}

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)