Skip to content

feat: optimize dynamic entry facade chunks by merging with common chunks when they are captured by common chunks#7486

Merged
graphite-app[bot] merged 1 commit intomainfrom
12-11-feat_5276
Dec 22, 2025
Merged

feat: optimize dynamic entry facade chunks by merging with common chunks when they are captured by common chunks#7486
graphite-app[bot] merged 1 commit intomainfrom
12-11-feat_5276

Conversation

@IWANABETHATGUY
Copy link
Member

@IWANABETHATGUY IWANABETHATGUY commented Dec 14, 2025

related to #5726, #4905

Copy link
Member Author

IWANABETHATGUY commented Dec 14, 2025


How to use the Graphite Merge Queue

Add the label graphite: merge to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@netlify
Copy link

netlify bot commented Dec 14, 2025

Deploy Preview for rolldown-rs canceled.

Name Link
🔨 Latest commit 1eb6763
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/693e46b107ef3f0008f70eb7

@netlify
Copy link

netlify bot commented Dec 14, 2025

Deploy Preview for rolldown-rs canceled.

Name Link
🔨 Latest commit d4f0b36
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/6948d880012fe20008b675ea

@codspeed-hq
Copy link

codspeed-hq bot commented Dec 14, 2025

CodSpeed Performance Report

Merging #7486 will not alter performance

Comparing 12-11-feat_5276 (d4f0b36) with main (552e271)1

Summary

✅ 8 untouched

Footnotes

  1. No successful run was found on main (d4f0b36) during the generation of this report, so 552e271 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 14, 2025

Benchmarks Rust

group                                                        pr                                     target
-----                                                        --                                     ------
bundle/bundle@multi-duplicated-top-level-symbol              1.01     63.9±1.54ms        ? ?/sec    1.00     63.0±1.21ms        ? ?/sec
bundle/bundle@multi-duplicated-top-level-symbol-sourcemap    1.01     70.1±2.27ms        ? ?/sec    1.00     69.5±1.32ms        ? ?/sec
bundle/bundle@rome_ts                                        1.00    107.2±3.35ms        ? ?/sec    1.00    107.1±1.47ms        ? ?/sec
bundle/bundle@rome_ts-sourcemap                              1.00    119.5±1.92ms        ? ?/sec    1.00    119.9±1.46ms        ? ?/sec
bundle/bundle@threejs                                        1.00     39.2±0.56ms        ? ?/sec    1.00     39.2±0.88ms        ? ?/sec
bundle/bundle@threejs-sourcemap                              1.00     42.9±0.97ms        ? ?/sec    1.00     42.8±0.74ms        ? ?/sec
bundle/bundle@threejs10x                                     1.00    393.1±4.03ms        ? ?/sec    1.00    393.0±4.69ms        ? ?/sec
bundle/bundle@threejs10x-sourcemap                           1.00    452.2±3.20ms        ? ?/sec    1.00    452.7±3.82ms        ? ?/sec
scan/scan@rome_ts                                            1.00     84.3±2.48ms        ? ?/sec    1.00     84.2±2.26ms        ? ?/sec
scan/scan@threejs                                            1.01     28.8±1.67ms        ? ?/sec    1.00     28.6±1.06ms        ? ?/sec
scan/scan@threejs10x                                         1.00    294.6±3.55ms        ? ?/sec    1.00    294.9±4.05ms        ? ?/sec

@IWANABETHATGUY IWANABETHATGUY force-pushed the 12-11-feat_5276 branch 3 times, most recently from 00404a0 to a9c63e9 Compare December 17, 2025 09:28
@IWANABETHATGUY IWANABETHATGUY changed the base branch from main to graphite-base/7486 December 17, 2025 14:09
@IWANABETHATGUY IWANABETHATGUY changed the base branch from graphite-base/7486 to 12-17-refactor_make_treeshake_context.is_stmt_info_included_vec_to_inspect_if_a_stmt_info_is_included_after_linking December 17, 2025 14:10
graphite-app bot pushed a commit that referenced this pull request Dec 18, 2025
related to #7486, we need to update the symbol usage after linking stage when merge dynamic chunks to common chunk
IWANABETHATGUY added a commit that referenced this pull request Dec 18, 2025
related to #7486, we need to update the symbol usage after linking stage
when merge dynamic chunks to common chunk
@IWANABETHATGUY IWANABETHATGUY changed the base branch from 12-17-refactor_make_treeshake_context.is_stmt_info_included_vec_to_inspect_if_a_stmt_info_is_included_after_linking to graphite-base/7486 December 18, 2025 13:52
@IWANABETHATGUY IWANABETHATGUY changed the base branch from graphite-base/7486 to 12-18-refactor_use_meta_stmt_info_included_to_check_if_a_stmt_info_is_included December 18, 2025 13:52
@graphite-app graphite-app bot force-pushed the 12-18-refactor_use_meta_stmt_info_included_to_check_if_a_stmt_info_is_included branch 2 times, most recently from 8649da9 to 4883c75 Compare December 18, 2025 17:20
@IWANABETHATGUY IWANABETHATGUY changed the title feat: feat: optimize empty dynamic entry chunks by merging with common chunks Dec 21, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements an optimization for code splitting that addresses issue #5276. The optimization handles cases where dynamic entry chunks become empty after all their modules are moved to common chunks during advanced chunking. Instead of keeping empty entry chunks, the PR rewrites dynamic imports to extract the correct namespace from the common chunk and removes the empty chunks.

