Представим, что у вас порядка 500-1000 доменов и 5-10 разных дизайнов сайтов, распределенных между этими доменами примерно так:
Из-за двух последних условий от SEOшников, вариантов реализации подобного проекта остается не так много.
Я использовал NextJS (Pages router). Так как по адресам domain.com/[firstLevel] может находиться и товар/услуга, и категория товара/услуги, и инфо страница, и любая другая страница, остается только один путь получения данных - полностью получать с бэка всю информацию по странице.
--- В папке /pages создал
async rewrites() {
return [
{
source: '/admin/ath*',
destination: '/admin/ath*',
},
{
has: [
{
type: 'host',
value: '(?<host>.*)',
},
],
source: '/',
destination: '/:host',
},
{
has: [
{
type: 'host',
value: '(?<host>.*)',
},
],
source: '/ath*',
destination: '/:host/ath*',
},
];
},
--- В 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<any> => ({
fallback: 'blocking',
paths: []
})
--- Передаю baseApi вниз в компонент динамической страницы (DynamicPage), там повторяю запрос на pageData, достаю данные по странице, которые содержат:
--- В админке необходимо создать управление всеми сущностями, которые есть на сайтах: товары, услуги, категории товаров/услуг, страницы, пользователи, бренды и всё, всё, всё! И самое главное у всех страниц необходимо создать управление СЕО. В итоге - это в основном множество таблиц и полей форм сущностей. Админка вся на getServerSideProps и частично на CSR. На любые методы PUT/PATCH/DELETE/POST необходимо в ответ получать адреса ревалидации с бэка и отправлять на внутреннее api NextJS:
/** обработчик обновления страниц */
export default async function handler (req: NextApiRequest, res:NextApiResponse): Promise<void> {
if (req?.method !== 'POST') {
return res.status(405).json({ message: 'Метод не разрешен' })
}
try {
if (req?.body?.secret !== process.env.REVALIDATE_TOKEN) {
return res.status(401).json({ message: 'Неверный токен' })
}
if (!Array.isArray(req.body.url)) {
return res.status(400).json({ message: 'Не правильный формат урл' })
}
/** промисы */
const revalidatePromises = req?.body?.url?.map(async (url: string) => res.revalidate(url))
/** результаты */
const results = await Promise.allSettled(revalidatePromises)
/** кол-во успешных */
const successfulRevalidations = results.filter(result => result.status === 'fulfilled').length
return res.json({ revalidated: true, successfulRevalidations })
} catch (err) {
return res.status(500).send('Ошибка ревалидации из хэндлера')
}
}
Единственное неудобство - необходимость в каждый запрос передавать baseApi.
Честно говоря, до сих пор пишу и поддерживаю этот проект и ощущение, что где-то, что-то делаю не так, но все работает: страницы генерируются, регенирируются по запросу. Важные данные по цене и наличию делаю клиентскими.
- domain.com, domain-[city].com, domain-[subproduct]-[city].com - "сетка" 1
- domain2.com, domain2-[city].com, domain2-[anything]-[city].com - "сетка" 2
- 4,5...
Из-за двух последних условий от SEOшников, вариантов реализации подобного проекта остается не так много.
Я использовал NextJS (Pages router). Так как по адресам domain.com/[firstLevel] может находиться и товар/услуга, и категория товара/услуги, и инфо страница, и любая другая страница, остается только один путь получения данных - полностью получать с бэка всю информацию по странице.
--- В папке /pages создал
- [...slug].tsx
- папку admin
- [adminFoldersAndRoutes] - в реале не один динамический путь, а много папок и файлов
- удалил index.tsx
async rewrites() {
return [
{
source: '/admin/ath*',
destination: '/admin/ath*',
},
{
has: [
{
type: 'host',
value: '(?<host>.*)',
},
],
source: '/',
destination: '/:host',
},
{
has: [
{
type: 'host',
value: '(?<host>.*)',
},
],
source: '/ath*',
destination: '/:host/ath*',
},
];
},
--- В 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<any> => ({
fallback: 'blocking',
paths: []
})
--- Передаю baseApi вниз в компонент динамической страницы (DynamicPage), там повторяю запрос на pageData, достаю данные по странице, которые содержат:
- тип страницы (switch/case)
- хлебные крошки
- содержание (вывод по условиям блоков страниц)
- СЕО
--- В админке необходимо создать управление всеми сущностями, которые есть на сайтах: товары, услуги, категории товаров/услуг, страницы, пользователи, бренды и всё, всё, всё! И самое главное у всех страниц необходимо создать управление СЕО. В итоге - это в основном множество таблиц и полей форм сущностей. Админка вся на getServerSideProps и частично на CSR. На любые методы PUT/PATCH/DELETE/POST необходимо в ответ получать адреса ревалидации с бэка и отправлять на внутреннее api NextJS:
/** обработчик обновления страниц */
export default async function handler (req: NextApiRequest, res:NextApiResponse): Promise<void> {
if (req?.method !== 'POST') {
return res.status(405).json({ message: 'Метод не разрешен' })
}
try {
if (req?.body?.secret !== process.env.REVALIDATE_TOKEN) {
return res.status(401).json({ message: 'Неверный токен' })
}
if (!Array.isArray(req.body.url)) {
return res.status(400).json({ message: 'Не правильный формат урл' })
}
/** промисы */
const revalidatePromises = req?.body?.url?.map(async (url: string) => res.revalidate(url))
/** результаты */
const results = await Promise.allSettled(revalidatePromises)
/** кол-во успешных */
const successfulRevalidations = results.filter(result => result.status === 'fulfilled').length
return res.json({ revalidated: true, successfulRevalidations })
} catch (err) {
return res.status(500).send('Ошибка ревалидации из хэндлера')
}
}
Единственное неудобство - необходимость в каждый запрос передавать baseApi.
Честно говоря, до сих пор пишу и поддерживаю этот проект и ощущение, что где-то, что-то делаю не так, но все работает: страницы генерируются, регенирируются по запросу. Важные данные по цене и наличию делаю клиентскими.
Мультидоменный проект (мультисайт) на NextJS
Привет! Я frontend-разработчик в одной компании, занимающейся электронной коммерцией. Не буду долго рассказывать о себе, о компании и о том, как возникла потребность написать подобный проект, сразу...
habr.com