react-refresh-webpack-plugin
react-refresh-webpack-plugin copied to clipboard
feat: acceptSelf
Problem
The runtime hot.accepts a refreshed module unconditionally, however in advanced circumstances it might be desired for the HMR invalidation to propagate up to a parent watching for changes. Currently, attempts to accept from any parent fail.
In order to allow parents to monitor the context for changes, this PR adds a new option to the plugin: acceptSelf.
Example use-case
Watching a require.context ID for changes:
const context = require.context('./my-components');
module.hot.accept(context.id, () => {
// Unreachable
});
// Even e.g. this will never work:
require.cache[context.id].hot.accept(context.resolve(context.keys()[0]), () => {
// Still unreachable
});
New documentation
acceptSelf
Type: boolean
Default: undefined
Determines whether a module that is refreshed will self-accept.
- If
acceptSelfis not provided ortrue, the refreshed module will be self-accept()ed. - If
acceptSelfisfalse, the refreshed module will not be self-accept()ed and HMR invalidation will propagate up through the module tree. (NOTE: this is targeted for ADVANCED use cases.)
New test
const getSandbox = require('../helpers/sandbox');
it('allows self invalidation', async () => {
// ***NOTE***: I enhanced your test sandbox to allow this
const [session] = await getSandbox({ pluginOptions: { acceptSelf: false } });
await session.write('index.js', `module.exports = function Noop() { return null; };`);
await session.reload();
await session.write(
'foo.js',
`
require('./bar');
module.exports = function Foo() {};
module.hot.accept('./bar', () => window.log('accept ./bar'));
`
);
await session.write(
'bar.js',
`window.log('init BarV1'); module.exports = function Bar() { return null; };`
);
await session.patch(
'index.js',
`require('./foo'); module.exports = function Noop() { return null; };`
);
// Edited Bar doesn't self-accept
session.resetState();
await session.patch(
'bar.js',
`window.log('init BarV2'); module.exports = function Bar() { return null; };`
);
expect(session.logs).toStrictEqual(['accept ./bar']);
});
NOTES
I made a couple small changes to the test sandbox to allow passing plugin options. This was necessary to build the test correctly.
FYI, fails are only because of things choking on Node 14
I'm not sure this is what should be implemented - in particular by prohibiting custom accept chains we're also enforcing a constraint that modules cannot have side-effects which is essential for react-refresh to work properly. This also means things like the Error Overlay won't work reliably.
Do you have a more concrete use case why this is needed, or a reproduction if you ran into something (which could be a bug)?
Everything I posted here works fine.
I demonstrated a usecase/bug in my original comment.
I moved away from webpack; it's old and the ecosystem is RIP (case in point).