Как настроить поддержку нескольких доменов в Next.js?

  • 8 августа 2023 г. 20:11
Ответы на вопрос 3
Для поддержки нескольких доменов с Next.js вы можете использовать custom server, например с express.js.

Сначала установите express.js, если у вас его еще нет:

```bash
npm install express
```

Затем создайте файл server.js в корневом каталоге проекта:

```javascript
const express = require('express')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
.then(() => {
  const server = express()

  server.get('*', (req, res) => {
    return handle(req, res)
  })

  server.listen(3000, (err) => {
    if (err) throw err
    console.log('> Ready on http://localhost:3000')
  })
})
```

В этом файле создается экспресс-сервер, который фактически обрабатывает все запросы.

Разумеется, для поддержки нескольких доменов вам потребуется соответствующий код. Вы можете использовать, например, middleware, которое по hostname запроса будет раздавать нужные страницы:

```javascript
const express = require('express')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
.then(() => {
  const server = express()

  server.use((req, res, next) => {
    switch (req.headers.host) {
      case 'www.domain1.com':
        req.url = '/domain1' + req.url;
        break;
      case 'www.domain2.com':
        req.url = '/domain2' + req.url;
        break;
    }
    next();
  });

  server.get('*', (req, res) => {
    return handle(req, res)
  })

  server.listen(3000, (err) => {
    if (err) throw err
    console.log('> Ready on http://localhost:3000')
  })
})
```

И последнее что вам нужно сделать - это изменить скрипт "start" в файле package.json на следующий:

```json
"scripts": {
  "dev": "node server.js",
  "build": "next build",
  "start": "NODE_ENV=production node server.js"
}
```

Теперь сервер запускается не стандартным образом next start, а через ваш server.js, где и происходит разделение на домены. 

Обратите внимание, что рассмотренный метод требует тщательного тестирования и не всегда может быть оптимальным для больших приложений, особенно если приложение активно развивается и постоянно обновляется.
- Создайте функцию-обертку `withHost`, которая принимает функцию `getStaticPropsData` в качестве аргумента.
- Внутри `withHost`, создайте функцию `getStaticProps`, которая принимает параметр `ctx`.
- Внутри `getStaticProps`, вызовите функцию `getHost` с параметром `ctx.params.host` и сохраните результат в переменной `response`.
- Вызовите функцию `getStaticPropsData` с параметром `ctx` и сохраните результат в переменной `gspData`.
- Верните объект со свойствами `props`, где значениями будут `response.data` и распыленный объект `gspData.props`.

- Создайте функцию `getStaticPaths`, которая не принимает аргументов.
- Внутри `getStaticPaths`, вызовите функцию `ServerCache.get("hosts")` и сохраните результат в переменной `response`.
- Верните объект со свойствами `paths`, где значениями будут результаты применения функции `.map(...)` к `response.data`, и `fallback`, равный "blocking".

- Верните объект с функциями `getStaticPaths` и `getStaticProps` из функции `withHost`.

В файле `index.tsx`, импортируйте функции `getStaticPaths` и `getStaticProps` из `withHost`, и используйте их при экспорте:

```
export const { getStaticPaths, getStaticProps } = withHost(() => ({
    props: {}
}));
```

Вынесите функцию `getStaticProps` в отдельную функцию и используйте ее для каждого роута:

```
export const getStaticProps = withHost(() => ({
    props: {}
}));

export const getStaticPaths = getHostsPaths();
```
Описание проблемы:
Я потратил 6 часов времени на разработку, и столкнулся с проблемой в следующей функции-обертке:

async function withHost(getStaticPropsData) {
    const getStaticProps = async (ctx) => {
        const response = await getHost(ctx.params.host);
        const gspData = await getStaticPropsData(ctx);
        return {
            props: { host: response.data, ...gpsData.props }
        }
    };

    const getStaticPaths = async () => {
        const response = await ServerCache.get("hosts");
        return {
            paths: response.data.map(...), 
            fallback: "blocking" 
        };
    }

    return { getStaticPaths, getStaticProps };
};

Решение проблемы:
Я вынес функцию gsp (getStaticProps) в отдельную функцию и использовал ее для каждого роута:

export const getStaticProps = withHost(() => ({
    props: {}
}))

export const getStaticPaths = getHostsPaths();
```
Похожие вопросы