Skip to content

Comments

fix(hmr): rewrite import.meta.hot#4370

Merged
underfin merged 2 commits intomainfrom
04-29-fix_hmr_rewrite_import.meta.hot
Apr 30, 2025
Merged

fix(hmr): rewrite import.meta.hot#4370
underfin merged 2 commits intomainfrom
04-29-fix_hmr_rewrite_import.meta.hot

Conversation

@underfin
Copy link
Contributor

@underfin underfin commented Apr 29, 2025

Description

The import.meta.hot.invalidate is execute at hmr, The original import.meta.hot is dependent on the module execute order, it will break at import.meta.hot.invalidate.

import.meta.hot.accept(() => {
    // Trigger HMR in importers
    import.meta.hot.invalidate()
})

So the pr intend to fix it.

  • Init chunk, create a hot symbol to deconflict.
  • hmr chunk create a name ${reprname}_hot.
const main_hot = __rolldown_runtime__.createModuleHotContext("main.js");
main_hot.accept(() => {
    // Trigger HMR in importers
    main_hot.invalidate()
})

Copy link
Contributor Author

underfin commented Apr 29, 2025

@github-actions
Copy link
Contributor

github-actions bot commented Apr 29, 2025

Benchmarks Rust

  • target: main(9725513)
  • pr: 04-29-fix_hmr_rewrite_import.meta.hot(ca0c834)
group                                                               pr                                     target
-----                                                               --                                     ------
bundle/bundle@multi-duplicated-top-level-symbol                     1.00     75.6±1.91ms        ? ?/sec    1.01     76.0±1.13ms        ? ?/sec
bundle/bundle@multi-duplicated-top-level-symbol-minify              1.00     94.3±1.15ms        ? ?/sec    1.03     97.5±1.39ms        ? ?/sec
bundle/bundle@multi-duplicated-top-level-symbol-minify-sourcemap    1.00    108.2±1.63ms        ? ?/sec    1.02    110.4±3.12ms        ? ?/sec
bundle/bundle@multi-duplicated-top-level-symbol-sourcemap           1.00     84.3±1.19ms        ? ?/sec    1.02     86.1±1.66ms        ? ?/sec
bundle/bundle@rome-ts                                               1.01    121.1±1.81ms        ? ?/sec    1.00    119.4±1.42ms        ? ?/sec
bundle/bundle@rome-ts-minify                                        1.00    193.4±2.24ms        ? ?/sec    1.02    196.6±4.44ms        ? ?/sec
bundle/bundle@rome-ts-minify-sourcemap                              1.00    231.8±3.88ms        ? ?/sec    1.02    236.6±4.43ms        ? ?/sec
bundle/bundle@rome-ts-sourcemap                                     1.01    135.4±3.14ms        ? ?/sec    1.00    133.9±2.43ms        ? ?/sec
bundle/bundle@threejs                                               1.00     40.7±0.70ms        ? ?/sec    1.02     41.4±1.27ms        ? ?/sec
bundle/bundle@threejs-minify                                        1.00     83.7±0.62ms        ? ?/sec    1.00     83.6±1.35ms        ? ?/sec
bundle/bundle@threejs-minify-sourcemap                              1.00     98.8±0.47ms        ? ?/sec    1.00     98.4±0.66ms        ? ?/sec
bundle/bundle@threejs-sourcemap                                     1.00     47.6±0.52ms        ? ?/sec    1.00     47.7±0.33ms        ? ?/sec
bundle/bundle@threejs10x                                            1.01    427.7±7.31ms        ? ?/sec    1.00    424.6±3.31ms        ? ?/sec
bundle/bundle@threejs10x-minify                                     1.00   1051.0±9.25ms        ? ?/sec    1.00   1048.9±9.86ms        ? ?/sec
bundle/bundle@threejs10x-minify-sourcemap                           1.01  1244.6±12.67ms        ? ?/sec    1.00   1230.0±5.10ms        ? ?/sec
bundle/bundle@threejs10x-sourcemap                                  1.00    499.4±5.92ms        ? ?/sec    1.00    499.3±4.52ms        ? ?/sec
remapping/remapping                                                 1.00     27.2±0.11ms        ? ?/sec    1.02     27.8±0.24ms        ? ?/sec
remapping/render-chunk-remapping                                    1.05     70.4±3.80ms        ? ?/sec    1.00     66.8±0.98ms        ? ?/sec
scan/scan@rome-ts                                                   1.00     91.9±1.07ms        ? ?/sec    1.01     92.5±1.51ms        ? ?/sec
scan/scan@threejs                                                   1.05     33.1±4.24ms        ? ?/sec    1.00     31.6±0.54ms        ? ?/sec
scan/scan@threejs10x                                                1.00    311.2±3.21ms        ? ?/sec    1.02    317.0±3.21ms        ? ?/sec

