Skip to content

fix(plugin-react): respect hmr flag for refresh#2487

Merged
Yradex merged 2 commits intolynx-family:mainfrom
Yradex:wt/plugin-react-refresh-hmr-gate
Apr 21, 2026
Merged

fix(plugin-react): respect hmr flag for refresh#2487
Yradex merged 2 commits intolynx-family:mainfrom
Yradex:wt/plugin-react-refresh-hmr-gate

Conversation

@Yradex
Copy link
Copy Markdown
Collaborator

@Yradex Yradex commented Apr 21, 2026

Summary by CodeRabbit

  • Bug Fixes
    • React Refresh integration now correctly respects the dev.hmr: false configuration, ensuring the React Refresh loader is not injected when HMR is disabled.

Overview

  • dev.hmr: false already prevented the React refresh runtime entry from being prepended, but the React Refresh webpack integration was still installed in development builds.
  • This change makes the refresh loader and plugin follow the same HMR gate, so disabling HMR fully disables React Refresh integration.

Key Points

  • Guards both webpack and bundler chain refresh setup with environment.config.dev?.hmr !== false.
  • Adds coverage for the disabled-HMR case to ensure the refresh plugin and loader are not injected.
  • Keeps the existing development refresh behavior unchanged when HMR is enabled or omitted.

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7e301c24-a176-4a35-b110-8988a70f250d

📥 Commits

Reviewing files that changed from the base of the PR and between cffd0b1 and d4d8daf.

📒 Files selected for processing (3)
  • .changeset/fix-plugin-react-hmr-refresh.md
  • packages/rspeedy/plugin-react/src/refresh.ts
  • packages/rspeedy/plugin-react/test/refresh.test.ts

📝 Walkthrough

Walkthrough

This PR adds a conditional check to respect the dev.hmr: false configuration flag when applying React Refresh. When HMR is disabled, the React Refresh loader and plugin are no longer injected into the bundle. Changes include a changeset entry, updated refresh logic with environment configuration checks, and new test coverage.

Changes

Cohort / File(s) Summary
Changeset Entry
.changeset/fix-plugin-react-hmr-refresh.md
Added patch release note documenting that React Refresh installation now respects dev.hmr: false to avoid injecting refresh artifacts when HMR is disabled.
React Plugin Refresh Logic
packages/rspeedy/plugin-react/src/refresh.ts
Updated applyRefresh function to check environment.config.dev?.hmr !== false before applying React Refresh rules in both modifyWebpackChain and modifyBundlerChain hooks; expanded callback destructuring to access environment context.
Refresh Plugin Tests
packages/rspeedy/plugin-react/test/refresh.test.ts
Added new test case verifying that pluginReactLynx() excludes ReactRefreshRspackPlugin and its loader when HMR is disabled via rspeedyConfig.dev.hmr = false.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • PR #1756: Modifies the same refresh.ts logic for applying React Refresh callback parameters and control flow.
  • PR #1980: Similar changes to respect dev.hmr: false and prevent HMR-related runtime/refresh artifact injection.
  • PR #1882: Related implementation ensuring dev.hmr configuration is properly propagated into rsbuild's environment config.

Suggested labels

framework:React

Suggested reviewers

  • upupming
  • gaoachao

Poem

🐰 When HMR takes a break, so does Refresh,
No needless loaders cluttering the mesh,
A config flag brings harmony true,
React Refresh respects what's best for you! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(plugin-react): respect hmr flag for refresh' directly describes the main change: respecting the HMR flag in the React refresh plugin, which is the core objective of the entire changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 21, 2026

🦋 Changeset detected

Latest commit: d4d8daf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@lynx-js/react-rsbuild-plugin Patch
@lynx-js/react-alias-rsbuild-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Yradex Yradex marked this pull request as ready for review April 21, 2026 08:08
@Yradex Yradex requested a review from upupming as a code owner April 21, 2026 08:08
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 21, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 1 line in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
packages/rspeedy/plugin-react/src/refresh.ts 75.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 21, 2026

Merging this PR will improve performance by 17.21%

⚡ 2 improved benchmarks
✅ 79 untouched benchmarks
⏩ 26 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
002-hello-reactLynx-destroyBackground 896.6 µs 824.4 µs +8.76%
transform 1000 view elements 46.8 ms 39.9 ms +17.21%

Comparing Yradex:wt/plugin-react-refresh-hmr-gate (d4d8daf) with main (cffd0b1)

Open in CodSpeed

Footnotes

  1. 26 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Apr 21, 2026

React Example

#7445 Bundle Size — 224.28KiB (0%).

d4d8daf(current) vs cffd0b1 main#7440(baseline)

