#!/usr/bin/env node /** * HexaHost.de Build Script * * Obfusciert JavaScript und minifiziert CSS für die Produktion * * Verwendung: * npm run build - Alles bauen * npm run build:js - Nur JavaScript * npm run build:css - Nur CSS */ const fs = require('fs'); const path = require('path'); const JavaScriptObfuscator = require('javascript-obfuscator'); const CleanCSS = require('clean-css'); // Konfiguration const config = { srcDir: path.join(__dirname, '..'), distDir: path.join(__dirname, '..', 'dist'), // JavaScript-Dateien zum Obfuscieren jsFiles: [ 'assets/js/main.js', 'assets/js/contact.js', 'assets/js/cookie-consent.js' ], // CSS-Dateien zum Minifizieren cssFiles: [ 'assets/css/style.css' ], // PHP-Dateien (nur kopieren) phpFiles: [ 'config/config.php', 'config/mail-config.php', 'config/products-config.php', 'includes/header.php', 'includes/footer.php', 'includes/functions.php' ], // JavaScript Obfuscator Optionen jsObfuscatorOptions: { compact: true, controlFlowFlattening: true, controlFlowFlatteningThreshold: 0.7, deadCodeInjection: true, deadCodeInjectionThreshold: 0.4, debugProtection: false, disableConsoleOutput: true, identifierNamesGenerator: 'hexadecimal', log: false, numbersToExpressions: true, renameGlobals: false, selfDefending: true, simplify: true, splitStrings: true, splitStringsChunkLength: 10, stringArray: true, stringArrayCallsTransform: true, stringArrayEncoding: ['base64'], stringArrayIndexShift: true, stringArrayRotate: true, stringArrayShuffle: true, stringArrayWrappersCount: 2, stringArrayWrappersChainedCalls: true, stringArrayWrappersParametersMaxCount: 4, stringArrayWrappersType: 'function', stringArrayThreshold: 0.75, transformObjectKeys: true, unicodeEscapeSequence: false }, // Clean-CSS Optionen cssMinifyOptions: { level: { 1: { specialComments: 0 }, 2: { mergeMedia: true, removeEmpty: true, removeDuplicateFontRules: true, removeDuplicateMediaBlocks: true, removeDuplicateRules: true } } } }; // Hilfsfunktionen function ensureDir(dir) { if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } } function copyFile(src, dest) { ensureDir(path.dirname(dest)); fs.copyFileSync(src, dest); } function formatBytes(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } function getCompressionRatio(original, compressed) { return ((1 - compressed / original) * 100).toFixed(1); } // JavaScript obfuscieren function obfuscateJS(filePath) { const srcPath = path.join(config.srcDir, filePath); const destPath = path.join(config.distDir, filePath); if (!fs.existsSync(srcPath)) { console.log(` ⚠️ Datei nicht gefunden: ${filePath}`); return null; } const originalCode = fs.readFileSync(srcPath, 'utf8'); const originalSize = Buffer.byteLength(originalCode, 'utf8'); try { const obfuscatedCode = JavaScriptObfuscator.obfuscate( originalCode, config.jsObfuscatorOptions ).getObfuscatedCode(); const obfuscatedSize = Buffer.byteLength(obfuscatedCode, 'utf8'); ensureDir(path.dirname(destPath)); fs.writeFileSync(destPath, obfuscatedCode); return { file: filePath, originalSize, newSize: obfuscatedSize, ratio: getCompressionRatio(originalSize, obfuscatedSize) }; } catch (error) { console.log(` ❌ Fehler bei ${filePath}: ${error.message}`); return null; } } // CSS minifizieren function minifyCSS(filePath) { const srcPath = path.join(config.srcDir, filePath); const destPath = path.join(config.distDir, filePath); if (!fs.existsSync(srcPath)) { console.log(` ⚠️ Datei nicht gefunden: ${filePath}`); return null; } const originalCode = fs.readFileSync(srcPath, 'utf8'); const originalSize = Buffer.byteLength(originalCode, 'utf8'); try { const minified = new CleanCSS(config.cssMinifyOptions).minify(originalCode); if (minified.errors.length > 0) { console.log(` ❌ Fehler bei ${filePath}: ${minified.errors.join(', ')}`); return null; } const minifiedSize = Buffer.byteLength(minified.styles, 'utf8'); ensureDir(path.dirname(destPath)); fs.writeFileSync(destPath, minified.styles); return { file: filePath, originalSize, newSize: minifiedSize, ratio: getCompressionRatio(originalSize, minifiedSize) }; } catch (error) { console.log(` ❌ Fehler bei ${filePath}: ${error.message}`); return null; } } // PHP-Dateien kopieren (keine Obfuscation) function copyPHP(filePath) { const srcPath = path.join(config.srcDir, filePath); const destPath = path.join(config.distDir, filePath); if (!fs.existsSync(srcPath)) { console.log(` ⚠️ Datei nicht gefunden: ${filePath}`); return null; } try { copyFile(srcPath, destPath); const size = fs.statSync(srcPath).size; return { file: filePath, originalSize: size, newSize: size, ratio: '0' }; } catch (error) { console.log(` ❌ Fehler bei ${filePath}: ${error.message}`); return null; } } // Hauptfunktion function build() { const args = process.argv.slice(2); const jsOnly = args.includes('--js-only'); const cssOnly = args.includes('--css-only'); console.log('\n╔════════════════════════════════════════════════════════════╗'); console.log('║ HexaHost.de - Build System ║'); console.log('║ Obfuscation & Minification ║'); console.log('╚════════════════════════════════════════════════════════════╝\n'); // dist-Verzeichnis erstellen/leeren if (fs.existsSync(config.distDir)) { fs.rmSync(config.distDir, { recursive: true }); } ensureDir(config.distDir); const results = []; // JavaScript obfuscieren if (!cssOnly) { console.log('📦 JavaScript obfuscieren...\n'); config.jsFiles.forEach(file => { process.stdout.write(` → ${file}... `); const result = obfuscateJS(file); if (result) { console.log(`✓ (${formatBytes(result.originalSize)} → ${formatBytes(result.newSize)}, -${result.ratio}%)`); results.push(result); } }); console.log(); } // CSS minifizieren if (!jsOnly) { console.log('🎨 CSS minifizieren...\n'); config.cssFiles.forEach(file => { process.stdout.write(` → ${file}... `); const result = minifyCSS(file); if (result) { console.log(`✓ (${formatBytes(result.originalSize)} → ${formatBytes(result.newSize)}, -${result.ratio}%)`); results.push(result); } }); console.log(); } // PHP-Dateien kopieren if (!jsOnly && !cssOnly) { console.log('📄 PHP-Dateien kopieren...\n'); config.phpFiles.forEach(file => { process.stdout.write(` → ${file}... `); const result = copyPHP(file); if (result) { console.log(`✓ (${formatBytes(result.originalSize)})`); results.push(result); } }); console.log(); } // Zusammenfassung const totalOriginal = results.reduce((sum, r) => sum + r.originalSize, 0); const totalNew = results.reduce((sum, r) => sum + r.newSize, 0); console.log('═══════════════════════════════════════════════════════════════'); console.log(`✅ Build abgeschlossen!`); console.log(` Dateien: ${results.length}`); console.log(` Original: ${formatBytes(totalOriginal)}`); console.log(` Optimiert: ${formatBytes(totalNew)}`); console.log(` Ersparnis: ${formatBytes(totalOriginal - totalNew)} (${getCompressionRatio(totalOriginal, totalNew)}%)`); console.log(` Ausgabe: ${config.distDir}`); console.log('═══════════════════════════════════════════════════════════════\n'); } // Build starten build();