#!/usr/bin/env node import { execSync, spawn } from 'child_process'; import { setTimeout } from 'timers/promises'; import fs from 'fs'; import path from 'path'; const isWin = process.platform === 'win32'; const npmCmd = isWin ? 'npm.cmd' : 'npm'; const npxCmd = isWin ? 'npx.cmd' : 'npx'; if (!process.env.SKIP_BUILD) { console.log('Building the React app...'); try { execSync(`${npmCmd} run build`, { stdio: 'inherit', shell: isWin }); } catch (error) { console.error('Build failed:', error.message); process.exit(1); } } else { console.log('Skipping build (SKIP_BUILD=1)'); } // Copy server.js and server folder to dist for iisnode console.log('Copying server files to dist...'); try { // Create dist-specific server.js for iisnode (serves from __dirname, not dist subfolder) const distServerJs = `import express from 'express'; import path from 'path'; import { fileURLToPath } from 'url'; import seoMiddleware from './server/seo-middleware.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const app = express(); const PORT = process.env.PORT || 3000; // Serve static files - __dirname is already dist/ app.use(express.static(__dirname)); // Also mount under /home because Vite base is /home/ app.use('/home', express.static(__dirname)); // Apply SEO middleware for HTML routes app.use(seoMiddleware); app.listen(PORT, () => { console.log(\`Server running on port \${PORT}\`); console.log('Dynamic SEO enabled!'); }); export default app; `; fs.writeFileSync(path.join('dist', 'server.js'), distServerJs, 'utf8'); // Copy server folder to dist if (!fs.existsSync(path.join('dist', 'server'))) { fs.mkdirSync(path.join('dist', 'server')); } // Copy server.js from server folder (if it exists) if (fs.existsSync(path.join('server', 'server.js'))) { fs.copyFileSync( path.join('server', 'server.js'), path.join('dist', 'server', 'server.js') ); } // Create dist-specific seo-middleware.js with correct paths const seoMiddlewareJs = fs.readFileSync(path.join('server', 'seo-middleware.js'), 'utf8'); // Replace the path from ../dist to .. for dist deployment (handle all variations) const distSeoMiddlewareJs = seoMiddlewareJs .replace(/path\.join\(__dirname, '\.\.\/dist'/g, "path.join(__dirname, '..'") .replace(/path\.join\(__dirname, '\.\.', 'dist'/g, "path.join(__dirname, '..'") .replace(/path\.join\(__dirname, '\.\.\/dist',/g, "path.join(__dirname, '..',") .replace(/path\.join\(__dirname, '\.\.\/dist"/g, "path.join(__dirname, '..\"") .replace(/path\.join\(__dirname, '\.\.\/dist',\s*req\.path/g, "path.join(__dirname, '..', req.path"); fs.writeFileSync(path.join('dist', 'server', 'seo-middleware.js'), distSeoMiddlewareJs, 'utf8'); console.log('Server files copied successfully!'); } catch (error) { console.error('Failed to copy server files:', error.message); process.exit(1); } if (process.env.PRERENDER === '1') { let server; try { console.log('Starting development server for prerender...'); server = spawn(npmCmd, ['run', 'dev'], { stdio: 'inherit', shell: isWin }); // Wait for server to start await setTimeout(5000); console.log('Prerendering pages with react-snap...'); execSync(`${npxCmd} react-snap`, { stdio: 'inherit', shell: isWin }); } catch (error) { console.warn('Prerendering skipped due to error (continuing to SEO):', error?.message || error); } finally { if (server) { console.log('Stopping development server...'); server.kill(); } } } else { console.log('Skipping react-snap prerender (set PRERENDER=1 to enable)'); } console.log('Applying SEO optimizations...'); try { execSync('node scripts/generate-seo.js', { stdio: 'inherit', shell: isWin }); } catch (error) { console.error('SEO application failed:', error.message); process.exit(1); } console.log('JSX to HTML conversion completed successfully!');