next.js icon indicating copy to clipboard operation
next.js copied to clipboard

Presence of i18n config breaks multi-tenant's index page (404 Not Found)

Open patrik-simunic-cz opened this issue 1 year ago • 5 comments

Verify canary release

  • [X] I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System: Platform: darwin Arch: x64 Version: Darwin Kernel Version 21.4.0: Mon Feb 21 20:35:58 PST 2022; root:xnu-8020.101.4~2/RELEASE_ARM64_T6000 Binaries: Node: 14.18.3 npm: 8.5.1 Yarn: 1.22.18 pnpm: N/A Relevant packages: next: 13.0.3-canary.4 eslint-config-next: N/A react: 18.2.0 react-dom: 18.2.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

If there is i18n config present in next.config.js, then index (home) page unexpectedly ends with error 404 (Not Found). All other pages work just fine. Only index page is broken. I've previously open an issue in the next-i18next repository, however I was redirected here as it appears to be an error on the part of Next.js itself. To see the existing discussion, here is my original issue: https://github.com/i18next/next-i18next/issues/2019

Expected Behavior

The index page should load just fine even with i18n config present in next.config.js.

Link to reproduction - Issues with a link to complete (but minimal) reproduction code will be addressed faster

https://github.com/patrik-simunic-cz/bug-nextjs-multitenant-i18n

To Reproduce

  • Clone the repo
  • Run yarn dev
  • Open the index page http://localhost:3000 and you'll get 404
  • Open different page http://localhost:3000/works and it will load totally fine (even with correct translations)

If you remove the i18n config from next.config.js file, then translations are broken (obviously), however you'll no longer get 404 on the index page.

patrik-simunic-cz avatar Nov 11 '22 14:11 patrik-simunic-cz

To add 1 more perplexing fact (as with regard to the minimal reproducible example): I've added console.log to the middleware to see when it's invoked (and with what url). If I open some page (/works) it works including different locales (/en/works, /cs/works) and the middleware is invoked. But when I open the index page and get 404, the middleware is not even invoked - it ends on 404 even before calling the middleware.

patrik-simunic-cz avatar Nov 11 '22 14:11 patrik-simunic-cz

https://yourdomain/-> falls to 404 page if you access https://yourdomain/index -> works fine

nir099 avatar Nov 12 '22 10:11 nir099

@nir099 No, it doesn't... I've tried it and when you clone my bug reproduction, you can see that localhost:3000 falls to 404 and so does localhost:3000/index. Even if it indeed would work, that still doesn't solve anything. Index page has to be accessible without explicitly specifying /index in the path - but as the demo demonstrate, it doesn't even work with explicitly specifying /index (although if you do specify /index, the request at least reaches the middleware - but still ends in 404)

patrik-simunic-cz avatar Nov 12 '22 13:11 patrik-simunic-cz

Alright, I'm one step closer, but still with no solution in sight. The 404 is gone if I create an index page at the utmost top-level of pages (pages/index) and it resolves to this page. But this is useless - it's a multi-tenant app, the index page it should resolve to pages/web/[tenant]/index, not pages/index. For some reason, the presence of i18n config in next.config.js forces Next.js to bypass the middleware which rewrites everything to tenant-specific path:

import { NextRequest, NextResponse } from 'next/server'

const rootHost = 'localhost:3000'

export const config = {
    matcher: [ '/((?!api|_next|locales|fonts|[\\w-]+\\.\\w+).*)' ],
}

export default (request: NextRequest) => {
    const url = request.nextUrl
    const hostname = request.headers.get('host') || rootHost

    url.pathname = `/web/${hostname}${url.pathname}`
    return NextResponse.rewrite(url)
}

patrik-simunic-cz avatar Nov 12 '22 13:11 patrik-simunic-cz

Alright, issue solved. The problem is that the official matcher for multi-tenant application is absolutely incompatible with the very presence of i18n config in next.config.js file. You need to either fix this matcher:

export const config = {
    matcher: [ '/((?!api|_next|fonts|examples|[\\w-]+\\.\\w+).*)' ],
}

or remove it and solve it programmatically within the middleware itself.

I'm leaving this issue open until someone from Vercel deigns to at least look at this issue and maybe consider at least adding a warning the the official Vercel guide for multi-tenant apps? And/or updating the official starter kit for multi-tenant apps? This was just a colossal waste of time. A note that presence of i18n changes the matcher behaviour would be nice....

patrik-simunic-cz avatar Nov 12 '22 15:11 patrik-simunic-cz

I have the same problem. Someone from the Vercel team to help?

cjambrosi avatar Nov 30 '22 02:11 cjambrosi

Hey @patrik-simunic-cz, very much appreciate your deep dive here and apologies for the bad experience. Agreed it could be more clear that using i18n routing configuration options might have conflicts with Middleware. We will update our guide/code to make sure of that note. Further, going forward in the app directory future, we recommend using Middleware for i18n routing. You can view the new docs here: https://beta.nextjs.org/docs/guides/internationalization

leerob avatar Jan 19 '23 03:01 leerob

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

github-actions[bot] avatar Feb 18 '23 12:02 github-actions[bot]