react-refresh-webpack-plugin icon indicating copy to clipboard operation
react-refresh-webpack-plugin copied to clipboard

[bug] `originalFactory` undefined with `experiments.lazyCompilation: true` (`TypeError: Cannot read properties of undefined (reading 'call')`)

Open mjames-c opened this issue 4 months ago • 0 comments

Possibly related to https://github.com/pmmmwh/react-refresh-webpack-plugin/issues/328 but i'm not sure at this stage.

After an initial webpack build, a majority of this module interceptors run successfully however a small number of them fail (2 in this case). One of those failures was passed an options object which does NOT contain a factory method:

{
    "id": "../node_modules/.pnpm/[email protected]_patch_hash=fkx2gt7y67232wbropmj3evxhu/node_modules/mobx/dist/mobx.esm.js",
    "module": {
        "exports": {},
        "hot": {
            "_acceptedDependencies": {},
            "_acceptedErrorHandlers": {},
            "_declinedDependencies": {},
            "_selfAccepted": false,
            "_selfDeclined": false,
            "_selfInvalidated": false,
            "_disposeHandlers": [],
            "_main": false,
            "active": true
        },
        "parents": [
            "<omitted>"
        ],
        "children": []
    },
    require: f (request)
}

Somewhat interestingly the page will successfully load on subsequent refresh -- the module interceptor no longer errors on the modules that used to fail.

Injected module interceptor

/******/ 		__webpack_require__.i.push((options) => {
/******/ 			const originalFactory = options.factory;
/******/ 			options.factory = function(moduleObject, moduleExports, webpackRequire) {
/******/ 				const hotRequire = (request) => (webpackRequire(request));
/******/ 				const createPropertyDescriptor = (name) => {
/******/ 					return {
/******/ 						configurable: true,
/******/ 						enumerable: true,
/******/ 						get: () => (webpackRequire[name]),
/******/ 						set: (value) => {
/******/ 							webpackRequire[name] = value;
/******/ 						},
/******/ 					};
/******/ 				};
/******/ 				for (const name in webpackRequire) {
/******/ 					if (name === "$Refresh$") continue;
/******/ 					if (Object.prototype.hasOwnProperty.call(webpackRequire, name)) {
/******/ 						Object.defineProperty(hotRequire, name, createPropertyDescriptor(name));
/******/ 					}
/******/ 				}
/******/ 				hotRequire.$Refresh$ = setup(options.id);
/******/                // `originalFactory` is undefined in the error case so the line below throws:
/******/ 				originalFactory.call(this, moduleObject, moduleExports, hotRequire);
/******/ 			};
/******/ 		});

Webpack config snippet

{
  experiments: {
    lazyCompilation: {
      backend: {
        listen: {
          port: 9999,
        },
        server: {
          maxHeaderSize: 256000,
        },
      },
    },
  },
  devServer: {
    static: false,
    compress: true,
    devMiddleware: {
      etag: 'weak',
      stats: {
        ...stats,
        entrypoints: false,
        modules: false,
      },
    },
    hot: true,
    client: undefined,
    liveReload: false,
  }
}

Package versions

$ pnpm ls react-refresh
react-refresh 0.17.0

$ pnpm ls @pmmmwh/react-refresh-webpack-plugin
@pmmmwh/react-refresh-webpack-plugin 0.6.1

$ pnpm ls webpack
webpack 5.99.9

I plan on spending more time investigating this and will update this description as I uncover more insights.

mjames-c avatar Aug 14 '25 06:08 mjames-c