When useFileSystemPublicRoutes is set to false and there is no custom route for path, but page-based route exists, nextjs will render that page on client instead of 404.
Steps to reproduce:
custom-server exampleconst app = next({ dev }) in server.js withconst app = next({
dev,
conf: {
useFileSystemPublicRoutes: false
}
})/pages/index.js component. Browser console contains Warning: React attempted to reuse markupSo with this option behavior on server and client is not consistent, and it doesn't look like it should work this way.
I've also run into this issue.
This useFileSystemPublicRoutes: false seems to be useless βΒ it stops the server from setting up matching routes for the file names, but the next client still attempts to use a PageLoader to pull in the chunk for the file-named pathname at runtime.
So when a request comes in for a named page e.g. pages/foo.js:
_error component is correctly rendered/foo (this shouldn't happen)What should _probably_ happen is that when _error is rendered, it should have the same behaviour as if pages/foo.js doesn't exist.
This is tough though, as you will probably still want to load the foo.js chunk on anotherβvalidβpage.
One solution is that a flag is passed down to the error page, so it doesn't attempt to load a named chunk (foo.js in our case), but just the error chunk.
This will solve the flash-404, but this won't work for client-side routing (where the client wouldn't start from an error page).
But this would be fine as long as you don't make a bad link.
I'll give it a go and open a PR.
Any updates on this? I'm using a custom server to point /:username to ./pages/user.js, but like what @GennadyPonomarev & @iest have described, it didn't work as expected.
Hmm seems I did it wrong, this could fix my issue:
server.get('/:username', (req, res) => {
app.render(req, res, '/user', {
username: req.params.username
})
})
My app:
<Link href="/user?username=egoist" as="/egoist">
<a>egoist</a>
</Link>
I just ran into this as well, playing with one of the examples (ssr caching) to make it use koa.
In the example, /blog should be invalid, and /blog/first should work.
useFileSystemPublicRoutes = false
is ignored by the client-side code.
I worked around the problem by renaming pages/blog.js to pages/blog2.js and fixing my code a bit, just to hide /blog a little better. So now at least /blog is a proper Next 404, but /blog2 is still available and it's a mix of my blog2.js content and formatted as a Next error page.
I've got a small example at https://ssr-caching-koa-amateehwho.now.sh/ (and source).
useFileSystemPublicRoutes is set false in next.config.js.
First, the actual problem can be seen at https://ssr-caching-koa-amateehwho.now.sh/blog2. Note that there is a /pages/blog2.js file.
A correct 404 is https://ssr-caching-koa-amateehwho.now.sh/blog. We have no /pages/blog.js file.
Actual posts are at https://ssr-caching-koa-amateehwho.now.sh/blog/first for example but I'm making use of a custom server to handle routing and map /blog/:id to the /pages/blog2.js file (passing the id parameter).
I solved this problem changing the end of the default export of /client/index.js to:
if (props && props.statusCode === 404) { // here
return emitter // here
} // here
router.subscribe(({ Component, props, hash, err }) => {
render({ Component, props, err, hash, emitter })
})
const hash = location.hash.substring(1)
render({ Component, props, hash, err, emitter })
return emitter
So if the client receives 404 from the server, it stops trying to render the page again. I am not sure if this is the best approach as I am not familiar with the lib. To me, an even better solution would be to prevent the client from re-rendering error pages.
This seems to be a problem that needs to be addressed. Why no updates in over 6 months?
@rafaelalmeidatk I don't get your code. The props variable doesn't seem to exist outside of subscribe function.
@iest Any update on your fix?
thanks.
also seeing the same problem, any updates on this issue? thanks
@fuzzthink These changes are here: https://github.com/zeit/next.js/blob/canary/client/index.js#L85
I'm currently still experiencing this in 5.0.0.
@timneutkens I see you've added the label: good first issue. Do you have any pointers on where to look for this?
I'll try to submit a PR to fix this.
@thomhos it's actually not easy to fix, removed the label π, I'd have to investigate it further to come up with a solution.
Ah, I just submitted a PR which seems to fix the problem for me as far as I could test locally. I guess we should close that as well?
I encountered the same problem in 5.0.0
Any updates? This is a very annoying issue.
@gcpantazis The problem is that you can have something like
.
βββ pages
βββ dashboard
β βββ index.js
βββ landing
βββ index.js
And then have some custom routing like:
router.get('/', (req, res) => {
if (!req.isAuthenticated()) {
return next.render(req, res, '/dashboard', req.query);
}
next.render(req, res, '/landing', req.query);
});
So that logged-out users see a landing view, and logged-in users see a dashboard.
This works fine when hitting / as expected.
But if any user goes to /dashboard or /landing they will see these views (though it will likely throw some errors along the way). The expected behavior is that by setting useFileSystemPublicRoutes: false the routes _must_ be defined manually, but they are still accessible via the browser.
@tmarshall Apologies, you're right; I deleted my comments to avoid confusion. I had some ideas on the way home, so I'll make a test project to see if we can suss out a proposal to fix this. π
For what it's worth, it looks like the case mentioned by most of the reporters here (i.e., server renders a 404s then flashes to an unexpected client-rendered page) was fixed incidentally as of 5.0.1-canary.5 (and specifically by #3749).
There's a few other cases that we could consider:
1) Create a Link that corresponds to a file-system route, even though you disabled it via useFileSystemPublicRoutes.
2) Click on that Link.
3) See the page, even though useFileSystemPublicRoutes: false implies you shouldn't.
popstate:1) Go to a URL that corresponds to a file-system route, even though you disabled it via useFileSystemPublicRoutes. Get a 404 from SSR.
2) Click on a link that takes you something else via client-side navigation.
3) Hit "back" on the browser.
4) You'll see the file-system route render instead of a 404.
Of the two, I'd say the first is maybe not a huge concern, since as you've opted to replace Next's default routing you should be responsible for client-side navigation to bad URLs. The second I think is a bigger issue (and perhaps can be a separate issue, since as far as I can tell most of the reporters' problems will be resolved in 5.0.1).
Test case here: https://github.com/gcpantazis/nextjs-playground/tree/useFileSystemPublicRoutes
@thomhos made a PR for it: https://github.com/zeit/next.js/pull/3777
@gcpantazis could you try out the PR?
Rebased and tried that patch, @timneutkens. Unfortunately I think #3777 only fixes the issue described here because it breaks client-side altogether (removes the route to the bundles, i.e. ['/_next/:buildId/page/:path*.js'] if useFileSystemPublicRoutes: false).
I think I have an alternate solution; I'll put it together when I get to the office.
Hi guys, I realize now as well that #3777 was a very naive approach to the problem, I was hoping to kickstart it a bit and come to a solution together :)
Let me know if you need any help, I haven't looked into this for a while.
@timneutkens ping on βοΈ before it gets stale! π
The case mentioned in the issue topic is actually solved in next@canary. Thanks new 404 logic.
Creating a new issue for @gcpantazis's comments on other cases.
Most helpful comment
also seeing the same problem, any updates on this issue? thanks