исправил скрипт для пререндеринга, сделал получение страниц динамическим добавил гннерацию карты

This commit is contained in:
Joe_Peach committed 2026-04-12 16:12:43 +03:00
1 parent b7027d1183
commit c6b9001f74
1 file changed
+114 -37
+114 -37
View File
@@ -1,69 +1,146 @@
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs'; import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
import { resolve, dirname } from 'path'; import { resolve, dirname } from "path";
import { fileURLToPath } from 'url'; import { fileURLToPath } from "url";
import { client } from "../src/api/client";
const __dirname = dirname(fileURLToPath(import.meta.url)); const __dirname = dirname(fileURLToPath(import.meta.url));
// Список всех страниц const products = async function getProducts() {
const routes = [ try {
'/', console.log("📡 Загрузка товаров из API...");
'/products', const response = await client.get("/productList/");
'/about', return response.data;
// добавьте свои URL } catch (error) {
]; console.error("❌ Ошибка загрузки из API:", error.message);
console.log("📦 Использую тестовые данные...");
}
};
const distPath = resolve(__dirname, '../dist'); const distPath = resolve(__dirname, "../dist");
const indexHtmlPath = resolve(distPath, 'index.html'); const indexHtmlPath = resolve(distPath, "index.html");
if (!existsSync(indexHtmlPath)) { if (!existsSync(indexHtmlPath)) {
console.error('❌ Сначала запустите npm run build'); console.error("❌ Сначала запустите npm run build");
process.exit(1); process.exit(1);
} }
// Читаем исходный HTML // Читаем исходный HTML
let baseHtml = readFileSync(indexHtmlPath, 'utf-8'); let baseHtml = readFileSync(indexHtmlPath, "utf-8");
// Добавляем базовые мета-теги для каждой страницы // Добавляем базовые мета-теги для каждой страницы
const pages = { const pages = [
'/': { {
title: 'Магазин труб - Главная', path: "/",
description: 'Купить канализационные трубы по низким ценам' title: "Магазин труб - Главная",
description:
"Купить канализационные трубы, фитинги и комплектующие по низким ценам.",
}, },
'/products': { {
title: 'Каталог труб для канализации', path: "/products",
description: 'Широкий выбор труб, фитингов и комплектующих' title: "Каталог труб и фитингов для канализации",
description:
"Широкий выбор канализационных труб ПВХ, фитингов, тройников, переходов, колен. Высокое качество, низкие цены.",
}, },
'/about': { {
title: 'О магазине труб', path: "/about",
description: 'Информация о нашей компании' title: "О магазине труб - Доставка и гарантия",
} description:
}; "Информация о нашей компании. Как мы работаем, условия доставки, гарантия на все товары.",
},
];
routes.forEach(route => { const allRoutes = [...pages];
const pageInfo = pages[route] || pages['/'];
// Заменяем мета-теги в HTML // Добавляем маршруты товаров
for (const product of products) {
allRoutes.push({
path: `/product/${product.id}`,
description: product.description,
title: product.full_name,
});
}
let successCount = 0;
let errorCount = 0;
for (const route of allRoutes) {
try {
// Заменяем мета-теги
let html = baseHtml let html = baseHtml
.replace(/<title>.*?<\/title>/, `<title>${pageInfo.title}</title>`) .replace(
/<title>.*?<\/title>/,
`<title>${escapeHtml(route.title)}</title>`,
)
.replace( .replace(
/<meta name="description".*?>/, /<meta name="description".*?>/,
`<meta name="description" content="${pageInfo.description}">` `<meta name="description" content="${escapeHtml(route.description)}">`,
);
// Добавляем Open Graph теги (для соцсетей)
html = html.replace(
"</head>",
` <meta property="og:title" content="${escapeHtml(route.title)}">
<meta property="og:description" content="${escapeHtml(route.description)}">
<meta property="og:type" content="website">
<meta name="robots" content="index, follow">
</head>`,
); );
// Определяем путь для сохранения // Определяем путь для сохранения
let outputPath; let outputPath;
if (route === '/') { if (route.path === "/") {
outputPath = indexHtmlPath; outputPath = indexHtmlPath;
} else { } else {
const routeDir = resolve(distPath, route.substring(1)); const routeDir = resolve(distPath, route.path.substring(1));
if (!existsSync(routeDir)) { if (!existsSync(routeDir)) {
mkdirSync(routeDir, { recursive: true }); mkdirSync(routeDir, { recursive: true });
} }
outputPath = resolve(routeDir, 'index.html'); outputPath = resolve(routeDir, "index.html");
} }
writeFileSync(outputPath, html); writeFileSync(outputPath, html);
console.log(`✅ ${route} → ${outputPath}`); console.log(`✅ ${route.path} → ${outputPath}`);
}); successCount++;
} catch (error) {
console.error(`❌ Ошибка при генерации ${route.path}:`, error.message);
errorCount++;
}
}
console.log('✨ Done!'); const urls = allRoutes.map(route => ({
url: route.path,
lastmod: new Date().toISOString().split('T')[0],
priority: route.path === '/' ? 1.0 : route.path.startsWith('/product') ? 0.8 : 0.7
}));
const sitemapContent = generateSitemap(urls, 'https://pvh.projects.rustprogersteam.ru'); // замените на ваш домен
const sitemapPath = resolve(distPath, 'sitemap.xml');
writeFileSync(sitemapPath, sitemapContent);
console.log(`\n🗺️ Sitemap создан: ${sitemapPath}`);
// ============================================
// ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
// ============================================
function escapeHtml(text) {
return text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function generateSitemap(urls, baseUrl) {
return `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map(item => ` <url>
<loc>${baseUrl}${item.url}</loc>
<lastmod>${item.lastmod}</lastmod>
<priority>${item.priority}</priority>
</url>`).join('\n')}
</urlset>`;
}
console.log("✨ Done!");