mirror of
https://github.com/litruv/lit.ruv.wtf.git
synced 2026-07-24 02:36:02 +10:00
177 lines
7.9 KiB
JavaScript
177 lines
7.9 KiB
JavaScript
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 = /<!--\s*METADATA:([\s\S]*?)-->/;
|
|
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, '<!-- START_STYLES -->', '<!-- END_STYLES -->');
|
|
finalMetadata.pageSpecificStyles = stylesExtraction.blockContent;
|
|
mainPageContent = stylesExtraction.remainingContent;
|
|
|
|
// Extract page-specific defer scripts
|
|
const deferScriptsExtraction = extractBlock(mainPageContent, '<!-- START_SCRIPTS_DEFER -->', '<!-- END_SCRIPTS_DEFER -->');
|
|
finalMetadata.pageSpecificScriptsDefer = deferScriptsExtraction.blockContent;
|
|
mainPageContent = deferScriptsExtraction.remainingContent;
|
|
|
|
// Extract page-specific body-end scripts
|
|
const bodyEndScriptsExtraction = extractBlock(mainPageContent, '<!-- START_SCRIPTS_BODY_END -->', '<!-- END_SCRIPTS_BODY_END -->');
|
|
finalMetadata.pageSpecificScriptsBodyEnd = bodyEndScriptsExtraction.blockContent;
|
|
mainPageContent = bodyEndScriptsExtraction.remainingContent;
|
|
|
|
// Replace metadata placeholders in layout
|
|
layoutContent = layoutContent.replace(/<!-- ::PAGE_TITLE:: -->/g, finalMetadata.title)
|
|
.replace(/<!-- ::META_DESCRIPTION:: -->/g, finalMetadata.metaDescription)
|
|
.replace(/<!-- ::PAGE_CSP:: -->/g, finalMetadata.csp)
|
|
.replace(/<!-- ::OG_TITLE:: -->/g, finalMetadata.ogTitle)
|
|
.replace(/<!-- ::OG_DESCRIPTION:: -->/g, finalMetadata.ogDescription)
|
|
.replace(/<!-- ::OG_URL:: -->/g, finalMetadata.ogUrl)
|
|
.replace(/<!-- ::TWITTER_TITLE:: -->/g, finalMetadata.twitterTitle)
|
|
.replace(/<!-- ::TWITTER_DESCRIPTION:: -->/g, finalMetadata.twitterDescription)
|
|
.replace(/<!-- ::TWITTER_URL:: -->/g, finalMetadata.twitterUrl)
|
|
.replace(/<!-- ::PAGE_SPECIFIC_STYLES:: -->/g, finalMetadata.pageSpecificStyles)
|
|
.replace(/<!-- ::PAGE_SPECIFIC_SCRIPTS_DEFER:: -->/g, finalMetadata.pageSpecificScriptsDefer)
|
|
.replace(/<!-- ::PAGE_SPECIFIC_SCRIPTS_BODY_END:: -->/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('<!-- ::HEADER:: -->', headerContentToInject);
|
|
layoutContent = layoutContent.replace('<!-- ::FOOTER:: -->', footerContentToInject);
|
|
layoutContent = layoutContent.replace('<!-- ::CONTENT:: -->', 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();
|