diff --git a/src/components/ProductDetailPage.js b/src/components/ProductDetailPage.js index 524f352..a51ad4a 100644 --- a/src/components/ProductDetailPage.js +++ b/src/components/ProductDetailPage.js @@ -294,9 +294,12 @@ class ProductDetailPage extends Component { })); console.log('loadKomponent', id, count); + const currentLanguage = this.props.languageContext?.currentLanguage + const currentLanguage2 = this.props.i18n?.language || 'de'; + console.log('debuglanguage', currentLanguage, currentLanguage2); window.socketManager.emit( "getProductView", - { articleId: id }, + { articleId: id, language: currentLanguage, requestTranslation: currentLanguage === "de" ? false : true}, (res) => { if (res.success) { // Cache the successful response @@ -406,9 +409,11 @@ class ProductDetailPage extends Component { loadProductData = () => { console.log('loadProductData', this.props.seoName); + const currentLanguage = this.props.languageContext?.currentLanguage || this.props.i18n?.language || 'de'; + console.log('debuglanguage', currentLanguage); window.socketManager.emit( "getProductView", - { seoName: this.props.seoName }, + { seoName: this.props.seoName, language: currentLanguage, requestTranslation: currentLanguage === "de" ? false : true}, (res) => { if (res.success) { res.product.seoName = this.props.seoName; diff --git a/webpack.config.js b/webpack.config.js index d6941f7..8aaede4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -396,15 +396,7 @@ export default { headers: { 'Cache-Control': 'public, max-age=3600', }, - static: [ - { - directory: path.resolve(__dirname, 'dist'), - }, - { - directory: path.resolve(__dirname, 'public'), - publicPath: '/', - } - ], + // Add proxy configuration for socket.io and API proxy: [ { @@ -423,266 +415,12 @@ export default { secure: proxyTarget.startsWith('https') } ], - setupMiddlewares: (middlewares, devServer) => { - if (!devServer) throw new Error('webpack-dev-server is not defined'); - - // Middleware to serve prerendered files as HTML - devServer.app.use((req, res, next) => { - // Check if this is a request for a prerendered file - if (req.url.startsWith('/Kategorie/') || req.url.startsWith('/Artikel/')) { - const filePath = path.resolve(__dirname, 'public', req.url.slice(1)); - - // Check if the prerendered file exists - if (fs.existsSync(filePath)) { - res.setHeader('Content-Type', 'text/html; charset=utf-8'); - res.setHeader('Cache-Control', 'public, max-age=3600'); - return res.sendFile(filePath); - } - } - - // Handle root index file - if (req.url === '/' || req.url.startsWith('/index.html')) { - res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); - res.setHeader('Pragma', 'no-cache'); - res.setHeader('Expires', '0'); - } - - next(); - }); - // Add middleware to handle /404 route BEFORE webpack-dev-server processing - middlewares.unshift({ - name: 'handle-404-route', - middleware: async (req, res, next) => { - if (req.url === '/404') { - // Set up prerender environment - const { createRequire } = await import('module'); - const require = createRequire(import.meta.url); - - require('@babel/register')({ - presets: [ - ['@babel/preset-env', { targets: { node: 'current' } }], - '@babel/preset-react' - ], - extensions: ['.js', '.jsx'], - ignore: [/node_modules/] - }); - - // Import React first and make it globally available - const React = require('react'); - global.React = React; // Make React available globally for components that don't import it - - // Set up minimal globals for prerender - if (!global.window) { - global.window = {}; - } - if (!global.navigator) { - global.navigator = { userAgent: 'node.js' }; - } - if (!global.URL) { - global.URL = require('url').URL; - } - if (!global.Blob) { - global.Blob = class MockBlob { - constructor(data, options) { - this.data = data; - this.type = options?.type || ''; - } - }; - } - - // Mock browser storage APIs - const mockStorage = { - getItem: () => null, - setItem: () => {}, - removeItem: () => {}, - clear: () => {}, - key: () => null, - length: 0 - }; - - if (!global.localStorage) { - global.localStorage = mockStorage; - } - if (!global.sessionStorage) { - global.sessionStorage = mockStorage; - } - - // Also add to window object for components that access it via window - global.window.localStorage = mockStorage; - global.window.sessionStorage = mockStorage; - - // Import the dedicated prerender component - const PrerenderNotFound = require('./src/PrerenderNotFound.js').default; - - // Create the prerender component - const component = React.createElement(PrerenderNotFound); - - // Get only the essential bundles (not lazy-loaded chunks) - let jsBundles = []; - try { - const outputFileSystem = devServer.compiler.outputFileSystem; - const outputPath = devServer.compiler.outputPath; - const jsPath = path.join(outputPath, 'js'); - - if (outputFileSystem.existsSync && outputFileSystem.existsSync(jsPath)) { - const jsFiles = outputFileSystem.readdirSync(jsPath); - - // Only include essential bundles in correct dependency order - const essentialBundles = []; - - // 1. Runtime bundle (webpack runtime - must be first) - const runtimeFile = jsFiles.find(f => f.startsWith('runtime.') && f.endsWith('.bundle.js')); - if (runtimeFile) essentialBundles.push('/js/' + runtimeFile); - - // 2. Vendor bundles (libraries that main depends on) - const reactFile = jsFiles.find(f => f.startsWith('react.') && f.endsWith('.bundle.js')); - if (reactFile) essentialBundles.push('/js/' + reactFile); - - const emotionFile = jsFiles.find(f => f.startsWith('emotion.') && f.endsWith('.bundle.js')); - if (emotionFile) essentialBundles.push('/js/' + emotionFile); - - const muiIconsCommonFile = jsFiles.find(f => f.startsWith('mui-icons-common.') && f.endsWith('.bundle.js')); - if (muiIconsCommonFile) essentialBundles.push('/js/' + muiIconsCommonFile); - - const muiCoreFile = jsFiles.find(f => f.startsWith('mui-core.') && f.endsWith('.bundle.js')); - if (muiCoreFile) essentialBundles.push('/js/' + muiCoreFile); - - const vendorFile = jsFiles.find(f => f.startsWith('vendor.') && f.endsWith('.bundle.js')); - if (vendorFile) essentialBundles.push('/js/' + vendorFile); - - // 3. Common shared code - const commonFile = jsFiles.find(f => f.startsWith('common.') && f.endsWith('.chunk.js')); - if (commonFile) essentialBundles.push('/js/' + commonFile); - - // 4. Main bundle (your app code - must be last) - const mainFile = jsFiles.find(f => f.startsWith('main.') && f.endsWith('.bundle.js')); - if (mainFile) essentialBundles.push('/js/' + mainFile); - - jsBundles = essentialBundles; - } - } catch (error) { - console.warn('Could not read webpack output filesystem:', error.message); - } - - // Fallback if we can't read the filesystem - if (jsBundles.length === 0) { - jsBundles = ['/js/runtime.bundle.js', '/js/main.bundle.js']; - } - - // Render the page in memory only (no file writing in dev mode) - 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; - - // Create fresh Emotion cache for this page - const cache = createEmotionCache(); - const { extractCriticalToChunks } = createEmotionServer(cache); - - // Wrap with StaticRouter to provide React Router context for Logo's Link components - const routedComponent = React.createElement( - StaticRouter, - { location: '/404' }, - component - ); - - const pageElement = React.createElement( - CacheProvider, - { value: cache }, - React.createElement(ThemeProvider, { theme: theme }, routedComponent) - ); - - // Render to string - const renderedMarkup = ReactDOMServer.renderToString(pageElement); - const emotionChunks = extractCriticalToChunks(renderedMarkup); - - // Build the full HTML page - const templatePath = path.resolve(__dirname, 'public', 'index.html'); - let template = fs.readFileSync(templatePath, 'utf8'); - - // Add JavaScript bundles - let scriptTags = ''; - jsBundles.forEach(jsFile => { - scriptTags += ``; - }); - - // Add global CSS from src/index.css - let globalCss = ''; - try { - globalCss = fs.readFileSync(path.resolve(__dirname, 'src', 'index.css'), 'utf8'); - // Fix relative font paths for prerendered HTML (remove ../public to make them relative to public root) - globalCss = globalCss.replace(/url\('\.\.\/public/g, "url('"); - } catch (error) { - console.warn('Could not read src/index.css:', error.message); - } - - // Add inline CSS from emotion - let emotionCss = ''; - if (emotionChunks.styles.length > 0) { - emotionChunks.styles.forEach(style => { - if (style.css) { - emotionCss += style.css; - } - }); - } - - // Combine all CSS - const inlineCss = globalCss + emotionCss; - - // Use the rendered markup as-is (no regex replacements) - let processedMarkup = renderedMarkup; - - // Replace placeholders in template - const finalHtml = template - .replace('
', `
${processedMarkup}
`) - .replace('', ``) - .replace('', ` - - ${scriptTags} - `); - - // Serve the prerendered HTML with 404 status - res.status(404); - res.setHeader('Content-Type', 'text/html; charset=utf-8'); - res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); - res.setHeader('Pragma', 'no-cache'); - res.setHeader('Expires', '0'); - return res.send(finalHtml); - - // If we get here, prerender failed - let the error bubble up - throw new Error('404 prerender failed completely'); - } else { - next(); - } - } - }); - - return middlewares; - }, hot: true, port: 9500, open: false, historyApiFallback: { - index: '/index.html', - disableDotRule: true, - htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'], - rewrites: [ - // Exclude prerendered routes from SPA fallback - { from: /^\/Kategorie\//, to: function(context) { - return context.parsedUrl.pathname; - }}, - { from: /^\/Artikel\//, to: function(context) { - return context.parsedUrl.pathname; - }}, - // All other routes should fallback to React SPA - { from: /^\/(?!api|socket\.io|assets|js|css|favicon\.ico).*$/, to: '/index.html' } - ] + index: '/index.html' }, client: { logging: 'verbose',