react-hot-loader: RHL throwing ReferenceErrors when hot-reloading third-party hooks.
Description
👋 Hey folks! I’m having a little trouble with RHL’s hooks support in a little Gatsby project. RHL seems to be injecting code that evaluates the imported hook functions using their reference names in the source code. But since the imports have been transformed by Babel and/or Webpack, there’s nothing in scope that matches. React’s built-in hooks do not seem to be affected.
By way of a contrived example, here’s a silly SFC that uses react-spring:
import { animated, useSpring } from 'react-spring'
import React, { useCallback, useState } from 'react'
function Index() {
const [thingDone, toggleThingDone] = useState(false)
const doTheThing = useCallback(() => toggleThingDone(!thingDone), [thingDone])
const fader = useSpring({ opacity: thingDone ? 1 : 0 })
return (
<>
<animated.h1 style={ fader }>
You did the thing!
</animated.h1>
<button type='button' onClick={ doTheThing }>
{ thingDone ? 'Undo The Thing' : 'Do The Thing' }
</button>
</>
)
}
I dropped the transpiled code into this gist; the relevant hunks seem to be line 22:
var _reactSpring = __webpack_require__(/*! react-spring */ "./node_modules/react-spring/web.js");
…lines 42–44:
const fader = (0, _reactSpring.useSpring)({
opacity: thingDone ? 1 : 0
});
…and line 63:
__signature__(Index, "useState{[thingDone, toggleThingDone]}\nuseCallback{doTheThing}\nuseSpring{fader}", () => [useSpring]);
The component uses the transpiled reference as expected, but RHL doesn’t seem to know about it. When a hot update is triggered, it throws a ReferenceError:
Stack trace :boom:
Uncaught ReferenceError: useSpring is not defined
at Object.getCustomHooks (index.js:5)
at haveEqualSignatures (react-hot-loader.development.js:2349)
at areSignaturesCompatible (react-hot-loader.development.js:2370)
at compareRegistered (react-hot-loader.development.js:2384)
at compareComponents (react-hot-loader.development.js:2395)
at hotComponentCompare (react-hot-loader.development.js:2468)
at reconcileSingleElement (react-dom.development.js:12507)
at reconcileChildFibers (react-dom.development.js:12589)
at reconcileChildren (react-dom.development.js:14411)
at finishClassComponent (react-dom.development.js:14759)
at updateClassComponent (react-dom.development.js:14697)
at beginWork (react-dom.development.js:15645)
at performUnitOfWork (react-dom.development.js:19313)
at workLoop (react-dom.development.js:19353)
at renderRoot (react-dom.development.js:19436)
at performWorkOnRoot (react-dom.development.js:20343)
at performWork (react-dom.development.js:20255)
at performSyncWork (react-dom.development.js:20229)
at requestWork (react-dom.development.js:20098)
at scheduleWork (react-dom.development.js:19912)
at Object.enqueueForceUpdate (react-dom.development.js:11209)
at ExportedComponent../node_modules/react/cjs/react.development.js.Component.forceUpdate (react.development.js:353)
at react-hot-loader.development.js:2740
at Array.forEach (<anonymous>)
at react-hot-loader.development.js:2739
(anonymous) @ index.js:5
haveEqualSignatures @ react-hot-loader.development.js:2349
areSignaturesCompatible @ react-hot-loader.development.js:2370
compareRegistered @ react-hot-loader.development.js:2384
compareComponents @ react-hot-loader.development.js:2395
hotComponentCompare @ react-hot-loader.development.js:2468
reconcileSingleElement @ react-dom.development.js:12507
reconcileChildFibers @ react-dom.development.js:12589
reconcileChildren @ react-dom.development.js:14411
finishClassComponent @ react-dom.development.js:14759
updateClassComponent @ react-dom.development.js:14697
beginWork @ react-dom.development.js:15645
performUnitOfWork @ react-dom.development.js:19313
workLoop @ react-dom.development.js:19353
renderRoot @ react-dom.development.js:19436
performWorkOnRoot @ react-dom.development.js:20343
performWork @ react-dom.development.js:20255
performSyncWork @ react-dom.development.js:20229
requestWork @ react-dom.development.js:20098
scheduleWork @ react-dom.development.js:19912
enqueueForceUpdate @ react-dom.development.js:11209
./node_modules/react/cjs/react.development.js.Component.forceUpdate @ react.development.js:353
(anonymous) @ react-hot-loader.development.js:2740
(anonymous) @ react-hot-loader.development.js:2739
setTimeout (async)
updateInstances @ react-hot-loader.development.js:2732
(anonymous) @ react-hot-loader.development.js:2756
hotSetStatus @ bootstrap:246
hotApply @ bootstrap:628
cb @ process-update.js:76
(anonymous) @ process-update.js:91
Promise.then (async)
check @ process-update.js:90
./node_modules/webpack-hot-middleware/process-update.js.module.exports @ process-update.js:52
processMessage @ client.js:279
handleMessage @ client.js:139
handleMessage @ client.js:102
06:17:01.939 index.js:2177 The above error occurred in the <LocationProvider> component:
in LocationProvider (created by Context.Consumer)
in Location (created by Context.Consumer)
in Router (created by Root)
in Root (at root.js:90)
in ThemeProvider (at provider.js:7)
in Provider (at gatsby-browser.js:21)
in _default (at app.js:62)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
stack_frame_overlay_proxy_console @ index.js:2177
logCapturedError @ react-dom.development.js:17118
logError @ react-dom.development.js:17154
update.callback @ react-dom.development.js:18066
callCallback @ react-dom.development.js:16434
commitUpdateEffects @ react-dom.development.js:16473
commitUpdateQueue @ react-dom.development.js:16461
commitLifeCycles @ react-dom.development.js:17384
commitAllLifeCycles @ react-dom.development.js:18737
callCallback @ react-dom.development.js:150
invokeGuardedCallbackDev @ react-dom.development.js:200
invokeGuardedCallback @ react-dom.development.js:257
commitRoot @ react-dom.development.js:18949
(anonymous) @ react-dom.development.js:20419
unstable_runWithPriority @ scheduler.development.js:255
completeRoot @ react-dom.development.js:20418
performWorkOnRoot @ react-dom.development.js:20347
performWork @ react-dom.development.js:20255
performSyncWork @ react-dom.development.js:20229
requestWork @ react-dom.development.js:20098
scheduleWork @ react-dom.development.js:19912
enqueueForceUpdate @ react-dom.development.js:11209
./node_modules/react/cjs/react.development.js.Component.forceUpdate @ react.development.js:353
(anonymous) @ react-hot-loader.development.js:2740
(anonymous) @ react-hot-loader.development.js:2739
setTimeout (async)
updateInstances @ react-hot-loader.development.js:2732
(anonymous) @ react-hot-loader.development.js:2756
hotSetStatus @ bootstrap:246
hotApply @ bootstrap:628
cb @ process-update.js:76
(anonymous) @ process-update.js:91
Promise.then (async)
check @ process-update.js:90
./node_modules/webpack-hot-middleware/process-update.js.module.exports @ process-update.js:52
processMessage @ client.js:279
handleMessage @ client.js:139
handleMessage @ client.js:102
I’m willing to believe this is an issue with Gatsby’s configuration patterns or my particular abuses of Gatsby’s configuration patterns, so I’m working on putting together a lightweight reproduction case. But I wanted to run it by you folks in the meantime to see whether there were any known issues that may be germane.
Let me know if I can do anything to add more color to the problem or help out with a solution! Thanks so much for your insight. ✨
Expected behavior
RHL should invoke hooks with their transpiled references, so as to avoid throwing ReferenceErrors.
Actual behavior
RHL attempts to invoke hooks using their untranspiled references, which are never in scope and throw ReferenceErrors.
Environment
React Hot Loader version: v4.11.0
Run these commands in the project folder and fill in their results:
node -v:v12.4.0npm -v:v6.9.0yarn -v’:v1.16.0
Then, specify:
- Operating system: macOS 10.15 (19A471t)
- Browser and version: Chrome 76.0.3809.21
Reproducible Demo
🚧 So far just the gist, but I’m working on it!
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 1
- Comments: 31 (16 by maintainers)
Commits related to this issue
- fix: clone node for signature, fixes #1268 — committed to gaearon/react-hot-loader by theKashey 5 years ago
- fix: clone node for signature, fixes #1268 — committed to gaearon/react-hot-loader by theKashey 5 years ago
- Merge pull request #1278 from dgreensp/repro-hook-issue Reproduce #1268 — committed to gaearon/react-hot-loader by theKashey 5 years ago
- Merge pull request #1276 from gaearon/fix-common-signature fix: clone node for signature, fixes #1268 — committed to gaearon/react-hot-loader by theKashey 5 years ago
- make parcel example more fragile to #1268 — committed to gaearon/react-hot-loader by theKashey 5 years ago
v4.11.2, or, better, v4.12 should solve the problem
v.4.11.1 released. Containing fixes both for your problem and
react-spring. https://github.com/gaearon/react-hot-loader/releases/tag/v4.11.1