Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New locale redirect behavior #20612

Closed
Timer opened this issue Dec 30, 2020 · 3 comments · Fixed by #20631
Closed

New locale redirect behavior #20612

Timer opened this issue Dec 30, 2020 · 3 comments · Fixed by #20631
Assignees
Milestone

Comments

@Timer
Copy link
Member

Timer commented Dec 30, 2020

Thanks @ijjk I just tried v10.0.5-canary.4 in one of my projects. Is it expected that <Link href="/hello" locale="xx" /> still points to /xx/hello, which is followed by a redirect on click? Two observations:

  • Having /xx/hello is probably not as good as my-domain-for.xx/hello SEO-wise

  • During local dev, having domains: [{domain: "xx.localhost", defaultLocale: "xx"}] means that the redirect from /xx/hello goes to https://xx.localhost/hello instead of http://xx.localhost:3000/hello (note the port and the protocol). This requires manual URL tweaking before the website in another locale can be viewed. What would be the suggested way forward here?

Originally posted by @kachkaev in #19174 (comment)

@Timer Timer added this to the iteration 15 milestone Dec 30, 2020
@kachkaev
Copy link
Contributor

kachkaev commented Dec 30, 2020

Some additional thoughts:

  • Picking the right port number and the protocol is not that straightforward. The website can be sitting behind the reverse proxy, which forwards https requests on port 443 to a Next.js container port 3000 via http. What I've been doing in cross-domain projects so far was determining the hostname for the current request and then amending it:

    type SomeRequest =
      | NextApiRequest
      | IncomingMessage
      | Pick<ApolloRequest, "url" | "method" | "headers">;
    
    const getHeader = (req: SomeRequest, header: string): string | undefined =>
      typeof req.headers?.get === "function"
        ? req.headers.get(header)
        : req.headers?.[header];
    
    const getRequestHostnameWithPort = (req: SomeRequest): string =>
      getHeader(req, "x-forwarded-host") ?? getHeader(req, "host") ?? "";
    
    const getRequestProtocol = (req: SomeRequest): string =>
      getHeader(req, "x-forwarded-proto") ?? "http";
      
    export const getBaseUrl = (req: SomeRequest, locale?: string) => {
      const baseUrl = new URL(`${getRequestProtocol(req)}://${getRequestHostnameWithPort(req)}/`);
      if (locale) {
        const hostnameForLocale = getHostnameForLocale(locale); // e.g. can use Next.js serverRuntimeConfig
        if (hostnameForLocale) {
          baseUrl.hostname = hostnameForLocale;
        }
      }
      return baseUrl.toString();
    };

    If I’m at http://xx.localhost:3000/ for locale xx, to know the base URL for locale yy, I need to extract the current request’s protocol and host and then replace the hostname only. Of course, my code is not perfect as it relies on the names as well as the trustworthiness of the reverse proxy headers, so a proper solution will need to be more elegant and cover more cases. Importantly, I don’t just trim the port number or add https based on process.env.NODE_ENV, because I still want next start to use http and port 3000 locally (e.g. during integration tests).

  • It’s important that next.config.jsi18ndomains are runtime values for SSR and ISR pages. Otherwise, this flow won’t work:

    1. Refer to process.env.DOMAIN_XX and process.env.DOMAIN_YY in next.config.jsi18ndomains
    2. next build
    3. containerize the app (container entrypoint is next start)
    4. deploy the container to staging with (DOMAIN_XX=xx.staging.example.com and DOMAIN_YY=yy.staging.example.com)
    5. sign off
    6. deploy the same container to prod (DOMAIN_XX=example.xx and DOMAIN_YY=example.yy)
       

    I know that on Vercel every redeployment results in a new app build, but this is not suitable in all scenarios due to the build reliability tradeoff . Sometimes, having a single artifact that can be promoted across environments is more desirable. For this use case to work, it is crucial to allow next.config.jsi18ndomains to be grabbed from the env variables at runtime.

@ijjk
Copy link
Member

ijjk commented Dec 31, 2020

I opened a PR here to address the href rendering with domain locales aspect of this issue, the other parts seem to be different and require further investigation. Currently specifying ports in locale domains isn't supported and changing these values without a new build is also not supported similarly to the basePath, rewrites, redirects, and headers configs since they affect resulting client bundles.

@kodiakhq kodiakhq bot closed this as completed in #20631 Dec 31, 2020
kodiakhq bot pushed a commit that referenced this issue Dec 31, 2020
This ensures we render the locale domain on the `href` when using `next/link` previously the provided `href` was stilling being rendered which differed from the resulting `href` that was navigated to. 

Fixes: #20612
@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants