Skip to content

feat(turbopack): support webpack-like output.css_filename & output.as…#116

Merged
xusd320 merged 1 commit intoutoofrom
feat/output-filename-template
Feb 26, 2026
Merged

feat(turbopack): support webpack-like output.css_filename & output.as…#116
xusd320 merged 1 commit intoutoofrom
feat/output-filename-template

Conversation

@xusd320
Copy link

@xusd320 xusd320 commented Feb 26, 2026

This pull request enhances the BrowserChunkingContext in the turbopack-browser crate to provide more flexible and customizable filename templating for CSS and asset modules. The changes introduce new configuration options for specifying filename templates for initial and non-initial CSS chunks, as well as asset modules, and update logic to use these templates when generating output filenames.

The most important changes are:

Filename templating for CSS and asset modules:

  • Added new fields to BrowserChunkingContext for css_filename, css_chunk_filename, and asset_module_filename to allow custom filename templates for initial CSS chunks, non-initial CSS chunks, and asset modules, respectively.
  • Updated the chunk filename resolution logic to use the appropriate CSS filename template when emitting CSS chunks, and to use the asset module filename template when emitting asset modules. [1] [2] [3]

Builder API enhancements:

  • Added new builder methods (css_filename, css_chunk_filename, asset_module_filename) to BrowserChunkingContextBuilder for setting the new filename template fields.

Dependency updates:

  • Added turbopack-css as a dependency to enable CSS chunk detection and handling.
  • Imported necessary types from turbopack_css for CSS chunk handling.

Initialization and defaults:

  • Updated the Default implementation for BrowserChunkingContext to initialize the new filename template fields.

@gemini-code-assist
Copy link

Summary of Changes

Hello @xusd320, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances Turbopack's browser chunking context by introducing a more granular and configurable system for generating output filenames. It allows developers to define custom templates for initial CSS, non-initial CSS, and general asset modules, providing greater control over the output structure and aligning with more advanced bundling requirements.

Highlights

  • Filename Templating for CSS and Asset Modules: Introduced new configuration options (css_filename, css_chunk_filename, asset_module_filename) within BrowserChunkingContext to allow for flexible and customizable filename templating for initial CSS chunks, non-initial CSS chunks, and asset modules, respectively.
  • Builder API Enhancements: Added corresponding builder methods (css_filename, css_chunk_filename, asset_module_filename) to BrowserChunkingContextBuilder for easily setting the new filename template fields.
  • Output Path Resolution Logic Update: Modified the internal logic for resolving output paths to correctly apply the newly introduced CSS and asset module filename templates when generating output filenames for these specific asset types.
  • Dependency Update: Added turbopack-css as a new dependency to enable the detection and handling of CSS chunks within the turbopack-browser crate.
Changelog
  • turbopack/crates/turbopack-browser/Cargo.toml
    • Added turbopack-css as a new dependency to the project.
  • turbopack/crates/turbopack-browser/src/chunking_context.rs
    • Imported CssChunk and CssChunkSourceMapAsset types for CSS-related processing.
    • Extended BrowserChunkingContextBuilder with new methods (css_filename, css_chunk_filename, asset_module_filename) to configure filename templates.
    • Added css_filename, css_chunk_filename, and asset_module_filename fields to the BrowserChunkingContext struct to store filename templates.
    • Updated the Default implementation for BrowserChunkingContext to initialize the new filename template fields.
    • Modified the resolve_output_path function to conditionally use css_filename for initial CSS chunks, distinguishing them from other chunk types.
    • Updated the resolve_asset_path function to utilize the asset_module_filename template for generating paths for asset modules, supporting placeholders like [name] and [contenthash].
Activity
  • No specific activity (comments, reviews, etc.) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@xusd320 xusd320 changed the title feat(turbopack): support webpack like output.css_filename & output.as… feat(turbopack): support webpack-like output.css_filename & output.as… Feb 26, 2026
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces filename templating for CSS and asset modules, which is a great enhancement for customization. However, I've found a critical issue in the asset module filename generation that could lead to incorrect filenames and data loss (the content hash). Additionally, there are opportunities to improve the efficiency of type checking for CSS chunks and to complete the implementation for distinguishing between initial and non-initial CSS chunk filenames. My review includes suggestions to address these points.

