#!/usr/bin/env node /** * Build custom highlight.js bundle by downloading and combining CDN files * This creates a single local file with all required languages * * Usage: * node scripts/build-highlight-bundle.js * * This generates a bundle at public/js/highlight-bundle.min.js */ const fs = require('fs'); const path = require('path'); const https = require('https'); // Languages we want to include (in addition to core languages) const additionalLanguages = [ 'rust', 'typescript', 'bash', 'yaml', 'dockerfile', 'sql', 'python', 'ini', // For TOML-like syntax 'properties', // Also TOML-like syntax 'markdown' ]; const CDN_BASE = 'https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0'; function downloadFile(url) { return new Promise((resolve, reject) => { https.get(url, (response) => { if (response.statusCode !== 200) { reject(new Error(`HTTP ${response.statusCode}: ${url}`)); return; } let data = ''; response.on('data', (chunk) => data += chunk); response.on('end', () => resolve(data)); }).on('error', reject); }); } async function buildBundle() { try { // Ensure output directory exists first const outputDir = path.join(__dirname, '../public/js'); if (!fs.existsSync(outputDir)) { fs.mkdirSync(outputDir, { recursive: true }); } // Check if bundle already exists and is recent (less than 24 hours old) const outputPath = path.join(outputDir, 'highlight-bundle.min.js'); if (fs.existsSync(outputPath)) { const stats = fs.statSync(outputPath); const fileAge = Date.now() - stats.mtime.getTime(); const maxAge = 24 * 60 * 60 * 1000; // 24 hours in milliseconds if (fileAge < maxAge) { const fileSizeKB = Math.round(stats.size / 1024); const ageHours = Math.round(fileAge / (60 * 60 * 1000)); console.log('✅ Highlight.js bundle already exists and is recent!'); console.log(`📁 File: ${outputPath}`); console.log(`📊 Size: ${fileSizeKB}KB`); console.log(`⏰ Age: ${ageHours}h (created: ${stats.mtime.toLocaleString()})`); console.log('🎯 Languages: Core JS/HTML/CSS/JSON/XML + ' + additionalLanguages.join(', ')); console.log('💡 To force rebuild, delete the file or wait 24 hours'); return; } else { console.log('🔄 Bundle exists but is older than 24 hours, rebuilding...'); } } console.log('🔨 Building highlight.js bundle from CDN...'); console.log(`📦 Including core + ${additionalLanguages.length} additional languages: ${additionalLanguages.join(', ')}`); // Download core highlight.js console.log('📥 Downloading core highlight.js...'); const coreJs = await downloadFile(`${CDN_BASE}/highlight.min.js`); let bundleContent = `/*! Custom Highlight.js Bundle for Rustelo * Generated on ${new Date().toISOString()} * Core + Additional Languages: ${additionalLanguages.join(', ')} * Based on Highlight.js 11.9.0 from CDN */ // Core highlight.js ${coreJs} // Additional language definitions (function() { if (typeof hljs === 'undefined') { console.error('Highlight.js core not available'); return; } `; // Download and add each language console.log('📝 Downloading language definitions...'); for (const lang of additionalLanguages) { try { console.log(` 📥 Downloading: ${lang}`); const langJs = await downloadFile(`${CDN_BASE}/languages/${lang}.min.js`); // Wrap the language code to register it properly bundleContent += ` // Language: ${lang} (function() { ${langJs} })(); `; console.log(` ✅ Added: ${lang}`); } catch (error) { console.log(` ❌ Failed to download ${lang}: ${error.message}`); } } // Close the bundle bundleContent += ` })(); // Auto-initialize when DOM is ready if (typeof document !== 'undefined') { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function() { if (typeof hljs !== 'undefined' && hljs.highlightAll) { hljs.configure({ ignoreUnescapedHTML: true }); hljs.highlightAll(); } }); } else { // DOM already ready if (typeof hljs !== 'undefined' && hljs.highlightAll) { hljs.configure({ ignoreUnescapedHTML: true }); hljs.highlightAll(); } } } `; // Write the bundle (directory already created at the start) fs.writeFileSync(outputPath, bundleContent); // Get file size const stats = fs.statSync(outputPath); const fileSizeKB = Math.round(stats.size / 1024); console.log(`✅ Highlight.js bundle created successfully!`); console.log(`📁 Output: ${outputPath}`); console.log(`📊 Size: ${fileSizeKB}KB`); console.log(`🎯 Languages: Core JS/HTML/CSS/JSON/XML + ${additionalLanguages.join(', ')}`); console.log(''); console.log('🚀 Ready to use! The bundle includes:'); console.log(' - Auto-initialization on DOM ready'); console.log(' - All required languages pre-registered'); console.log(' - Single HTTP request instead of multiple CDN calls'); } catch (error) { console.error('❌ Error building bundle:', error.message); process.exit(1); } } buildBundle();