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', () => {