Comment on lines +770 to +801
let asset_path = match &self.asset_module_filename {
Some(filename_template) => {
let mut filename = filename_template.to_string();

if match_name_placeholder(&filename) {
filename = replace_name_placeholder(&filename, basename);
}

if match_content_hash_placeholder(&filename) {
filename = replace_content_hash_placeholder(&filename, &content_hash);
};

if let Some(ext) = source_path.extension_ref() {
if let Some((stem, _)) = filename.rsplit_once(".") {
filename = stem.to_string();
}
filename = format!("{filename}.{ext}");
}

filename
}
None => match source_path.extension_ref() {
Some(ext) => format!(
"{basename}.{content_hash}.{ext}",
basename = &basename[..basename.len() - ext.len() - 1],
content_hash = &content_hash[..8]
),
None => format!(
"{basename}.{content_hash}",
content_hash = &content_hash[..8]
),
},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The current implementation for asset module filename templating has a critical flaw that can lead to incorrect filenames by removing the content hash.

  1. Incorrect [name] replacement: The basename passed to replace_name_placeholder includes the file extension. The [name] placeholder should represent the filename without the extension.
  2. Buggy extension handling: The logic at lines 782-787 unconditionally strips everything after the last dot. If the [contenthash] is placed after a dot in the template (e.g., [name].[contenthash]), the hash will be removed from the filename.

This suggested change fixes these issues by correctly extracting the filename stem for the [name] placeholder and removing the flawed extension-replacement logic. The template is now expected to define the full filename. A more robust long-term solution would be to support an [ext] placeholder.

        let asset_path = match &self.asset_module_filename {
            Some(filename_template) => {
                let name_part = source_path.file_stem().unwrap_or(basename);
                let mut filename = filename_template.to_string();

                if match_name_placeholder(&filename) {
                    filename = replace_name_placeholder(&filename, name_part);
                }

                if match_content_hash_placeholder(&filename) {
                    filename = replace_content_hash_placeholder(&filename, &content_hash);
                }

                filename
            }
            None => match source_path.extension_ref() {
                Some(ext) => format!(
                    "{basename}.{content_hash}.{ext}",
                    basename = &basename[..basename.len() - ext.len() - 1],
                    content_hash = &content_hash[..8]
                ),
                None => format!(
                    "{basename}.{content_hash}",
                    content_hash = &content_hash[..8]
                ),
            },

Comment on lines +662 to +672
let resolved_asset = asset.to_resolved().await?;
if ResolvedVc::try_downcast_type::<CssChunk>(resolved_asset).is_some()
|| ResolvedVc::try_downcast_type::<CssChunkSourceMapAsset>(resolved_asset)
.is_some()
{
// TODO: distinguash initial or non-initial css chunk, the non-initial css
// chunk should use css_chunk_filename for template
this.css_filename.clone()
} else {
this.chunk_filename.clone()
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This type check is inefficient because it requires resolving the Vc to a concrete asset via to_resolved().await? before checking its type. This can be optimized by using Vc::is::<T>(), which performs the type check without needing to resolve the full asset content, leading to better performance.

Consider refactoring to something like:

let is_css = asset.is::<CssChunk>().await?
    || asset.is::<CssChunkSourceMapAsset>().await?;
if is_css {
    // ...
} else {
    // ...
}

This would avoid the await on to_resolved() just for a type check.

Comment on lines +667 to +669
// TODO: distinguash initial or non-initial css chunk, the non-initial css
// chunk should use css_chunk_filename for template
this.css_filename.clone()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The implementation currently uses css_filename for all CSS chunks. However, the css_chunk_filename option was also introduced for non-initial CSS chunks but is not being used. The TODO comment acknowledges this. To complete this feature, logic to distinguish between initial and non-initial CSS chunks should be added to make use of css_chunk_filename as intended.

@xusd320 xusd320 merged commit 8eb8d66 into utoo Feb 26, 2026
12 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants