From c1d57680b18e7556683939ee0b8a0318ae72ba34 Mon Sep 17 00:00:00 2001 From: neverland Date: Wed, 8 Apr 2026 10:54:05 +0800 Subject: [PATCH 1/2] feat!: update default include regex --- README.md | 2 +- src/options.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f4486df..5e166d9 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ new ReactRefreshPlugin({ ### include - Type: [Rspack.RuleSetCondition](https://rspack.rs/config/module-rules#condition) -- Default: `/\.([cm]js|[jt]sx?|flow)$/i` +- Default: `/\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/` Explicitly includes files to be processed by the React Refresh loader. This option is passed to the `builtin:react-refresh-loader` as the `rule.include` condition. diff --git a/src/options.ts b/src/options.ts index 6a62c60..770c59b 100644 --- a/src/options.ts +++ b/src/options.ts @@ -13,7 +13,7 @@ export type PluginOptions = { * This option is passed to the `builtin:react-refresh-loader` as the `rule.include` condition. * Use this to limit processing to specific directories or file patterns. * Works identically to Rspack's `rule.include` option. - * @default /\.([cm]js|[jt]sx?|flow)$/i + * @default /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/ * @see https://rspack.rs/config/module-rules#rulesinclude */ include?: RuleSetCondition | null; @@ -94,7 +94,7 @@ export function normalizeOptions( options: PluginOptions, ): NormalizedPluginOptions { d(options, 'exclude', /node_modules/i); - d(options, 'include', /\.([cm]js|[jt]sx?|flow)$/i); + d(options, 'include', /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/); d(options, 'library'); d(options, 'forceEnable', false); d(options, 'injectLoader', true); From c4b4cf109cbf975fa4c908559ace8a25cfe8fede Mon Sep 17 00:00:00 2001 From: neverland Date: Wed, 8 Apr 2026 11:17:02 +0800 Subject: [PATCH 2/2] fix: preserve default extension filter when include is customized --- README.md | 4 +-- src/options.ts | 5 ++-- test/fixtures/include/index.js | 3 ++ test/fixtures/include/style.css | 3 ++ test/test.spec.ts | 53 ++++++++++++++++++++++----------- 5 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 test/fixtures/include/index.js create mode 100644 test/fixtures/include/style.css diff --git a/README.md b/README.md index 5e166d9..6900f35 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Compared to the previous approach, this method decouples the React Fast Refresh ### test - Type: [Rspack.RuleSetCondition](https://rspack.rs/config/module-rules#condition) -- Default: `undefined` +- Default: `/\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/` Specifies which files should be processed by the React Refresh loader. This option is passed to the `builtin:react-refresh-loader` as the `rule.test` condition. @@ -104,7 +104,7 @@ new ReactRefreshPlugin({ ### include - Type: [Rspack.RuleSetCondition](https://rspack.rs/config/module-rules#condition) -- Default: `/\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/` +- Default: `undefined` Explicitly includes files to be processed by the React Refresh loader. This option is passed to the `builtin:react-refresh-loader` as the `rule.include` condition. diff --git a/src/options.ts b/src/options.ts index 770c59b..6203c5f 100644 --- a/src/options.ts +++ b/src/options.ts @@ -5,6 +5,7 @@ export type PluginOptions = { * Specifies which files should be processed by the React Refresh loader. * This option is passed to the `builtin:react-refresh-loader` as the `rule.test` condition. * Works identically to Rspack's `rule.test` option. + * @default /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/ * @see https://rspack.rs/config/module-rules#rulestest */ test?: RuleSetCondition; @@ -13,7 +14,7 @@ export type PluginOptions = { * This option is passed to the `builtin:react-refresh-loader` as the `rule.include` condition. * Use this to limit processing to specific directories or file patterns. * Works identically to Rspack's `rule.include` option. - * @default /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/ + * @default undefined * @see https://rspack.rs/config/module-rules#rulesinclude */ include?: RuleSetCondition | null; @@ -93,8 +94,8 @@ const d = ( export function normalizeOptions( options: PluginOptions, ): NormalizedPluginOptions { + d(options, 'test', /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/); d(options, 'exclude', /node_modules/i); - d(options, 'include', /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)$/); d(options, 'library'); d(options, 'forceEnable', false); d(options, 'injectLoader', true); diff --git a/test/fixtures/include/index.js b/test/fixtures/include/index.js new file mode 100644 index 0000000..325598e --- /dev/null +++ b/test/fixtures/include/index.js @@ -0,0 +1,3 @@ +import './style.css'; + +export default 'include'; diff --git a/test/fixtures/include/style.css b/test/fixtures/include/style.css new file mode 100644 index 0000000..8579bef --- /dev/null +++ b/test/fixtures/include/style.css @@ -0,0 +1,3 @@ +.include { + color: red; +} diff --git a/test/test.spec.ts b/test/test.spec.ts index 8518255..8c66906 100644 --- a/test/test.spec.ts +++ b/test/test.spec.ts @@ -12,6 +12,7 @@ type Outputs = { fixture: string; runtime: string; vendor: string; + css?: string; }; type CompilationResult = { @@ -22,6 +23,10 @@ type CompilationResult = { }; const uniqueName = 'ReactRefreshLibrary'; +const readOutput = (fixturePath: string, file: string) => + fs.existsSync(path.join(fixturePath, 'dist', file)) + ? fs.readFileSync(path.join(fixturePath, 'dist', file), 'utf-8') + : ''; const compileWithReactRefresh = ( fixturePath: string, @@ -32,7 +37,9 @@ const compileWithReactRefresh = ( const cjsEntry = path.join(fixturePath, 'index.js'); const ctsEntry = path.join(fixturePath, 'index.cjs'); const mjsEntry = path.join(fixturePath, 'index.mjs'); - const customLoader = path.join(fixturePath, 'loader.cjs'); + const customLoader = fs.existsSync(path.join(fixturePath, 'loader.cjs')) + ? path.join(fixturePath, 'loader.cjs') + : path.join(import.meta.dirname, 'fixtures/loader/loader.cjs'); const entry = fs.existsSync(cjsEntry) ? cjsEntry : fs.existsSync(ctsEntry) @@ -52,6 +59,14 @@ const compileWithReactRefresh = ( uniqueName, assetModuleFilename: '[name][ext]', }, + module: { + rules: [ + { + test: /\.css$/, + type: 'css/auto', + }, + ], + }, resolveLoader: { alias: { 'custom-react-refresh-loader': customLoader, @@ -112,22 +127,11 @@ const compileWithReactRefresh = ( error, stats, outputs: { - reactRefresh: fs.readFileSync( - path.join(fixturePath, 'dist', 'react-refresh.js'), - 'utf-8', - ), - fixture: fs.readFileSync( - path.join(fixturePath, 'dist', 'fixture.js'), - 'utf-8', - ), - runtime: fs.readFileSync( - path.join(fixturePath, 'dist', 'runtime.js'), - 'utf-8', - ), - vendor: fs.readFileSync( - path.join(fixturePath, 'dist', 'vendor.js'), - 'utf-8', - ), + reactRefresh: readOutput(fixturePath, 'react-refresh.js'), + fixture: readOutput(fixturePath, 'fixture.js'), + runtime: readOutput(fixturePath, 'runtime.js'), + vendor: readOutput(fixturePath, 'vendor.js'), + css: readOutput(fixturePath, 'fixture.css') || undefined, }, plugin, }); @@ -301,4 +305,19 @@ describe('react-refresh-rspack-plugin', () => { expect(fixture).toContain('TEST_LOADER'); expect(fixture).not.toContain('function $RefreshReg$'); }); + + it('should keep the default extension filter when include targets a directory', async () => { + const { + outputs: { fixture, css }, + } = await compileWithReactRefresh( + path.join(import.meta.dirname, 'fixtures/include'), + { + include: path.join(import.meta.dirname, 'fixtures/include'), + reactRefreshLoader: 'custom-react-refresh-loader', + }, + ); + expect(fixture).toContain('TEST_LOADER'); + expect(css).toBeDefined(); + expect(css).not.toContain('TEST_LOADER'); + }); });