Base automatically changed from 04-27-feat_hmr_handle_import.meta.hot to main April 30, 2025 02:44
@underfin underfin force-pushed the 04-29-fix_hmr_rewrite_import.meta.hot branch from 7f07380 to ca0c834 Compare April 30, 2025 03:13
@coderabbitai
Copy link

coderabbitai bot commented Apr 30, 2025

Walkthrough

This change introduces a new optional field, hmr_hot_ref, to several structs and workflows related to Hot Module Replacement (HMR) in the codebase. The field is conditionally initialized and propagated through the module scanning, view creation, finalization, and symbol deconfliction processes. Additionally, the handling of import.meta.hot is refactored to use a named constant variable instead of direct assignment, with new methods added to rewrite relevant AST expressions accordingly. These updates ensure consistent tracking and transformation of HMR-related references throughout the module lifecycle.

Changes

File(s) Change Summary
crates/rolldown/src/ast_scanner/mod.rs
crates/rolldown_common/src/ecmascript/ecma_view.rs
Added an optional hmr_hot_ref field to ScanResult and EcmaView structs. ScanResult's constructor now initializes this field based on HMR options.
crates/rolldown/src/ecmascript/ecma_module_view_factory.rs Updated create_ecma_view to extract and pass hmr_hot_ref from ScanResult into EcmaView.
crates/rolldown/src/hmr/hmr_ast_finalizer.rs
crates/rolldown/src/module_finalizers/scope_hoisting/hmr.rs
Refactored HMR initialization to declare a constant variable for import.meta.hot. Added methods to rewrite import.meta.hot expressions to use this variable.
crates/rolldown/src/module_finalizers/scope_hoisting/impl_visit_mut.rs Ensured rewrite_import_meta_hot is called on every visited expression in the ScopeHoistingFinalizer's visit_expression method.
crates/rolldown/src/module_loader/runtime_module_task.rs Added hmr_hot_ref field (initialized to None) to EcmaView in the NormalModule construction.
crates/rolldown/src/utils/chunk/deconflict_chunk_symbols.rs Ensured that hmr_hot_ref symbols are added to the renamer's root scope during chunk symbol deconfliction, if present in a module.

Sequence Diagram(s)

sequenceDiagram
    participant Options
    participant AstScanner
    participant ScanResult
    participant EcmaViewFactory
    participant EcmaView

    Options->>AstScanner: new(options)
    AstScanner->>ScanResult: scan()
    Note right of ScanResult: If HMR enabled,<br>initialize hmr_hot_ref
    EcmaViewFactory->>ScanResult: scan(ast)
    ScanResult->>EcmaViewFactory: { hmr_hot_ref, ... }
    EcmaViewFactory->>EcmaView: create({ hmr_hot_ref, ... })
Loading
sequenceDiagram
    participant HmrFinalizer
    participant AST
    participant Expr

    HmrFinalizer->>AST: visit_expression(expr)
    AST->>Expr: check import.meta.hot
    alt is import.meta.hot
        HmrFinalizer->>Expr: rewrite to hot_<module_name> variable
    end
Loading

Poem

