react-refresh-webpack-plugin: ReferenceError: $RefreshSig$ is not defined while running with webpack-dev-server

Our webpack configuration matches the readme. No other options passed to the plugin. The main difference is devServer writeToDisk: true option as we have a PHP backend which servers builded files. Single file entry.

"scripts": {
  "dev-server": "webpack-dev-server --watch --mode development --hot",
  "dev": "webpack --watch --mode development"
}

When we run npm run dev-server, the compilation step finishes without a problem:

[1] multi (webpack)-dev-server/client?http://localhost:5000 (webpack)/hot/dev-server.js ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ReactRefreshEntry.js ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ErrorOverlayEntry.js ./app/index 76 bytes {main} [built]

But we face the fatal error in a browser afterwards:

sockjs.js:4533 Uncaught ReferenceError: $RefreshSig$ is not defined
    at setup (sockjs.js:4533)
    at Object.<anonymous> (sockjs.js:4506)
    at Object.55../common (sockjs.js:4519)
    at o (sockjs.js:41)
    at sockjs.js:43
    at Object.<anonymous> (sockjs.js:4094)
    at Object.52.debug (sockjs.js:4133)
    at o (sockjs.js:41)
    at sockjs.js:43
    at Object.<anonymous> (sockjs.js:3276)

And it looks like ReactRefreshEntry.js was never called.

If we run npm run dev which calls webpack directly, the compilation step finished successfully:

[0] multi ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ReactRefreshEntry.js ./node_modules/@pmmmwh/react-refresh-webpack-plugin/src/runtime/ErrorOverlayEntry.js ./app/index 52 bytes {main} [built]

And the browser console is clean and our app works fine. But the hot reload functionality is gone as there is no running dev server to get changes from.

RefreshReg, $RefreshSig$ and $RefreshSetup$ are now present under window object.

I have tried disabling everything, even the whole app/index.js file but without a success. My humble debugging suggests that ReactRefreshEntry is not called early enough. The chain goes like this:

webpack-dev-server/client/index.js → webpack-dev-server/client/socket.js → webpack-dev-server/client/clients/SockJSClient.js → sockjs-client/dist/sockjs.js → and finally setup(env) failing to call var _s = $RefreshSig$();

That’s where my abilities ends and wonders begin 😃

Can you point me in some direction what to check and how can I provide better feedback?

Thanks!


Versions:

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 16 (6 by maintainers)

Most upvoted comments

My guess is that you’ve included the react-refresh/babel plugin to process node_modules. This will break because some code (as used by Webpack and WDS) will inevitably run before the plugin.

Well I have already deleted it but here is the one.

I think you didn’t set NODE_ENV to production for the production build? That’s why the api.env()is always development?

I have recently introduced the plugin and have got the error only in production. The exclude setting is applied to my webpack.common.js and the plugin has to do nothing with my production config, so what’d be wrong here?

You probably need to exclude the react-refresh/babel plugin for your production build, or properly set NODE_ENV for the build process as well.

I just hit this. We have a requirement to allow refreshing of a single node module. I wonder if it’s possible?

It works for our Electron app, but when I try to load the file standalone in a browser this regex seems not to be satisfactory: exclude: /node_modules\/(?!@our\/package)/

But exclude: /node_modules/ works fine (except that we need to hot reload @our/package.

Can anyone advise if/how this is possible?

You probably also need to pass your package through Babel with the react-refresh/babel plugin.

Here it is: plugins: [ new ReactRefreshWebpackPlugin(), new HtmlWebpackPlugin({…}), new Dotenv(), ], … module: { rules: [ { test: /.tsx?$/, use: ‘ts-loader’, exclude: /node_modules/, options: { getCustomTransformers: () => ({ before: [require(‘react-refresh/typescript’)()], }), }, }, { test: /.svg$/, type: ‘asset’, use: ‘svgo-loader’, }, { test: /.(png|jpg|jpeg|gif|ico|mp3)$/i, type: ‘asset/resource’, }, { test: /.(woff|woff2|eot|ttf|otf)$/i, type: ‘asset/resource’, generator: { filename: ‘fonts/[name][ext]’, }, }, ], },

I have recently introduced the plugin and have got the error only in production. The exclude setting is applied to my webpack.common.js and the plugin has to do nothing with my production config, so what’d be wrong here?

webpack.common.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const Dotenv = require('dotenv-webpack');

module.exports = {
  entry: './src/index.tsx',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
      },
    ],
  },
  resolve: {
    extensions: ['.ts', '.tsx', '.js', '.jsx'],
    fallback: {
      fs: false,
      net: false,
      tls: false,
      assert: require.resolve('assert/'),
      https: require.resolve('https-browserify'),
      crypto: require.resolve('crypto-browserify'),
      buffer: require.resolve('buffer/'),
      http: require.resolve('stream-http'),
      stream: require.resolve('stream-browserify'),
      os: require.resolve('os-browserify/browser'),
      zlib: require.resolve('browserify-zlib'),
      path: require.resolve('path-browserify'),
    },
  },
  output: {
    path: path.resolve(__dirname, 'dist/'),
    filename: 'bundle.js',
  },
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        extractComments: false,
      }),
    ],
  },
  plugins: [new Dotenv()],
};
webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const CompressionPlugin = require('compression-webpack-plugin');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

