From d6cf5e42ce16f16716bf33368f8d8865b357eee2 Mon Sep 17 00:00:00 2001 From: Qingyu Wang <40660121+colinaaa@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:28:22 +0800 Subject: [PATCH] fix(rspeedy/react): only inject hot clients on needed --- .changeset/cold-frogs-flash.md | 5 ++ packages/rspeedy/plugin-react/src/entry.ts | 45 +++++----- .../rspeedy/plugin-react/test/config.test.ts | 87 +++++++++++++++++++ 3 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 .changeset/cold-frogs-flash.md diff --git a/.changeset/cold-frogs-flash.md b/.changeset/cold-frogs-flash.md new file mode 100644 index 0000000000..040f6ef9df --- /dev/null +++ b/.changeset/cold-frogs-flash.md @@ -0,0 +1,5 @@ +--- +"@lynx-js/react-rsbuild-plugin": patch +--- + +Dev servers now honor `dev.hmr` and `dev.liveReload` when deciding whether to load hot clients. diff --git a/packages/rspeedy/plugin-react/src/entry.ts b/packages/rspeedy/plugin-react/src/entry.ts index 73d5889b42..8b667eee14 100644 --- a/packages/rspeedy/plugin-react/src/entry.ts +++ b/packages/rspeedy/plugin-react/src/entry.ts @@ -63,6 +63,8 @@ export function applyEntry( const isLynx = environment.name === 'lynx' const isWeb = environment.name === 'web' + const { hmr, liveReload } = environment.config.dev ?? {} + chain.entryPoints.clear() const mainThreadChunks: string[] = [] @@ -116,7 +118,7 @@ export function applyEntry( import: imports, filename: mainThreadName, }) - .when(isDev && !isWeb, entry => { + .when(isDev && !isWeb && hmr !== false, entry => { const require = createRequire(import.meta.url) // use prepend to make sure it does not affect the exports // from the entry @@ -137,25 +139,28 @@ export function applyEntry( }) // in standalone lazy bundle mode, we do not add // other entries to avoid wrongly exporting from other entries - .when(isDev && !isWeb, entry => { - // use prepend to make sure it does not affect the exports - // from the entry - entry - // This is aliased in `@lynx-js/rspeedy` - .prepend({ - layer: LAYERS.BACKGROUND, - import: '@rspack/core/hot/dev-server', - }) - .prepend({ - layer: LAYERS.BACKGROUND, - import: '@lynx-js/webpack-dev-transport/client', - }) - // This is aliased in `./refresh.ts` - .prepend({ - layer: LAYERS.BACKGROUND, - import: '@lynx-js/react/refresh', - }) - }) + .when( + isDev && !isWeb && !(hmr === false && liveReload === false), + entry => { + // use prepend to make sure it does not affect the exports + // from the entry + entry + // This is aliased in `@lynx-js/rspeedy` + .prepend({ + layer: LAYERS.BACKGROUND, + import: '@rspack/core/hot/dev-server', + }) + .prepend({ + layer: LAYERS.BACKGROUND, + import: '@lynx-js/webpack-dev-transport/client', + }) + // This is aliased in `./refresh.ts` + .prepend({ + layer: LAYERS.BACKGROUND, + import: '@lynx-js/react/refresh', + }) + }, + ) .end() .plugin(`${PLUGIN_NAME_TEMPLATE}-${entryName}`) .use(LynxTemplatePlugin, [{ diff --git a/packages/rspeedy/plugin-react/test/config.test.ts b/packages/rspeedy/plugin-react/test/config.test.ts index 172e5f58ac..548237dd03 100644 --- a/packages/rspeedy/plugin-react/test/config.test.ts +++ b/packages/rspeedy/plugin-react/test/config.test.ts @@ -1422,6 +1422,93 @@ describe('Config', () => { } `) }) + + test('disables hot clients when hmr and liveReload are false', async () => { + vi.stubEnv('NODE_ENV', 'development') + const { pluginReactLynx } = await import('../src/pluginReactLynx.js') + + const hmrOffConfig = { + hmr: false, + liveReload: false, + } as const + + const rsbuild = await createRspeedy({ + rspeedyConfig: { + source: { + entry: { + main: './fixtures/basic.tsx', + }, + }, + environments: { + lynx: { + dev: hmrOffConfig, + }, + }, + plugins: [ + pluginReactLynx(), + pluginStubRspeedyAPI(), + ], + }, + }) + + const [config] = await rsbuild.initConfigs() + + if (!config?.entry) { + expect.fail('should have config.entry') + } + + const entry = config.entry as Record + expect(entry['main']?.import).toEqual([ + './fixtures/basic.tsx', + ]) + expect(entry['main__main-thread']?.import).toEqual([ + './fixtures/basic.tsx', + ]) + }) + + test('disables css hmr when hmr is false but keeps live reload', async () => { + vi.stubEnv('NODE_ENV', 'development') + const { pluginReactLynx } = await import('../src/pluginReactLynx.js') + + const rsbuild = await createRspeedy({ + rspeedyConfig: { + source: { + entry: { + main: './fixtures/basic.tsx', + }, + }, + environments: { + lynx: { + dev: { + hmr: false, + liveReload: true, + }, + }, + }, + plugins: [ + pluginReactLynx(), + pluginStubRspeedyAPI(), + ], + }, + }) + + const [config] = await rsbuild.initConfigs() + + if (!config?.entry) { + expect.fail('should have config.entry') + } + + const entry = config.entry as Record + expect(entry['main']?.import).toEqual([ + '@lynx-js/react/refresh', + '@lynx-js/webpack-dev-transport/client', + '@rspack/core/hot/dev-server', + './fixtures/basic.tsx', + ]) + expect(entry['main__main-thread']?.import).toEqual([ + './fixtures/basic.tsx', + ]) + }) }) describe('Output SourceMap', () => {