In fields of code where hotness flows,
A bunny hops where HMR grows.
With hmr_hot_ref now in tow,
Each module’s warmth begins to show.
Constants declared, expressions rewrite,
The code hops forward, feeling light.
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9725513 and ca0c834.

⛔ Files ignored due to path filters (3)
  • crates/rolldown/tests/rolldown/issues/4129/artifacts.snap is excluded by !**/*.snap
  • crates/rolldown/tests/rolldown/topics/hmr/register_exports/artifacts.snap is excluded by !**/*.snap
  • crates/rolldown/tests/snapshots/integration_rolldown__filename_with_hash.snap is excluded by !**/*.snap
📒 Files selected for processing (8)
  • crates/rolldown/src/ast_scanner/mod.rs (3 hunks)
  • crates/rolldown/src/ecmascript/ecma_module_view_factory.rs (2 hunks)
  • crates/rolldown/src/hmr/hmr_ast_finalizer.rs (3 hunks)
  • crates/rolldown/src/module_finalizers/scope_hoisting/hmr.rs (1 hunks)
  • crates/rolldown/src/module_finalizers/scope_hoisting/impl_visit_mut.rs (1 hunks)
  • crates/rolldown/src/module_loader/runtime_module_task.rs (1 hunks)
  • crates/rolldown/src/utils/chunk/deconflict_chunk_symbols.rs (1 hunks)
  • crates/rolldown_common/src/ecmascript/ecma_view.rs (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
crates/rolldown/src/hmr/hmr_ast_finalizer.rs (2)
crates/rolldown_ecmascript_utils/src/quote.rs (1)
  • quote_stmt (34-38)
crates/rolldown/src/module_finalizers/scope_hoisting/hmr.rs (1)
  • rewrite_import_meta_hot (138-143)
⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: node-test (windows-latest) / Node Test
  • GitHub Check: node-test (ubuntu-latest) / Node Test
  • GitHub Check: node-test (macos-latest) / Node Test
  • GitHub Check: cargo-test (windows-latest) / Cargo Test
  • GitHub Check: cargo-test (ubuntu-latest) / Cargo Test
  • GitHub Check: cargo-test (macos-latest) / Cargo Test
  • GitHub Check: browser-test (windows-latest) / WASI Test
  • GitHub Check: browser-test (ubuntu-latest) / WASI Test
  • GitHub Check: browser-test (macos-latest) / WASI Test
  • GitHub Check: Codspeed Benchmark
  • GitHub Check: Benchmark Rust
  • GitHub Check: Benchmark Node
🔇 Additional comments (15)
crates/rolldown_common/src/ecmascript/ecma_view.rs (1)

105-105: Good addition of the hmr_hot_ref field to EcmaView

The new field provides a dedicated way to track HMR hot references throughout the module lifecycle, which is crucial for properly handling import.meta.hot rewriting and ensuring consistent symbol access during deconfliction.

crates/rolldown/src/module_loader/runtime_module_task.rs (1)

152-152: Properly initializing hmr_hot_ref to None

This correctly initializes the newly added field to match the struct definition. Since this is a runtime module, it makes sense to start with None and let the appropriate finalizers populate it if needed.

crates/rolldown/src/utils/chunk/deconflict_chunk_symbols.rs (1)

129-132: Good integration with symbol deconfliction

This change ensures that the hmr_hot_ref symbol is properly considered during the symbol deconfliction process. By adding it to the root scope renamer when present, the code guarantees that this symbol receives a conflict-free name in the output bundle. This is essential for the proper functioning of Hot Module Replacement.

crates/rolldown/src/module_finalizers/scope_hoisting/impl_visit_mut.rs (1)

317-317: Robust rewriting of import.meta.hot expressions

Adding the call to rewrite_import_meta_hot in the visit_expression method ensures that all occurrences of import.meta.hot are transformed into references to a constant variable. This addresses the core issue by removing the dependency on module execution order that was causing HMR failures.

The placement after other expression rewrites but before recursively walking the subtree is appropriate and ensures proper transformation order.

crates/rolldown/src/ecmascript/ecma_module_view_factory.rs (2)

72-72: Added new hmr_hot_ref field to ScanResult

This field will store a reference to the symbol used for Hot Module Replacement context. Good addition that complements the existing hmr_info field and supports the refactoring of import.meta.hot handling.


126-126: Passing hmr_hot_ref to EcmaView construction

Correctly propagates the HMR hot reference from the scan results to the EcmaView struct. This maintains consistent tracking of the HMR context reference throughout the module processing pipeline.

crates/rolldown/src/ast_scanner/mod.rs (3)

82-82: Added new hmr_hot_ref field to ScanResult struct

This field of type Option<SymbolRef> will store a reference to the hot module replacement context symbol, enabling consistent tracking of this symbol throughout the module lifecycle.


138-140: Conditionally creating HMR hot reference symbol

Creates a new symbol reference for the HMR hot context only when HMR is enabled. The symbol naming follows the same pattern as other module-specific symbols, ensuring consistency throughout the codebase.


168-168: Propagating hmr_hot_ref to ScanResult initialization

Correctly includes the newly created hmr_hot_ref symbol in the ScanResult initialization, ensuring it's available for subsequent stages of the compilation pipeline.

crates/rolldown/src/module_finalizers/scope_hoisting/hmr.rs (2)

126-133: Refactored HMR hot context initialization

Instead of directly assigning to import.meta.hot, the method now declares a constant variable using the canonical name of the hmr_hot_ref symbol. This change addresses the core issue with HMR by eliminating dependency on module execution order.

This implementation ensures that all references to import.meta.hot in the module will be consistently handled regardless of execution order.


138-143: Added method to rewrite import.meta.hot expressions

This new method rewrites any expression that matches import.meta.hot pattern with a reference to the canonical hot context variable. This approach ensures that all references to import.meta.hot use the same symbol, maintaining consistency and avoiding issues with module execution order.

The implementation is clean and straightforward, making it easy to understand and maintain.

crates/rolldown/src/hmr/hmr_ast_finalizer.rs (4)

35-36: Refactored HMR hot context variable naming

Changed the hot context variable to use a consistent naming scheme based on the module's representative name. This aligns with the overall approach to use a constant variable for the hot context instead of directly using import.meta.hot.


40-41: Updated format string to use named parameter

Using a named parameter in the format string ({hot_name}) improves readability and maintainability of the code. This is a nice improvement over concatenating or using positional parameters.


159-164: Added method to rewrite import.meta.hot expressions

This new method replaces expressions matching import.meta.hot with references to the hot context variable. The implementation is clean and follows the same pattern as the one in the scope hoisting finalizer, providing a consistent approach to handling hot module replacement references.


524-525: Added call to rewrite import.meta.hot expressions

This change ensures that all instances of import.meta.hot in the AST are correctly rewritten to use the constant hot context variable. This is a critical part of fixing the issue with HMR as mentioned in the PR description.

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@underfin underfin marked this pull request as ready for review April 30, 2025 03:13
@netlify
Copy link

netlify bot commented Apr 30, 2025

Deploy Preview for rolldown-rs canceled.

Name Link
🔨 Latest commit ca0c834
🔍 Latest deploy log https://app.netlify.com/sites/rolldown-rs/deploys/681195463542470008d9e42c

@underfin underfin enabled auto-merge April 30, 2025 03:13
@underfin underfin added this pull request to the merge queue Apr 30, 2025
Merged via the queue into main with commit 7b030ee Apr 30, 2025
33 checks passed
@underfin underfin deleted the 04-29-fix_hmr_rewrite_import.meta.hot branch April 30, 2025 05:22
github-merge-queue bot pushed a commit that referenced this pull request May 2, 2025
…sts (#4391)

<!-- Thank you for contributing! -->

### Description

- Closes: #4390 
- Related: #4370

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **Bug Fixes**
- Improved handling of hot module replacement to prevent potential
runtime errors when hot module references are missing.

- **Tests**
- Added new test files and configuration to verify correct behavior when
accessing hot module replacement features.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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