module.exports = merge(common, {
  mode: 'development',
  devServer: {
    static: path.join(__dirname, 'dist'),
    compress: true,
    host: '127.0.0.1',
    hot: true,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
    }),
    new CompressionPlugin(),
    new ReactRefreshWebpackPlugin(),
  ],
});
webpack.prod.js
const { ProvidePlugin } = require('webpack');
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlInlineScriptPlugin = require('html-inline-script-webpack-plugin');

module.exports = merge(common, {
  mode: 'production',
  plugins: [
    new ProvidePlugin({
      process: 'process/browser',
      Buffer: ['buffer', 'Buffer'],
    }),
    new HtmlWebpackPlugin({
      template: 'public/index.html',
    }),
    new HtmlInlineScriptPlugin(),
  ],
});

package.json
{
  "..."
  "scripts": {
    "start": "webpack serve -c webpack.dev.js --open",
    "build": "webpack -c webpack.prod.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "..."
  "devDependencies": {
    "@apollo/client": "^3.3.13",
    "@googlemaps/js-api-loader": "^1.11.3",
    "@material-ui/icons": "^4.11.2",
    "@material-ui/lab": "^4.0.0-alpha.60",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
    "assert": "^2.0.0",
    "browserify-zlib": "^0.2.0",
    "buffer": "^6.0.3",
    "crypto-browserify": "^3.12.0",
    "dotenv": "^8.2.0",
    "graphql": "^15.5.0",
    "https-browserify": "^1.0.0",
    "os-browserify": "^0.3.0",
    "path-browserify": "^1.0.1",
    "react-refresh": "^0.10.0",
    "stream-browserify": "^3.0.0",
    "stream-http": "^3.1.1",
    "webpack-merge": "^5.7.3",
    "@babel/cli": "7.13.10",
    "@babel/core": "7.13.10",
    "@babel/preset-env": "7.13.12",
    "@babel/preset-react": "7.12.13",
    "@babel/preset-typescript": "7.13.0",
    "@material-ui/core": "4.11.3",
    "@react-google-maps/api": "2.1.1",
    "@types/dotenv": "^8.2.0",
    "@types/google.maps": "^3.44.2",
    "@types/lodash": "^4.14.168",
    "@types/node": "^14.14.36",
    "@types/react": "17.0.3",
    "@types/react-dom": "17.0.3",
    "@typescript-eslint/eslint-plugin": "4.19.0",
    "@typescript-eslint/parser": "4.19.0",
    "babel-eslint": "10.1.0",
    "babel-loader": "8.2.2",
    "compression-webpack-plugin": "7.1.2",
    "core-js": "3.9.1",
    "css-loader": "5.2.0",
    "dotenv-webpack": "^7.0.2",
    "eslint": "7.22.0",
    "eslint-config-prettier": "8.1.0",
    "eslint-config-react-app": "6.0.0",
    "eslint-plugin-flowtype": "5.4.0",
    "eslint-plugin-import": "2.22.1",
    "eslint-plugin-jsx-a11y": "6.4.1",
    "eslint-plugin-prettier": "3.3.1",
    "eslint-plugin-react": "7.23.1",
    "eslint-plugin-react-hooks": "4.2.0",
    "framer-motion": "4.0.3",
    "html-inline-script-webpack-plugin": "^2.0.0",
    "html-webpack-inline-source-plugin": "1.0.0-beta.2",
    "html-webpack-plugin": "5.3.1",
    "husky": "5.2.0",
    "license-checker": "25.0.1",
    "lint-staged": "10.5.4",
    "prettier": "2.2.1",
    "process": "^0.11.10",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-hook-geolocation": "1.0.7",
    "react-use": "17.2.1",
    "style-loader": "2.0.0",
    "terser-webpack-plugin": "^5.1.1",
    "ts-loader": "^8.0.18",
    "typescript": "4.2.3",
    "webpack": "5.28.0",
    "webpack-bundle-analyzer": "4.4.0",
    "webpack-cli": "4.5.0",
    "webpack-dev-server": "4.0.0-beta.0"
  },
  "..."
}

Indeed. What a great guess! The cause was missing exclude: /node_modules/ in js/ts loaders with babel-loader.

Thanks a lot, I was stuck on this for so long 🙏