Skip to content

Commit b863d17

Browse files
authored
fix: ensure this propagates through module execution interceptor (#921)
1 parent c40ad99 commit b863d17

File tree

2 files changed

+42
-39
lines changed

2 files changed

+42
-39
lines changed

lib/utils/makeRefreshRuntimeModule.js

Lines changed: 41 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/**
22
* Makes a runtime module to intercept module execution for React Refresh.
3-
* This module creates an isolated __webpak_require__ function for each module
4-
* and injects a $Refresh$ object into it for use by react-refresh.
3+
* This module creates an isolated `__webpack_require__` function for each module,
4+
* and injects a `$Refresh$` object into it for use by React Refresh.
55
* @param {import('webpack')} webpack The Webpack exports.
6-
* @returns {ReactRefreshRuntimeModule} The runtime module class.
6+
* @returns {typeof import('webpack').RuntimeModule} The runtime module class.
77
*/
88
function makeRefreshRuntimeModule(webpack) {
99
return class ReactRefreshRuntimeModule extends webpack.RuntimeModule {
@@ -17,6 +17,8 @@ function makeRefreshRuntimeModule(webpack) {
1717
* @returns {string} runtime code
1818
*/
1919
generate() {
20+
if (!this.compilation) throw new Error('Webpack compilation missing!');
21+
2022
const { runtimeTemplate } = this.compilation;
2123
const constDeclaration = runtimeTemplate.supportsConst() ? 'const' : 'var';
2224
return webpack.Template.asString([
@@ -48,45 +50,46 @@ function makeRefreshRuntimeModule(webpack) {
4850
'options',
4951
[
5052
`${constDeclaration} originalFactory = options.factory;`,
51-
`options.factory = ${runtimeTemplate.basicFunction(
52-
'moduleObject, moduleExports, webpackRequire',
53-
[
54-
// Our require function delegates to the original require function
55-
`${constDeclaration} hotRequire = ${runtimeTemplate.returningFunction(
56-
'webpackRequire(request)',
57-
'request'
58-
)};`,
59-
// The propery descriptor factory below
60-
// ensures all properties but $Refresh$ are proxied through to the original require function
61-
`${constDeclaration} createPropertyDescriptor = ${runtimeTemplate.basicFunction(
62-
'name',
63-
[
64-
`return {`,
65-
webpack.Template.indent([
66-
`configurable: true,`,
67-
`enumerable: true,`,
68-
`get: ${runtimeTemplate.returningFunction('webpackRequire[name]')},`,
69-
`set: ${runtimeTemplate.basicFunction('value', [
70-
'webpackRequire[name] = value;',
71-
])},`,
72-
]),
73-
`};`,
74-
]
75-
)};`,
76-
`for (${constDeclaration} name in webpackRequire) {`,
77-
webpack.Template.indent([
78-
'if (name === "$Refresh$") continue;',
79-
'if (Object.prototype.hasOwnProperty.call(webpackRequire, name)) {',
53+
// Using a function declaration -
54+
// ensures `this` would propagate for modules relying on it
55+
`options.factory = function(moduleObject, moduleExports, webpackRequire) {`,
56+
webpack.Template.indent([
57+
// Our require function delegates to the original require function
58+
`${constDeclaration} hotRequire = ${runtimeTemplate.returningFunction(
59+
'webpackRequire(request)',
60+
'request'
61+
)};`,
62+
// The propery descriptor factory below ensures all properties but `$Refresh$`
63+
// are proxied through to the original require function
64+
`${constDeclaration} createPropertyDescriptor = ${runtimeTemplate.basicFunction(
65+
'name',
66+
[
67+
`return {`,
8068
webpack.Template.indent([
81-
`Object.defineProperty(hotRequire, name, createPropertyDescriptor(name));`,
69+
`configurable: true,`,
70+
`enumerable: true,`,
71+
`get: ${runtimeTemplate.returningFunction('webpackRequire[name]')},`,
72+
`set: ${runtimeTemplate.basicFunction('value', [
73+
'webpackRequire[name] = value;',
74+
])},`,
8275
]),
83-
`}`,
76+
`};`,
77+
]
78+
)};`,
79+
`for (${constDeclaration} name in webpackRequire) {`,
80+
webpack.Template.indent([
81+
'if (name === "$Refresh$") continue;',
82+
'if (Object.prototype.hasOwnProperty.call(webpackRequire, name)) {',
83+
webpack.Template.indent([
84+
`Object.defineProperty(hotRequire, name, createPropertyDescriptor(name));`,
8485
]),
8586
`}`,
86-
`hotRequire.$Refresh$ = setup(options.id);`,
87-
`originalFactory.call(this, moduleObject, moduleExports, hotRequire);`,
88-
]
89-
)};`,
87+
]),
88+
`}`,
89+
`hotRequire.$Refresh$ = setup(options.id);`,
90+
`originalFactory.call(this, moduleObject, moduleExports, hotRequire);`,
91+
]),
92+
'};',
9093
]
9194
)});`,
9295
]);

test/unit/makeRefreshRuntimeModule.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ __webpack_require__.i.push(function(options) {
118118
119119
__webpack_require__.i.push((options) => {
120120
const originalFactory = options.factory;
121-
options.factory = (moduleObject, moduleExports, webpackRequire) => {
121+
options.factory = function(moduleObject, moduleExports, webpackRequire) {
122122
const hotRequire = (request) => (webpackRequire(request));
123123
const createPropertyDescriptor = (name) => {
124124
return {

0 commit comments

Comments
 (0)