Key Changes

  • Introduces AST manipulation utilities to transform dynamic imports into .then(n => n.namespace) chains
  • Adds a SimulatedFacadeChunk tracking mechanism to properly handle namespace symbols without marking modules as included
  • Implements chunk merging optimization in optimize_facade_dynamic_entry_chunks that removes empty dynamic entry chunks and updates import references

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
crates/rolldown_ecmascript_utils/src/ast_snippet.rs Adds helper methods to generate arrow functions and call expressions for extracting properties from dynamic import results
crates/rolldown_common/src/types/module_namespace_included_reason.rs Adds SimulateFacadeChunk flag to track namespace inclusion for simulated facade chunks
crates/rolldown_common/src/ecmascript/symbol_id_ext.rs Adds module_namespace_symbol_ref helper method to construct namespace symbol references
crates/rolldown/src/types/linking_metadata.rs Adds utilities to extract and restore inclusion information from linking metadata for temporary modifications
crates/rolldown/src/stages/link_stage/tree_shaking/include_statements.rs Adds SimulatedFacadeChunk include reason and logic to skip module inclusion when only tracking namespace symbols
crates/rolldown/src/stages/link_stage/tree_shaking/mod.rs Exports tree-shaking types and functions needed by the generate stage
crates/rolldown/src/stages/link_stage/mod.rs Re-exports tree-shaking utilities and adds normal_symbol_exports_chain_map to link output
crates/rolldown/src/stages/generate_stage/chunk_optimizer.rs Implements the main optimization logic to merge empty dynamic entry chunks with their target common chunks
crates/rolldown/src/stages/generate_stage/code_splitting.rs Refactors entry initialization and integrates the chunk optimization into the splitting flow
crates/rolldown/src/stages/generate_stage/chunk_ext.rs Moves chunk reason type assignment to always execute, not just in debug mode
crates/rolldown/src/stages/generate_stage/compute_cross_chunk_links.rs Adds logic to export namespace symbols for merged facade chunks in common chunks
crates/rolldown/src/stages/generate_stage/render_chunk_to_assets.rs Filters out removed chunks during asset rendering
crates/rolldown/src/stages/generate_stage/mod.rs Passes used_symbol_refs to finalizer context for export filtering
crates/rolldown/src/module_finalizers/mod.rs Implements dynamic import transformation and filters namespace exports based on actually used symbols
crates/rolldown/src/module_finalizers/finalizer_context.rs Adds used_symbol_refs field to finalizer context
crates/rolldown/src/chunk_graph.rs Adds tracking for removed chunks and common chunks that export facade namespace symbols
crates/rolldown/tests/rolldown/code_splitting/issue_5276/* Adds comprehensive test case validating the optimization with multiple dynamic imports
crates/rolldown/tests/snapshots/integration_rolldown__filename_with_hash.snap Updates snapshot with new test output hashes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@IWANABETHATGUY IWANABETHATGUY changed the title feat: optimize empty dynamic entry chunks by merging with common chunks feat: optimize dynamic entry facade chunks by merging with common chunks when they are captured by common chunks Dec 21, 2025
Copilot AI review requested due to automatic review settings December 21, 2025 15:40
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 9 comments.

Comments suppressed due to low confidence (1)

crates/rolldown/src/stages/generate_stage/code_splitting.rs:715

  • The method signature changed from &self to &mut self to accommodate the call to optimize_facade_dynamic_entry_chunks which requires mutable access to self.link_output. While this works, consider whether optimize_facade_dynamic_entry_chunks could be refactored to take only the necessary mutable parts as parameters (similar to how init_entry_point takes parameters) rather than requiring &mut self. This would make the mutability requirements more explicit and the code easier to reason about.
  async fn split_chunks(
    &mut self,
    index_splitting_info: &mut IndexSplittingInfo,
    chunk_graph: &mut ChunkGraph,
    bits_to_chunk: &mut FxHashMap<BitSet, ChunkIdx>,
    input_base: &ArcStr,
  ) -> BuildResult<()> {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings December 21, 2025 16:05
Copy link
Contributor

Copilot AI commented Dec 21, 2025

@IWANABETHATGUY I've opened a new pull request, #7614, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings December 21, 2025 16:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@sapphi-red
Copy link
Member

I wonder if we can reuse the optimization for preserveEntrySignature: 'allow-extension' by treating all dynamic imports to have preserveEntrySignature: 'allow-extension'.

@IWANABETHATGUY
Copy link
Member Author

I wonder if we can reuse the optimization for preserveEntrySignature: 'allow-extension' by treating all dynamic imports to have preserveEntrySignature: 'allow-extension'.

try_insert_common_module_to_exist_chunk differs from optimize_facade_dynamic_entry_chunks.

The first focused on merging common chunks into a dynamic entry chunk, while the second focused on merging dynamic entry chunks into common chunks. The first focused on module assignment; it reduced chunks by pushing modules that should belong to a new common chunk into existing entry chunks, whereas the second focused on chunk merging (the module is already assigned).

Also, the first optimization did not involve any tree-shake status update. I split them up to improve code maintenance and make it easier to review.

I will try to merge the two-pass optimization into a single pass in the future.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Member Author

@sapphi-red I have addressed all the issues you raised. I am going to merge it to avoid further conflicts. Feel free to point out any other issues. I will fix them in future pr.

…nks when they are captured by common chunks (#7486)

related to #5726, #4905
@graphite-app
Copy link
Contributor

graphite-app bot commented Dec 22, 2025

Merge activity

This was referenced Dec 24, 2025
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.

5 participants