const fs = require('fs').promises; const path = require('path'); // Helper function to extract content between delimeters function extractBlock(content, startDelimiter, endDelimiter) { const startIndex = content.indexOf(startDelimiter); if (startIndex === -1) return { blockContent: '', remainingContent: content }; const endIndex = content.indexOf(endDelimiter, startIndex + startDelimiter.length); if (endIndex === -1) return { blockContent: '', remainingContent: content }; // Or throw error const block = content.substring(startIndex + startDelimiter.length, endIndex).trim(); const remaining = content.substring(0, startIndex) + content.substring(endIndex + endDelimiter.length); return { blockContent: block, remainingContent: remaining.trim() }; } // Helper function to copy files recursively async function copyWebsiteFiles() { const websiteDir = path.join(__dirname, 'website'); const buildDir = path.join(__dirname, 'build'); try { const websiteExists = await fs.access(websiteDir).then(() => true).catch(() => false); if (!websiteExists) { console.log("No website directory found, skipping copy."); return; } async function copyRecursive(src, dest) { const stats = await fs.stat(src); if (stats.isDirectory()) { await fs.mkdir(dest, { recursive: true }); const items = await fs.readdir(src); for (const item of items) { const srcPath = path.join(src, item); const destPath = path.join(dest, item); await copyRecursive(srcPath, destPath); } } else { await fs.copyFile(src, dest); } } await copyRecursive(websiteDir, buildDir); console.log("Website files copied successfully."); } catch (error) { console.error('Error copying website files:', error); throw error; } } async function buildPage(pageName, outputName) { const layoutPath = path.join(__dirname, 'templates', '_layout.html'); const commonHeaderPath = path.join(__dirname, 'templates', '_header.html'); const commonFooterPath = path.join(__dirname, 'templates', '_footer.html'); const contentPath = path.join(__dirname, 'src', `${pageName}.html`); const outputDir = path.join(__dirname, 'build'); const outputPath = path.join(outputDir, `${outputName}.html`); try { // Ensure the build directory exists await fs.mkdir(outputDir, { recursive: true }); let layoutContent = await fs.readFile(layoutPath, 'utf-8'); const srcFileContent = await fs.readFile(contentPath, 'utf-8'); // Extract metadata const metadataRegex = //; const metadataMatch = srcFileContent.match(metadataRegex); let metadata = {}; let mainPageContent = srcFileContent; if (metadataMatch && metadataMatch[1]) { try { metadata = JSON.parse(metadataMatch[1].trim()); } catch (e) { console.error(`Error parsing metadata JSON for ${pageName}.html:`, e); } mainPageContent = srcFileContent.replace(metadataRegex, '').trim(); } // Defaults for metadata const defaults = { title: "Litruv", metaDescription: "Litruv's personal website.", csp: "script-src 'self' 'unsafe-inline';", ogTitle: "Litruv", ogDescription: "Litruv's personal website.", ogUrl: "https://lit.ruv.wtf", twitterTitle: "Litruv", twitterDescription: "Litruv's personal website.", twitterUrl: "https://lit.ruv.wtf", pageSpecificStyles: "", pageSpecificScriptsDefer: "", pageSpecificScriptsBodyEnd: "", useCommonHeader: true, useCommonFooter: true }; const finalMetadata = { ...defaults, ...metadata }; // Extract page-specific styles const stylesExtraction = extractBlock(mainPageContent, '', ''); finalMetadata.pageSpecificStyles = stylesExtraction.blockContent; mainPageContent = stylesExtraction.remainingContent; // Extract page-specific defer scripts const deferScriptsExtraction = extractBlock(mainPageContent, '', ''); finalMetadata.pageSpecificScriptsDefer = deferScriptsExtraction.blockContent; mainPageContent = deferScriptsExtraction.remainingContent; // Extract page-specific body-end scripts const bodyEndScriptsExtraction = extractBlock(mainPageContent, '', ''); finalMetadata.pageSpecificScriptsBodyEnd = bodyEndScriptsExtraction.blockContent; mainPageContent = bodyEndScriptsExtraction.remainingContent; // Replace metadata placeholders in layout layoutContent = layoutContent.replace(//g, finalMetadata.title) .replace(//g, finalMetadata.metaDescription) .replace(//g, finalMetadata.csp) .replace(//g, finalMetadata.ogTitle) .replace(//g, finalMetadata.ogDescription) .replace(//g, finalMetadata.ogUrl) .replace(//g, finalMetadata.twitterTitle) .replace(//g, finalMetadata.twitterDescription) .replace(//g, finalMetadata.twitterUrl) .replace(//g, finalMetadata.pageSpecificStyles) .replace(//g, finalMetadata.pageSpecificScriptsDefer) .replace(//g, finalMetadata.pageSpecificScriptsBodyEnd); // Handle common header and footer const headerContentToInject = finalMetadata.useCommonHeader ? await fs.readFile(commonHeaderPath, 'utf-8') : ''; const footerContentToInject = finalMetadata.useCommonFooter ? await fs.readFile(commonFooterPath, 'utf-8') : ''; layoutContent = layoutContent.replace('', headerContentToInject); layoutContent = layoutContent.replace('', footerContentToInject); layoutContent = layoutContent.replace('', mainPageContent); await fs.writeFile(outputPath, layoutContent, 'utf-8'); console.log(`Successfully built ${outputPath}`); } catch (error) { console.error(`Error building page ${pageName}:`, error); throw error; // Re-throw to fail the build process if needed } } async function main() { try { // Copy website files first await copyWebsiteFiles(); const srcDir = path.join(__dirname, 'src'); const files = await fs.readdir(srcDir); const htmlFiles = files.filter(file => file.endsWith('.html')); if (htmlFiles.length === 0) { console.log("No HTML files found in src directory to build."); return; } for (const file of htmlFiles) { const pageName = path.parse(file).name; const outputName = pageName; await buildPage(pageName, outputName); } console.log("All pages built successfully."); } catch (error) { console.error('Build process failed:', error); process.exit(1); } } main();