Bundle metrics  no changes
                 Current
#7445
     Baseline
#7440
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 0% 34.74%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 179 179
No change  Duplicate Modules 69 69
No change  Duplicate Code 44.5% 44.5%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#7445
     Baseline
#7440
No change  IMG 145.76KiB 145.76KiB
No change  Other 78.52KiB 78.52KiB

Bundle analysis reportBranch Yradex:wt/plugin-react-refresh-h...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Apr 21, 2026

Web Explorer

#9020 Bundle Size — 898.15KiB (0%).

d4d8daf(current) vs cffd0b1 main#9015(baseline)

Bundle metrics  no changes
                 Current
#9020
     Baseline
#9015
No change  Initial JS 44.47KiB 44.47KiB
No change  Initial CSS 2.22KiB 2.22KiB
No change  Cache Invalidation 0% 0%
No change  Chunks 9 9
No change  Assets 11 11
No change  Modules 230 230
No change  Duplicate Modules 11 11
No change  Duplicate Code 27.21% 27.21%
No change  Packages 10 10
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#9020
     Baseline
#9015
No change  JS 494.3KiB 494.3KiB
No change  Other 401.63KiB 401.63KiB
No change  CSS 2.22KiB 2.22KiB

Bundle analysis reportBranch Yradex:wt/plugin-react-refresh-h...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Apr 21, 2026

React External

#563 Bundle Size — 582.19KiB (0%).

d4d8daf(current) vs cffd0b1 main#558(baseline)

Bundle metrics  no changes
                 Current
#563
     Baseline
#558
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 0% 98.34%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 17 17
No change  Duplicate Modules 5 5
No change  Duplicate Code 8.59% 8.59%
No change  Packages 0 0
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#563
     Baseline
#558
No change  Other 582.19KiB 582.19KiB

Bundle analysis reportBranch Yradex:wt/plugin-react-refresh-h...Project dashboard


Generated by RelativeCIDocumentationReport issue

@relativeci
Copy link
Copy Markdown

relativeci Bot commented Apr 21, 2026

React MTF Example

#578 Bundle Size — 195.44KiB (0%).

d4d8daf(current) vs cffd0b1 main#573(baseline)

Bundle metrics  no changes
                 Current
#578
     Baseline
#573
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
Change  Cache Invalidation 0% 42.65%
No change  Chunks 0 0
No change  Assets 3 3
No change  Modules 173 173
No change  Duplicate Modules 66 66
No change  Duplicate Code 43.98% 43.98%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#578
     Baseline
#573
No change  IMG 111.23KiB 111.23KiB
No change  Other 84.2KiB 84.2KiB

Bundle analysis reportBranch Yradex:wt/plugin-react-refresh-h...Project dashboard


Generated by RelativeCIDocumentationReport issue

@Yradex Yradex enabled auto-merge (squash) April 21, 2026 08:32
@Yradex Yradex merged commit b5069a2 into lynx-family:main Apr 21, 2026
74 of 79 checks passed
@Yradex Yradex deleted the wt/plugin-react-refresh-hmr-gate branch April 21, 2026 08:37
colinaaa pushed a commit that referenced this pull request Apr 26, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @lynx-js/react@0.120.0

### Minor Changes

