Next.js global variables on server and client based on request domain

Viewed 7280

I am working on a Next.js multisite scoped project and I need to create a set of global variables to use on client and server (during SSR) side.

So far I came to the below solution.

This is how my custom App looks like:

import App from 'next/app'
import multisite from '@utils/multisite';
import MultisiteProvider from '@components/multisite/MultisiteProvider';

function MyApp({
  Component,
  site,
  pageProps
}) {
  // Will add site props to every page
  const props = { ...pageProps, site };
  return (
    // Provider will enable a hook to get site props on any child component
    <MultisiteProvider site={ site } >
      <Component { ...props }/>
    </MultisiteProvider>
  )
}

MyApp.getInitialProps = async(appContext) => {
  // getInitialProps executes on every page access, even on client when using "next/link"

  const appProps = await App.getInitialProps(appContext);
  let host;
  if (appContext.ctx.req) {
    // Get host from request during SSR
    host = appContext.ctx.req.headers.host;
  } else {
    // Get host from window on client
    host = window.location.host;
  }

  return {
    ...appProps,
    site: await multisite.resolveSiteProps(host)
  };
}

export default MyApp;

I would like to avoid using getInitialProps because it was supposed to disable Automatic Static Optimization in pages without Static Generation (which is my case). As mentioned on docs

The variables for each site are located on a "sites" directory under root folder like this:

/sites
--/siteone.com.us.json
--/siteone.com.br.json
--/sitetwo.com.us.json

And there is a function used to load the right file based on the current request domain.

const resolveSiteProps = async(host) => {
  const domain = normalizeDomain(host);
  const site = await
  import (
    /* webpackChunkName: "site-prefs" */
    /* webpackMode: "lazy" */
    `../sites/${domain}`
  );
  return {
    ...site.default,
    domain
  };
}

It would be nice if I could resolve this variables once during SSR and just use them in the client side.

I am looking for some helpful and elegant ideas to solve this case. Any thoughts?

2 Answers

Only tried this solution really quickly, but this should work at least in theory but is a different approach. We use rewrites based on host, but for a slightly different problem. Additionally, we do have a similar solution that you posted originally for deciding the brand based on request host.

What if you would have different paths for each site, and then use a rewrite in next.config.js based on the host?

Steps:

  1. add subfolders for each site in the pages, such as pages/siteone and pages/sitetwo
  2. Add rewrites based on site host as shown below
async rewrites() {
{
        source: '/:path*',
        destination: '/siteone/:path',
        has: [
          {
            type: 'host',
            value: 'siteone.com.us',
          },
        ],
      },
}

Of course this comes with a cost of having to have all the pages for each site, but you can share most of the code, so hopefully that's not an issue.

Note: this is probably not a fully functional example, but at least it gives you a hint about what could be possible with rewrites in Next.js.

https://nextjs.org/docs/api-reference/next.config.js/rewrites

Mainly There is two ways to do this:

  1. Create dynamic _sites/[site] route in the pages folder and then use rewrites to normalize your URLs.

    You can find full implementation here: https://github.com/vercel/next.js/discussions/12848#discussioncomment-1551776

    downsides:

    • you will have to explicitly include list of your domains in getStaticProps in all the pages you want static generated.

    • pathname in next useRouter will always include the prefix _sites/[site].

    • based on personal experience _sites/[site] prefix will sometimes appear actual website urls and cause errors.


  • Branch off of your main and deploy each branch separately. (RECOMMENDED)

    Create .env file and add NEXT_PUBLIC_DOMAIN=my-domain then create a new production branch from main and change the variable like this: NEXT_PUBLIC_DOMAIN=my-second-domain. you can access this variable wherever in your application, as stated in the docs

    downside:

    • You will have to manually merge your main branch to other branches that you create for each domain. This solution will not scale if you have many domains.

note: you cannot use _middleware for static optimization. The reason is static files are created at build time and cannot figure out which domain will make the requests.

Related