Мультидоменный проект (мультисайт) на NextJS

6465ed2a6cf9d5de201444716d344353

Привет! Я frontend-разработчик в одной компании, занимающейся электронной коммерцией.

Не буду долго рассказывать о себе, о компании и о том, как возникла потребность написать подобный проект, сразу приступлю к описанию решения.

Представим, что у вас порядка 500–1000 доменов и 5–10 разных дизайнов сайтов, распределенных между этими доменами примерно так:

  1. domain.com, domain-[city].com, domain-[subproduct]-[city].com — «сетка» 1

  2. domain2.com, domain2-[city].com, domain2-[anything]-[city].com — «сетка» 2

  3. 4,5…

Для всех сайтов нужна «одна» админка, БД разные. Для каждой «сетки» один дизайн. На каждом уникальном домене свои уникальные адреса продуктов/товаров/услуг и свои данные по продуктам. Никаких редиректов. Все страницы будем генерировать на сервере (SSG + ISR).

Из-за двух последних условий от SEOшников, вариантов реализации подобного проекта остается не так много.

Я использовал NextJS (Pages router). Так как по адресам domain.com/[firstLevel] может находиться и товар/услуга, и категория товара/услуги, и инфо страница, и любая другая страница, остается только один путь получения данных — полностью получать с бэка всю информацию по странице.

--- В папке /pages создал

  • […slug].tsx

  • папку admin

  • удалил index.tsx

--- В next.config.js необходимо прописать следующие настройки, чтобы получать имя хоста в getStaticProps в […slug].tsx:

async rewrites() {
    return [
      {
        source: '/admin/:path*',
        destination: '/admin/:path*',
      },
      {
        has: [
          {
            type: 'host',
            value: '(?.*)',
          },
        ],
        source: '/',
        destination: '/:host',
      },
      {
        has: [
          {
            type: 'host',
            value: '(?.*)',
          },
        ],
        source: '/:path*',
        destination: '/:host/:path*',
      },
    ];
  },

--- В getStaticProps в […slug].tsx:

Теперь в context попадает имя хоста в ctx.params.slug и весь путь страницы. С помощью React query делаем

 queryClient.prefetchQuery({
        queryFn: () => getPageData({ baseApi, url }),
        queryKey: [QUERY_KEY_FETCH_PAGE_DATA, { baseApi, url }]
      }),

baseApi определяется на основании полученного хоста.

Также в getStaticProps можно запросить domainData, где будет информация по домену (телефоны, адреса, инфо для шапки/футера, инфо домена: апи и тд…) и доставать эти данные из кэша там, где надо

В getStaticPaths:

export const getStaticPaths = async (): Promise => ({
  fallback: 'blocking',
  paths: []
})

--- Передаю baseApi вниз в компонент динамической страницы (DynamicPage), там повторяю запрос на pageData, достаю данные по странице, которые содержат:

  • тип страницы (switch/case)

  • хлебные крошки

  • содержание (вывод по условиям блоков страниц)

  • СЕО

--- Различия по CSS (шрифты, цвета) делаю через