debugging: $refreshsig$ is not defined

2021-09-22

 | 

~4 min read

 | 

645 words

**TL;DR:** If you use Parcel and you get an error with `$RefreshSig$ is not defined` try running with HMR disabled
% parcel entry.js --no-hrm

Story Time

I have a React library that’s bootstrapped with TSDX. TSDX ships with a convenient “Example” app which can be used to test the library. That library uses Parcel to bundle. Parcel’s a great, zero-config option, which is wonderful… until it’s not.

Today, I found one of those cases where it’s less than wonderful.

In my library, I added a new custom hook that would be called by a component.

Let’s look at a stylized example and pretend that my directory structure was something like:

.
└── src
    ├── components
    │   └── my-component.tsx
    └── hooks
        └── use-logger.ts

The hook, use-logger.ts is a dispatched action:

use-logger.ts
const { useDispatch } = require("react-redux")

export function useLogger() {
  const dispatch = useDispatch()
  const logger = {
    track: (payload: any) =>
      dispatch({
        type: "Track",
        payload,
      }),
  }
  return logger
}

The hook dispatches a simple action that’s then picked up by Redux middleware to send off the appropriate pieces of the payload to a logging service.

Note: Interestingly, the error I’ll be getting to in a moment was only triggered when I tried to import / use useDispatch. If I just called a function or returned an object, the entire app loaded fine.

To use this, we can jump over to my-component.tsx:

my-component.tsx
import { useLogger } from "../hooks/use-logger"
function MyComponent() {
  const logger = useLogger()
  // ...
  logger.track({ data: "Doing X" })
}

So far, this feels pretty standard to me, but when I went to run the Example app provided by TSDX, despite bundling fine, I was greeted by a white screen and an error:

index.8d3dd0da.js:32467 Uncaught ReferenceError: $RefreshSig$ is not defined
    at Object.4f4Im.react-redux (index.8d3dd0da.js:32467)
    at newRequire (index.8d3dd0da.js:71)
    at localRequire (index.8d3dd0da.js:83)
    at Object.6ssI8../useMixpanel (index.8d3dd0da.js:32458)
    at newRequire (index.8d3dd0da.js:71)
    at localRequire (index.8d3dd0da.js:83)
    at Object.MElwL../common (index.8d3dd0da.js:30584)
    at newRequire (index.8d3dd0da.js:71)
    at localRequire (index.8d3dd0da.js:83)
    at Object.2XFFW../_actions (index.8d3dd0da.js:30533)

Drilling down in the stack trace, I could see where it was happening: $RefreshSig$ is not defined

It was suspiciously close to the new code I’d added!

Searching the web for other examples of this error, I found several about webpack and the dev server, for example this one on the react-refresh-plugin.

In my case, I’d trusted the zero-config promise of Parcel because it’d always worked. Consequently though, I wasn’t sure if I was using react-refresh in any way because I’d never had a reason to look.

Now, I did and it turned out I did in fact have a dependency on react-refresh coming from Parcel’s default config!

parcel default config dependencies

Okay! Progress.

Next step? What is react-refresh and how can I work around it? It’s a library for Fast Refresh (the modern replacement for hot reloading).

I’d previously proven to myself that this was an issue with Parcel and not my actual code because I’d consumed the library just fine in a different application with a different build pipeline (webpack in that case).

Looking at the Parcel CLI, I noticed there’s an option to Disable HMR. I gave it a shot and, wouldn’t you know it?, it worked!

Now I can carry on with my day!

Wrapping Up

Though I’d figured out early in the process that the issue was my build configuration, and that in my particular example, that meant that the code could be shipped, I spent extra time figuring out why.

The reason was simple: having the Example app is a huge boon to productivity and losing it would have been costly.

Along the way, I learned something about how Parcel works, some CLI configurations and options I hadn’t needed to know about previously, and what react-refresh is.

What I haven’t solved (yet) is why this happened. But that’s just a matter of time!


Hi there and thanks for reading! My name's Stephen. I live in Chicago with my wife, Kate, and dog, Finn. Want more? See about and get in touch!