Enhance product rendering by incorporating category information into JSON-LD generation and parallel rendering functions, improving SEO structure and breadcrumb support.

This commit is contained in:
seb
2025-07-03 07:00:13 +02:00
parent 5d5c09abbf
commit 569f053757
2 changed files with 46 additions and 6 deletions

View File

@@ -75,7 +75,7 @@ const AGB = require("./src/pages/AGB.js").default;
const NotFound404 = require("./src/pages/NotFound404.js").default; const NotFound404 = require("./src/pages/NotFound404.js").default;
// Worker function for parallel product rendering // Worker function for parallel product rendering
const renderProductWorker = async (productSeoNames, workerId, progressCallback) => { const renderProductWorker = async (productSeoNames, workerId, progressCallback, categoryMap = {}) => {
const socketUrl = "http://127.0.0.1:9303"; const socketUrl = "http://127.0.0.1:9303";
const workerSocket = io(socketUrl, { const workerSocket = io(socketUrl, {
path: "/socket.io/", path: "/socket.io/",
@@ -114,10 +114,13 @@ const renderProductWorker = async (productSeoNames, workerId, progressCallback)
...productDetails.product, ...productDetails.product,
seoName: actualSeoName, seoName: actualSeoName,
}, shopConfig.baseUrl, shopConfig); }, shopConfig.baseUrl, shopConfig);
// Get category info from categoryMap if available
const categoryInfo = productDetails.product.categoryId ? categoryMap[productDetails.product.categoryId] : null;
const jsonLdScript = generateProductJsonLd({ const jsonLdScript = generateProductJsonLd({
...productDetails.product, ...productDetails.product,
seoName: actualSeoName, seoName: actualSeoName,
}, shopConfig.baseUrl, shopConfig); }, shopConfig.baseUrl, shopConfig, categoryInfo);
const combinedMetaTags = metaTags + "\n" + jsonLdScript; const combinedMetaTags = metaTags + "\n" + jsonLdScript;
const success = renderPage( const success = renderPage(
@@ -183,7 +186,7 @@ const renderProductWorker = async (productSeoNames, workerId, progressCallback)
}; };
// Function to render products in parallel // Function to render products in parallel
const renderProductsInParallel = async (allProductsArray, maxWorkers, totalProducts) => { const renderProductsInParallel = async (allProductsArray, maxWorkers, totalProducts, categoryMap = {}) => {
// Shared progress tracking // Shared progress tracking
let completedProducts = 0; let completedProducts = 0;
let totalSuccessCount = 0; let totalSuccessCount = 0;
@@ -245,7 +248,7 @@ const renderProductsInParallel = async (allProductsArray, maxWorkers, totalProdu
// Update progress bar with worker stats // Update progress bar with worker stats
updateProgressBar(completedProducts, totalProducts, lastProductName); updateProgressBar(completedProducts, totalProducts, lastProductName);
}); }, categoryMap);
workerPromises.push(promise); workerPromises.push(promise);
} }
@@ -534,6 +537,15 @@ const renderApp = async (categoryData, socket) => {
const numCPUs = os.cpus().length; const numCPUs = os.cpus().length;
const maxWorkers = Math.min(numCPUs, totalProducts, 8); // Cap at 8 workers to avoid overwhelming the server const maxWorkers = Math.min(numCPUs, totalProducts, 8); // Cap at 8 workers to avoid overwhelming the server
// Create category map for breadcrumbs
const categoryMap = {};
allCategories.forEach(category => {
categoryMap[category.id] = {
name: category.name,
seoName: category.seoName
};
});
console.log( console.log(
`\n📦 Rendering ${totalProducts} individual product pages using ${maxWorkers} parallel workers...` `\n📦 Rendering ${totalProducts} individual product pages using ${maxWorkers} parallel workers...`
); );
@@ -541,7 +553,8 @@ const renderApp = async (categoryData, socket) => {
const productPagesRendered = await renderProductsInParallel( const productPagesRendered = await renderProductsInParallel(
Array.from(allProducts), Array.from(allProducts),
maxWorkers, maxWorkers,
totalProducts totalProducts,
categoryMap
); );
console.log( console.log(

View File

@@ -50,7 +50,7 @@ const generateProductMetaTags = (product, baseUrl, config) => {
`; `;
}; };
const generateProductJsonLd = (product, baseUrl, config) => { const generateProductJsonLd = (product, baseUrl, config, categoryInfo = null) => {
const productUrl = `${baseUrl}/Artikel/${product.seoName}`; const productUrl = `${baseUrl}/Artikel/${product.seoName}`;
const imageUrl = const imageUrl =
product.pictureList && product.pictureList.trim() product.pictureList && product.pictureList.trim()
@@ -97,6 +97,33 @@ const generateProductJsonLd = (product, baseUrl, config) => {
}, },
}; };
// Add breadcrumb if category information is available
if (categoryInfo && categoryInfo.name && categoryInfo.seoName) {
jsonLd.breadcrumb = {
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "Home",
item: baseUrl,
},
{
"@type": "ListItem",
position: 2,
name: categoryInfo.name,
item: `${baseUrl}/Kategorie/${categoryInfo.seoName}`,
},
{
"@type": "ListItem",
position: 3,
name: product.name,
item: productUrl,
},
],
};
}
return `<script type="application/ld+json">${JSON.stringify( return `<script type="application/ld+json">${JSON.stringify(
jsonLd jsonLd
)}</script>`; )}</script>`;