Skip to content

Commit 8eb8d66

Browse files
authored
feat(turbopack): support webpack like output.css_filename & output.asset_module_filename (#116)
1 parent 1e570f0 commit 8eb8d66

File tree

2 files changed

+72
-12
lines changed

2 files changed

+72
-12
lines changed

turbopack/crates/turbopack-browser/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ turbo-tasks-hash = { workspace = true }
3838
turbopack-core = { workspace = true }
3939
turbopack-ecmascript = { workspace = true }
4040
turbopack-ecmascript-runtime = { workspace = true }
41+
turbopack-css = { workspace = true }
4142
turbopack-resolve = { workspace = true }
4243

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

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use turbopack_core::{
3333
},
3434
output::{OutputAsset, OutputAssets},
3535
};
36+
use turbopack_css::chunk::{CssChunk, source_map::CssChunkSourceMapAsset};
3637
use turbopack_ecmascript::{
3738
async_chunk::module::AsyncLoaderModule,
3839
chunk::EcmascriptChunk,
@@ -257,6 +258,21 @@ impl BrowserChunkingContextBuilder {
257258
self
258259
}
259260

261+
pub fn css_filename(mut self, css_filename: RcStr) -> Self {
262+
self.chunking_context.css_filename = Some(css_filename);
263+
self
264+
}
265+
266+
pub fn css_chunk_filename(mut self, css_chunk_filename: RcStr) -> Self {
267+
self.chunking_context.css_chunk_filename = Some(css_chunk_filename);
268+
self
269+
}
270+
271+
pub fn asset_module_filename(mut self, asset_module_filename: RcStr) -> Self {
272+
self.chunking_context.asset_module_filename = Some(asset_module_filename);
273+
self
274+
}
275+
260276
pub fn chunk_loading_global(mut self, chunk_loading_global: RcStr) -> Self {
261277
self.chunking_context.chunk_loading_global = Some(chunk_loading_global);
262278
self
@@ -360,6 +376,12 @@ pub struct BrowserChunkingContext {
360376
filename: Option<RcStr>,
361377
/// Non evaluate chunk filename template
362378
chunk_filename: Option<RcStr>,
379+
/// Initial css chunk filename template
380+
css_filename: Option<RcStr>,
381+
/// Non initial css chunk filename template
382+
css_chunk_filename: Option<RcStr>,
383+
/// Asset module filename template
384+
asset_module_filename: Option<RcStr>,
363385
/// Expose entry module exports to global scope with the specified name.
364386
/// When set, all named exports from the entry module will be available on
365387
/// `window`/`globalThis` under the specified name.
@@ -418,6 +440,9 @@ impl BrowserChunkingContext {
418440
chunk_loading_global: Default::default(),
419441
filename: Default::default(),
420442
chunk_filename: Default::default(),
443+
css_filename: Default::default(),
444+
css_chunk_filename: Default::default(),
445+
asset_module_filename: Default::default(),
421446
entry_root_export: None,
422447
},
423448
}
@@ -630,10 +655,21 @@ impl ChunkingContext for BrowserChunkingContext {
630655
query.get("name").unwrap_or(output_name.as_str())
631656
};
632657

658+
let this = self.await?;
633659
let filename_template = if evaluate {
634-
self.await?.filename.clone()
660+
this.filename.clone()
635661
} else {
636-
self.await?.chunk_filename.clone()
662+
let resolved_asset = asset.to_resolved().await?;
663+
if ResolvedVc::try_downcast_type::<CssChunk>(resolved_asset).is_some()
664+
|| ResolvedVc::try_downcast_type::<CssChunkSourceMapAsset>(resolved_asset)
665+
.is_some()
666+
{
667+
// TODO: distinguash initial or non-initial css chunk, the non-initial css
668+
// chunk should use css_chunk_filename for template
669+
this.css_filename.clone()
670+
} else {
671+
this.chunk_filename.clone()
672+
}
637673
};
638674

639675
match filename_template {
@@ -730,16 +766,39 @@ impl ChunkingContext for BrowserChunkingContext {
730766
) -> Result<Vc<FileSystemPath>> {
731767
let source_path = original_asset_ident.path().await?;
732768
let basename = source_path.file_name();
733-
let asset_path = match source_path.extension_ref() {
734-
Some(ext) => format!(
735-
"{basename}.{content_hash}.{ext}",
736-
basename = &basename[..basename.len() - ext.len() - 1],
737-
content_hash = &content_hash[..8]
738-
),
739-
None => format!(
740-
"{basename}.{content_hash}",
741-
content_hash = &content_hash[..8]
742-
),
769+
770+
let asset_path = match &self.asset_module_filename {
771+
Some(filename_template) => {
772+
let mut filename = filename_template.to_string();
773+
774+
if match_name_placeholder(&filename) {
775+
filename = replace_name_placeholder(&filename, basename);
776+
}
777+
778+
if match_content_hash_placeholder(&filename) {
779+
filename = replace_content_hash_placeholder(&filename, &content_hash);
780+
};
781+
782+
if let Some(ext) = source_path.extension_ref() {
783+
if let Some((stem, _)) = filename.rsplit_once(".") {
784+
filename = stem.to_string();
785+
}
786+
filename = format!("{filename}.{ext}");
787+
}
788+
789+
filename
790+
}
791+
None => match source_path.extension_ref() {
792+
Some(ext) => format!(
793+
"{basename}.{content_hash}.{ext}",
794+
basename = &basename[..basename.len() - ext.len() - 1],
795+
content_hash = &content_hash[..8]
796+
),
797+
None => format!(
798+
"{basename}.{content_hash}",
799+
content_hash = &content_hash[..8]
800+
),
801+
},
743802
};
744803

745804
let asset_root_path = tag

0 commit comments

Comments
 (0)