Spaces:
Build error
Build error
| // minify.js | |
| const { minify } = require('html-minifier'); | |
| const cheerio = require('cheerio'); | |
| function sanitizeHtml(html) { | |
| try { | |
| // Remove conditional comments | |
| html = html.replace(/<!--\[if.*?<!\[endif\]-->/gs, ''); | |
| // Fix incomplete URLs | |
| html = html.replace(/src="https?:\/\/[^"]*\.{3}"/g, ''); | |
| // Remove problematic script tags | |
| html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, ''); | |
| return html; | |
| } catch (err) { | |
| console.warn('HTML sanitization failed:', err); | |
| return html; | |
| } | |
| } | |
| function validateHtml(html) { | |
| try { | |
| const $ = cheerio.load(html, { | |
| xmlMode: false, | |
| decodeEntities: false | |
| }); | |
| const issues = []; | |
| if ($('html').length === 0) issues.push('Missing html tag'); | |
| if ($('head').length === 0) issues.push('Missing head tag'); | |
| if ($('body').length === 0) issues.push('Missing body tag'); | |
| return issues; | |
| } catch (err) { | |
| console.warn('HTML validation failed:', err); | |
| return ['Validation error: ' + err.message]; | |
| } | |
| } | |
| function safeMinify(html, options = {}) { | |
| const defaultOptions = { | |
| removeComments: true, | |
| collapseWhitespace: true, | |
| minifyCSS: true, | |
| minifyJS: true, | |
| conservativeCollapse: true, | |
| keepClosingSlash: true, | |
| removeAttributeQuotes: false, | |
| removeEmptyAttributes: true, | |
| removeRedundantAttributes: true, | |
| removeScriptTypeAttributes: false, | |
| removeStyleLinkTypeAttributes: false, | |
| sortAttributes: true, | |
| sortClassName: true | |
| }; | |
| const minifyOptions = { ...defaultOptions, ...options }; | |
| try { | |
| // Try full minification first | |
| return minify(html, minifyOptions); | |
| } catch (err) { | |
| console.warn('Full minification failed, trying conservative mode:', err); | |
| try { | |
| // Fall back to conservative minification | |
| return minify(html, { | |
| removeComments: true, | |
| collapseWhitespace: true, | |
| conservativeCollapse: true, | |
| keepClosingSlash: true, | |
| removeAttributeQuotes: false, | |
| removeEmptyAttributes: false, | |
| removeRedundantAttributes: false | |
| }); | |
| } catch (err2) { | |
| console.error('Conservative minification also failed:', err2); | |
| return html; | |
| } | |
| } | |
| } | |
| function minifyHtml(html, options = {}) { | |
| const result = { | |
| originalSize: html.length, | |
| minifiedHtml: '', | |
| success: false, | |
| issues: [], | |
| stats: {}, | |
| error: null | |
| }; | |
| try { | |
| // Step 1: Validate HTML | |
| const validationIssues = validateHtml(html); | |
| result.issues = validationIssues; | |
| // Step 2: Sanitize HTML | |
| const sanitized = sanitizeHtml(html); | |
| // Step 3: Minify HTML | |
| const minified = safeMinify(sanitized, options); | |
| result.minifiedHtml = minified; | |
| result.success = true; | |
| // Step 4: Calculate stats | |
| result.stats = { | |
| originalSize: html.length, | |
| minifiedSize: minified.length, | |
| reduction: ((html.length - minified.length) / html.length * 100).toFixed(2) + '%', | |
| validationIssues: validationIssues.length, | |
| timestamp: new Date().toISOString() | |
| }; | |
| } catch (err) { | |
| result.error = { | |
| message: err.message, | |
| stack: err.stack | |
| }; | |
| result.minifiedHtml = html; // Return original HTML if processing fails | |
| } | |
| return result; | |
| } | |
| module.exports = { | |
| minifyHtml, | |
| validateHtml, | |
| sanitizeHtml | |
| }; |