- Bump `@lynx-js/internal-preact` from `10.28.4-dfff9aa` to
`10.29.1-20260424024911-12b794f`
([diff](lynx-family/internal-preact@10.28.4-dfff9aa...10.29.1-20260424024911-12b794f)).
([#2512](#2512))

Fixes wrong DOM order when a keyed child moves to a different `$N` slot
across a re-render. Cross-slot moves now land at the correct slot
position instead of being appended past stable siblings.

- Refactor preact to support multi-slots children and reduce the number
and depth of snapshot.
([#1764](#1764))

### Patch Changes

- Fix stale callback-local references when transforming JSX inside
`children={array.map(...)}` prop expressions.
([#2524](#2524))

- Fix ref callbacks not being cleaned up or re-applied correctly when
the ref at the same element slot changes across rerenders that happen
before hydration (e.g. a `useEffect` triggering `setState` during the
initial background render).
([#2500](#2500))

- fix: reduce redundant updates for main-thread handlers and gestures
([#2188](#2188))

- Updates are faster when the main-thread event handler or gesture
object is stable across rerenders (fewer unnecessary native updates).
- Spread props rerenders that don't semantically change the
handler/gesture no longer trigger redundant updates.
- Removing a gesture from spread props reliably clears the gesture state
on the target element.

- Fix hydration edge cases by tolerating serialized snapshot nodes with
missing `values`
([#2481](#2481))

- Keep ReactLynx Testing Library imports aligned with the contained
snapshot runtime paths.
([#2498](#2498))

## @lynx-js/template-webpack-plugin@0.11.0

### Minor Changes

- Add CSS source map support and source-mapped template encode
diagnostics.
([#2483](#2483))

### Patch Changes

- fix: genStyleInfo should also preserve CSS variable fallback values
when encoding web-core stylesheets so declarations like `var(--token,
rgba(...))` are emitted with their fallback intact.
([#2502](#2502))

- Updated dependencies
\[[`e179680`](e179680),
[`8352530`](8352530),
[`30f0277`](30f0277),
[`887b8aa`](887b8aa),
[`1d4abfc`](1d4abfc),
[`25e196b`](25e196b),
[`fb7bc84`](fb7bc84),
[`9e149c4`](9e149c4),
[`30f0277`](30f0277),
[`9e149c4`](9e149c4)]:
    -   @lynx-js/css-serializer@0.1.6
    -   @lynx-js/web-core@0.20.3

## @lynx-js/i18next-translation-dedupe@0.0.1

### Patch Changes

- Introduce `@lynx-js/i18next-translation-dedupe` package to avoid
bundling i18next translations twice in Lynx apps.
([#2482](#2482))

The package reads translations extracted by
`rsbuild-plugin-i18next-extractor`, skips the extractor's default
rendered asset, and writes the translations into the Lynx bundle custom
section:

    ```json
    {
      "customSections": {
        "i18next-translations": {
          "content": {
            "en-US": {
              "hello": "Hello"
            },
            "zh-CN": {
              "hello": "你好"
            }
          }
        }
      }
    }
    ```

## @lynx-js/docs-mcp-server@0.2.2

### Patch Changes

- Fix Windows startup error.
([#2474](#2474))

## @lynx-js/react-umd@0.120.0

### Patch Changes

- Support compile main-thread script to bytecode in external bundle
([#2459](#2459))

## @lynx-js/rspeedy@0.14.3

### Patch Changes

- add a `sourceMap.css` option to emit CSS sourcemaps.
([#2442](#2442))

By default, `sourceMap.css` is false. You can set it to true to emit CSS
sourcemaps.

    ```js
    import { defineConfig } from "@lynx-js/rspeedy";

    export default defineConfig({
      output: {
        sourceMap: {
          css: true,
        },
      },
    });
    ```

- bump rsdoctor to 1.5.6
([#2410](#2410))

- Enable CSS source maps by default in Rspeedy output config.
([#2483](#2483))

- Prefer physical routable IPv4 addresses over tunnel and link-local
interfaces when resolving the dev host IP for generated preview and
bundle URLs.
([#2409](#2409))

-   Updated dependencies \[]:
    -   @lynx-js/web-rsbuild-server-middleware@0.20.3

## @lynx-js/lynx-bundle-rslib-config@0.3.2

### Patch Changes

- Support compile main-thread script to bytecode in external bundle
([#2459](#2459))

- Updated dependencies
\[[`e179680`](e179680)]:
    -   @lynx-js/css-serializer@0.1.6

## @lynx-js/react-rsbuild-plugin@0.16.1

### Patch Changes

- Respect `dev.hmr: false` when installing React Refresh integrations so
disabled HMR no longer injects the refresh loader or plugin.
([#2487](#2487))

- Fix stale callback-local references when transforming JSX inside
`children={array.map(...)}` prop expressions.
([#2524](#2524))

- Supports @lynx-js/react 0.120.0
([#1764](#1764))

- Updated dependencies
\[[`e179680`](e179680),
[`13655ac`](13655ac),
[`f15494b`](f15494b),
[`e179680`](e179680),
[`e179680`](e179680)]:
    -   @lynx-js/template-webpack-plugin@0.11.0
    -   @lynx-js/css-extract-webpack-plugin@0.7.1
    -   @lynx-js/react-webpack-plugin@0.9.2
    -   @lynx-js/react-alias-rsbuild-plugin@0.16.1
    -   @lynx-js/use-sync-external-store@1.5.0
    -   @lynx-js/react-refresh-webpack-plugin@0.3.5

## @lynx-js/css-serializer@0.1.6

### Patch Changes

- Add CSS source map support and source-mapped template encode
diagnostics.
([#2483](#2483))

## @lynx-js/web-core@0.20.3

### Patch Changes

- fix: `__AddClass` triggers style updates when `enableCSSSelector` is
`false` ([#2515](#2515))

`__AddClass` was missing the expected call to `update_css_og_style` when
CSS selectors are disabled (`enableCSSSelector: false`). With this fix,
dynamically adding a class correctly delegates style population from the
template AST into the DOM, mirroring the behavior of `__SetClasses`.

Added behavioral unit test and end-to-end playwright validations using
dynamically generated JSON AST `styleInfo` mocks.

- fix(web-core): skip setting lynxEntryNameAttribute for **Card** and
use constants for server element APIs
([#2510](#2510))

- Fix componentCSSID behavior for SSR and main thread by calculating
element css_id from parent component correctly.
([#2495](#2495))

- fix: avoid panic in dispatch_event_by_path when element data cannot be
retrieved ([#2508](#2508))

- fix: filter out -1 uniqueId in commonEventHandler
([#2493](#2493))

- feat: add x-markdown support
([#2412](#2412))

Add opt-in support for the `x-markdown` element on Lynx Web, including
Markdown rendering together with its related styling, interaction,
animation,
truncation, range rendering, and effect capabilities exposed through the
    component API.

Update the `web-core`, `web-core-wasm`, and `web-mainthread-apis`
runtime
paths to use the shared property-or-attribute setter from
`web-constants`, so
custom elements such as `x-markdown` can receive structured property
values
correctly instead of being forced through string-only attribute updates.

    ```javascript
    import "@lynx-js/web-elements/XMarkdown";
    ```

- fix: transformVH not work with cqw unit as the base length
([#2469](#2469))

- fix: add cardType resolution for legacy json lynx bundle
([#2510](#2510))

- fix: the default value of rpx is supposed to be 1/750 cqw
([#2469](#2469))

- Updated dependencies
\[[`e179680`](e179680),
[`647334c`](647334c),
[`fb7bc84`](fb7bc84),
[`9454dc4`](9454dc4),
[`bdec498`](bdec498),
[`b0247f9`](b0247f9),
[`eec539a`](eec539a)]:
    -   @lynx-js/css-serializer@0.1.6
    -   @lynx-js/web-elements@0.12.1
    -   @lynx-js/web-worker-rpc@0.20.3

## @lynx-js/web-elements@0.12.1

### Patch Changes

- fix: XMarkdown slot created should not have prefix
([#2520](#2520))

- feat: add x-markdown support
([#2412](#2412))

Add opt-in support for the `x-markdown` element on Lynx Web, including
Markdown rendering together with its related styling, interaction,
animation,
truncation, range rendering, and effect capabilities exposed through the
    component API.

Update the `web-core`, `web-core-wasm`, and `web-mainthread-apis`
runtime
paths to use the shared property-or-attribute setter from
`web-constants`, so
custom elements such as `x-markdown` can receive structured property
values
correctly instead of being forced through string-only attribute updates.

    ```javascript
    import "@lynx-js/web-elements/XMarkdown";
    ```

- fix: x-markdown inline view injection no longer queries light DOM
children when the content attribute changes. Consumers must now pre-set
`slot="{id}"` on the child element they want to project into
`inlineview://{id}`.
([#2516](#2516))

- fix: list cannot drag-scroll inside x-foldview-slot-ng
([#2507](#2507))

Cause: `touchstart` used `elementsFromPoint(pageX, pageY)` (expects
`clientX/clientY`), so hit-testing can miss the real inner scroller
(e.g. `x-list` shadow `#content`) when the document is scrolled.

Fix: use `elementsFromPoint(clientX, clientY)` + `event.composedPath()`
for Shadow DOM, and keep `previousPageX` updated during `touchmove`.

- fix: line-height of markdown-style should be added `px`
([#2509](#2509))

- fix: list `bindscrolltolower` may not trigger because the lower
threshold ([#2484](#2484))
    sentinel had no effective size or offset, causing the bottom
    `IntersectionObserver` to miss the list boundary

## @lynx-js/web-explorer@0.0.17

### Patch Changes

- bump rsdoctor to 1.5.6
([#2410](#2410))

## @lynx-js/css-extract-webpack-plugin@0.7.1

### Patch Changes

- Fix CSS source map line offsets when wrapping extracted CSS with cssId
metadata. ([#2514](#2514))

- Support `@lynx-js/template-webpack-plugin` v0.11.0.
([#2483](#2483))

## @lynx-js/react-webpack-plugin@0.9.2

### Patch Changes

- Support `@lynx-js/template-webpack-plugin` v0.11.0.
([#2483](#2483))

## create-rspeedy@0.14.3



## @lynx-js/react-alias-rsbuild-plugin@0.16.1



## upgrade-rspeedy@0.14.3



## @lynx-js/web-rsbuild-server-middleware@0.20.3



## @lynx-js/web-worker-rpc@0.20.3

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants