fix!: preserve default extension filter when include is customized#100
fix!: preserve default extension filter when include is customized#100chenjiahan merged 3 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes an option interaction in @rspack/plugin-react-refresh where overriding include with a directory unintentionally removed the default “script extensions only” guard, allowing non-script assets (e.g., CSS) to be processed by the React Refresh loader.
Changes:
- Move the default script-extension matcher to
testand leaveincludeunset by default. - Update option documentation in
src/options.tsandREADME.mdto reflect the new defaults. - Add a regression test fixture importing CSS and a test ensuring CSS isn’t instrumented even when
includetargets a directory.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| test/test.spec.ts | Adds CSS handling to the test harness and a regression test for directory-based include. |
| test/fixtures/include/style.css | New CSS asset used to validate exclusion from React Refresh instrumentation. |
| test/fixtures/include/index.js | Imports the CSS asset to ensure it participates in the build graph. |
| src/options.ts | Updates defaults so the extension filter lives on test instead of include. |
| README.md | Updates documented defaults for test and include. |
Comments suppressed due to low confidence (2)
test/test.spec.ts:35
readOutput()returns an empty string when an output file is missing, and it’s now used for required bundles (react-refresh.js/fixture.js/runtime.js/vendor.js). This can cause multiple existing assertions (e.g.expect(vendor).not.toContain(...)) to pass even if the bundle wasn’t emitted, and it can also mask stale files ifdist/isn’t cleaned between compiles. Consider keeping strict reads (throw/fail) for required outputs and only using a safe/optional read for the CSS output, and/or removedist/(or read fromstatsassets) before each compilation to ensure outputs are from the current run.
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,
refreshOptions: PluginOptions,
): Promise<CompilationResult> =>
new Promise((resolve, reject) => {
src/options.ts:105
normalizeOptions()no longer sets a default forinclude, but the function still returnsoptions as NormalizedPluginOptionswhereNormalizedPluginOptions = Required<PluginOptions>. This makes the normalized type claimincludecan’t beundefined, even though it can be when callers omit it. Please adjust the normalized type (or the normalization logic) soincludeis correctly typed as possiblyundefined, and avoid relying on non-null assertions forincludedownstream.
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, 'library');
d(options, 'forceEnable', false);
d(options, 'injectLoader', true);
d(options, 'injectEntry', true);
d(options, 'reloadOnRuntimeErrors', false);
d(options, 'reactRefreshLoader', 'builtin:react-refresh-loader');
return options as NormalizedPluginOptions;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6d7661eb96
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
When users override
includewith a directory such assrc, the plugin currently drops its default script-extension guard because that guard lives onincludeitself. That makes the React Refresh loader eligible for non-script files imported from the same directory, so CSS and other assets can be instrumented unexpectedly.This PR moves the default script extension matcher to
test, leavesincludeunset by default, updates the option docs, and adds a regression test that verifies CSS is still excluded whenincludepoints at a directory.Related Links