const fs = require("fs"); const path = require("path"); const React = require("react"); const ReactDOMServer = require("react-dom/server"); const { StaticRouter } = require("react-router"); const { CacheProvider } = require("@emotion/react"); const { ThemeProvider } = require("@mui/material/styles"); const createEmotionCache = require("../createEmotionCache.js").default; const theme = require("../src/theme.js").default; const createEmotionServer = require("@emotion/server/create-instance").default; const renderPage = ( component, location, filename, description, metaTags = "", needsRouter = false, config, suppressLogs = false, productData = null ) => { const { isProduction, outputDir, globalCss, globalCssCollection, webpackEntrypoints, } = config; const { optimizeCss } = require("./utils.cjs"); // @note Set prerender fallback flag in global environment for CategoryBox during SSR if (typeof global !== "undefined" && global.window) { global.window.__PRERENDER_FALLBACK__ = { path: location, timestamp: Date.now() }; } // Create fresh Emotion cache for each page const cache = createEmotionCache(); const { extractCriticalToChunks } = createEmotionServer(cache); const wrappedComponent = needsRouter ? React.createElement(StaticRouter, { location: location }, component) : component; const pageElement = React.createElement( CacheProvider, { value: cache }, React.createElement(ThemeProvider, { theme: theme }, wrappedComponent) ); let renderedMarkup; let pageSpecificCss = ""; // Declare outside try block for broader scope try { renderedMarkup = ReactDOMServer.renderToString(pageElement); const emotionChunks = extractCriticalToChunks(renderedMarkup); // Collect CSS from this page for direct inlining (no global accumulation) if (emotionChunks.styles.length > 0) { emotionChunks.styles.forEach((style) => { if (style.css) { pageSpecificCss += style.css + "\n"; } }); if (!suppressLogs) console.log(` - CSS rules: ${emotionChunks.styles.length}`); } } catch (error) { console.error(`❌ Rendering failed for ${filename}:`, error); return false; } // Use appropriate template path based on mode // In production, use a clean template file, not the already-rendered index.html const templatePath = isProduction ? path.resolve(__dirname, "..", "dist", "index_template.html") : path.resolve(__dirname, "..", "public", "index.html"); let template = fs.readFileSync(templatePath, "utf8"); // Build CSS and JS tags with optimized CSS loading let additionalTags = ""; let inlinedCss = ""; if (isProduction) { // Check if scripts are already present in template to avoid duplication const existingScripts = template.match(/`; } }); } else { // In development, try to inline prerender CSS as well try { const prerenderCssPath = path.resolve(__dirname, "..", outputDir, "prerender.css"); if (fs.existsSync(prerenderCssPath)) { const prerenderCssContent = fs.readFileSync(prerenderCssPath, "utf8"); const optimizedCss = optimizeCss(prerenderCssContent); inlinedCss += optimizedCss; if (!suppressLogs) console.log(` ✅ Inlined prerender CSS in development (${Math.round(optimizedCss.length / 1024)}KB)`); } else { // Fallback to external loading additionalTags += ``; } } catch (error) { // Fallback to external loading additionalTags += ``; } } // Create script to save prerendered content to window object for fallback use const prerenderFallbackScript = ` `; // @note Create script to populate window.productCache with ONLY the static category tree let productCacheScript = ''; if (typeof global !== "undefined" && global.window && global.window.categoryCache) { // Only include the static categoryTree_209, not any dynamic data that gets added during rendering const staticCache = {}; if (global.window.categoryCache["209_de"]) { staticCache["209_de"] = global.window.categoryCache["209_de"]; } const staticCacheData = JSON.stringify(staticCache); productCacheScript = ` `; } // Create script to populate window.productDetailCache for individual product pages let productDetailCacheScript = ''; if (productData && productData.product) { // Cache the entire response object (includes product, attributes, etc.) // Use language-aware cache key (prerender defaults to German) const productDetailCacheData = JSON.stringify(productData); const language = 'de'; // Prerender system caches German version const cacheKey = `product_${productData.product.seoName}_${language}`; productDetailCacheScript = ` `; } // Combine all CSS (global + inlined) into a single optimized style tag const combinedCss = globalCss + (inlinedCss ? '\n' + inlinedCss : ''); const combinedCssTag = combinedCss ? `` : ''; // Add resource hints for better performance const resourceHints = ` `; template = template.replace( "", `${resourceHints}${combinedCssTag}${additionalTags}${metaTags}${prerenderFallbackScript}${productCacheScript}${productDetailCacheScript}` ); const rootDivRegex = /