next.js: `next dev` will not resolve missing routes using yarn 2 zero-install
Next.js version: 10.0.6
Node.js version: v14.15.0
Browser: Firefox
OS: macOS
How are you deploying your application?: next dev
Reproduce with a fresh next-app, migrating to yarn 2 with pnp, installing, and starting a dev server:
yarn create next-app reproduction
cd reproduction
yarn set version berry
yarn install
yarn dev
Then navigate to an undefined route, e.g. http://localhost:3000/abc123
Expected Behavior: The app should render a static 404 error page stating This page could not be found
Actual Behavior: The browser tab spins forever, and the page never resolves.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 13
- Comments: 17 (5 by maintainers)
This seems to be related to Plug’n’Play - setting
nodeLinker: node-modules
in.yarnrc.yml
causes error pages to appear again. Similarly, runningyarn unplug next
makes the issue disappear, since thenext
module is unpacked into.yarn/unplugged
.I tried to do some debugging to determine the cause and was unable to find it, but here are some findings, hopefully they are helpful.
In
on-demand-entry-helper.ts
, theensurePage
function is called for the 404 page, and it returns a promise that is intended to resolve when thenext/dist/pages/_error
page is compiled, but that promise never resolves. This causes the behavior experienced where 404’s never appear in the browser, the tab just spins forever.Specifically, this code:
https://github.com/vercel/next.js/blob/5fff814ca1e7f78b50535a55d6f99bd842c4e049/packages/next/server/on-demand-entry-handler.ts#L203-L210
That registers a callback for the normalized page
'/next/dist/pages/_error'
and requests that the invalidator invalidate compilation. The call toinvalidator.invalidate()
does trigger some kind of recompile, reaching the code here that is supposed to emit the event for compile success:https://github.com/vercel/next.js/blob/bddb02286fdcfb83fc97fa91df378cb6d92778e8/packages/next/server/on-demand-entry-handler.ts#L71-L94
entries
variable is an empty object ({}
), andpagePaths
does not contain'/next/dist/pages/_error'
, so no event is emitted, the promise never resolves, and the browser hangs.entries
variable is an object with a key for'/next/dist/pages/_error'
, andpagePaths
contains'/next/dist/pages/_error'
, so an event is emitted and the 404 page is displayed.So, it would appear that the entry for
next/dist/pages/_error
is not getting registered with Webpack, or the hot reloader, or some other middleware in a way that works with Yarn PnP. I did some brief investigation into how this works currently, but don’t understand enough to determine the cause.Perhaps related is the
next-client-pages-loader
, it receivesnext/dist/pages/_error
as an “absolutePagePath”, and it’s not clear if it would correctly userequire.resolve
or similar to resolve the page path with PnP, but some attempts to resolve the path prior withrequire.resolve
caused Yarn to start complaining about importingprivate-next-pages
, which is supposed to be resolved by Webpack, so I clearly do not fully understand the loader structure.Hopefully that’s helpful and someone can locate the root cause!
+1 to fixing this. I worked around this by re-exporting the error page:
EDIT: Actually, just doing this gives a warning
So instead, I just added my own
pages/404.tsx
page.I think I’ve tracked down the cause of the problem. Thank you for your research @jacobwgillespie.
The hot reloader appears to determine whether a page exists by checking if write access is granted.
https://github.com/vercel/next.js/blob/76e2bb57adfd1dae53da912c5c666e63443dacf7/packages/next/server/hot-reloader.ts#L324-L329
https://github.com/vercel/next.js/blob/76e2bb57adfd1dae53da912c5c666e63443dacf7/packages/next/build/is-writeable.ts#L1-L10
I suspect that because the built in Next.js pages are contained within zip files, the virtual file system provided by Yarn PnP reports the file is read only (write access declined).
Changing the line of code in
hot-reloader.ts
to something like this appears to work:To test this yourself, you can use the Yarn 2 patch feature: https://yarnpkg.com/cli/pack https://yarnpkg.com/features/protocols#patch
next-patch.diff
:package.json
:Following up on what @ceefour said, Even on
next@11.1.3-canary.76
, I can only get things to work properly if both_error.tsx
and404.tsx
exist. I feel like there’s some file existence logic still in play somewhere.Hi, this has been updated in the latest version of Next.js
v11.1.3-canary.76
, please update and give it a try!Yes the workaround still works in next 11, I’m just saying that it’s still not completely fixed in a way so you don’t have to use the workaround
The fix mentioned here seems to work fine: https://github.com/vercel/next.js/issues/21828#issuecomment-854318588 . Yep, you need to add the custom
pages/404.tsx
.@meglio still doesn’t seem to be fixed in Next 11 sadly 😕
I second this. The patching approach by @strothj fixed the initial build issue and now next@10.1.3 works successfully with webpack@5.34.0 with
yarn next dev
. Hot reload isn’t working, which I imagine is the same issue as this.is it planned to be fixed?