From 569f0537570a495450a427f92e5c70de6953ef4d Mon Sep 17 00:00:00 2001 From: seb Date: Thu, 3 Jul 2025 07:00:13 +0200 Subject: [PATCH] Enhance product rendering by incorporating category information into JSON-LD generation and parallel rendering functions, improving SEO structure and breadcrumb support. --- prerender.cjs | 23 ++++++++++++++++++----- prerender/seo.cjs | 29 ++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/prerender.cjs b/prerender.cjs index eb1e7ed..52b6407 100644 --- a/prerender.cjs +++ b/prerender.cjs @@ -75,7 +75,7 @@ const AGB = require("./src/pages/AGB.js").default; const NotFound404 = require("./src/pages/NotFound404.js").default; // 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 workerSocket = io(socketUrl, { path: "/socket.io/", @@ -114,10 +114,13 @@ const renderProductWorker = async (productSeoNames, workerId, progressCallback) ...productDetails.product, seoName: actualSeoName, }, shopConfig.baseUrl, shopConfig); + // Get category info from categoryMap if available + const categoryInfo = productDetails.product.categoryId ? categoryMap[productDetails.product.categoryId] : null; + const jsonLdScript = generateProductJsonLd({ ...productDetails.product, seoName: actualSeoName, - }, shopConfig.baseUrl, shopConfig); + }, shopConfig.baseUrl, shopConfig, categoryInfo); const combinedMetaTags = metaTags + "\n" + jsonLdScript; const success = renderPage( @@ -183,7 +186,7 @@ const renderProductWorker = async (productSeoNames, workerId, progressCallback) }; // Function to render products in parallel -const renderProductsInParallel = async (allProductsArray, maxWorkers, totalProducts) => { +const renderProductsInParallel = async (allProductsArray, maxWorkers, totalProducts, categoryMap = {}) => { // Shared progress tracking let completedProducts = 0; let totalSuccessCount = 0; @@ -245,7 +248,7 @@ const renderProductsInParallel = async (allProductsArray, maxWorkers, totalProdu // Update progress bar with worker stats updateProgressBar(completedProducts, totalProducts, lastProductName); - }); + }, categoryMap); workerPromises.push(promise); } @@ -534,6 +537,15 @@ const renderApp = async (categoryData, socket) => { const numCPUs = os.cpus().length; 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( `\n📦 Rendering ${totalProducts} individual product pages using ${maxWorkers} parallel workers...` ); @@ -541,7 +553,8 @@ const renderApp = async (categoryData, socket) => { const productPagesRendered = await renderProductsInParallel( Array.from(allProducts), maxWorkers, - totalProducts + totalProducts, + categoryMap ); console.log( diff --git a/prerender/seo.cjs b/prerender/seo.cjs index 5637d30..476fdf9 100644 --- a/prerender/seo.cjs +++ b/prerender/seo.cjs @@ -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 imageUrl = 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 ``;