Skip to content

Commit

Permalink
Fix HMR error: "Cannot read properties of null (reading 'length')" (#…
Browse files Browse the repository at this point in the history
…43145)

After upgrading to Next.js 13, we started seeing the following HMR
errors:

```sh
$ next dev
# ...
warn  - Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/basic-features/fast-refresh#how-it-works
TypeError: Cannot read properties of null (reading 'length')
    at eval (webpack-internal:///./node_modules/next/dist/client/dev/error-overlay/hot-dev-client.js:262:55)
```

This error appears related to the changes made in
#42350 (cc @alexkirsz). It appears
that `module.hot.check` will pass `null` when there are no updates:

```ts
  /**
   * Throws an exceptions if status() is not idle.
   * Check all currently loaded modules for updates and apply updates if found.
   * If no update was found, the callback is called with null.
   * If autoApply is truthy the callback will be called with all modules that were disposed.
   * apply() is automatically called with autoApply as options parameter.
   * If autoApply is not set the callback will be called with all modules that will be disposed on apply().
   * @param autoApply
   */
  check(autoApply?: boolean): Promise<null|ModuleId[]>;
```

When `updatedModules` is `null`, we skip the `apply()` call as this was
producing `apply() is only allowed in ready status (state: idle)`
errors. This matches [the prior behavior when `autoApply` was
enabled](https://github.com/webpack/webpack/blob/8241da7f1e75c5581ba535d127fa66aeb9eb2ac8/lib/hmr/HotModuleReplacement.runtime.js#L266-L272).

Fixes #43143. Also reported on Stack Overflow: 
-
https://stackoverflow.com/questions/74415937/nextjs-typeerror-cannot-read-properties-of-null-reading-length
-
https://stackoverflow.com/questions/74504229/nextjs-v-13-typeerror-cannot-read-properties-of-null-reading-length

I tested this change locally and no longer see these HMR errors.

## Bug

- [X] Related issues linked using `fixes #number` - no related issues
- [X] Integration tests added - there aren't any existing tests, afaict
- [X] Errors have a helpful link attached, see `contributing.md` - N/A

Co-authored-by: JJ Kasper <jj@jjsweb.site>
  • Loading branch information
colinking and ijjk committed Nov 22, 2022
1 parent d8d9b2c commit ed2aa9f
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 6 deletions.
Expand Up @@ -124,7 +124,7 @@ function tryApplyUpdates(
return
}

function handleApplyUpdates(err: any, updatedModules: any) {
function handleApplyUpdates(err: any, updatedModules: any[] | null) {
if (err || RuntimeErrorHandler.hadRuntimeError || !updatedModules) {
if (err) {
console.warn(
Expand All @@ -144,7 +144,7 @@ function tryApplyUpdates(
return
}

const hasUpdates = Boolean(updatedModules.length)
const hasUpdates = Boolean(updatedModules?.length)
if (typeof onHotUpdateSuccess === 'function') {
// Maybe we want to do something.
onHotUpdateSuccess(hasUpdates)
Expand Down Expand Up @@ -175,8 +175,8 @@ function tryApplyUpdates(
// @ts-expect-error module.hot exists
module.hot
.check(/* autoApply */ false)
.then((updatedModules: any) => {
const hasUpdates = Boolean(updatedModules.length)
.then((updatedModules: any[] | null) => {
const hasUpdates = Boolean(updatedModules?.length)
if (typeof onBeforeUpdate === 'function') {
onBeforeUpdate(hasUpdates)
}
Expand Down
4 changes: 2 additions & 2 deletions packages/next/client/dev/error-overlay/hot-dev-client.js
Expand Up @@ -337,7 +337,7 @@ function tryApplyUpdates(onBeforeHotUpdate, onHotUpdateSuccess) {
return
}

const hasUpdates = Boolean(updatedModules.length)
const hasUpdates = Boolean(updatedModules?.length)
if (typeof onHotUpdateSuccess === 'function') {
// Maybe we want to do something.
onHotUpdateSuccess(hasUpdates)
Expand Down Expand Up @@ -368,7 +368,7 @@ function tryApplyUpdates(onBeforeHotUpdate, onHotUpdateSuccess) {
.check(/* autoApply */ false)
.then((updatedModules) => {
if (typeof onBeforeHotUpdate === 'function') {
const hasUpdates = Boolean(updatedModules.length)
const hasUpdates = Boolean(updatedModules?.length)
onBeforeHotUpdate(hasUpdates)
}
return module.hot.apply()
Expand Down

0 comments on commit ed2aa9f

Please sign in to comment.