From 4fd6378aabbffec5f88d7eeb99a505fd50df6894 Mon Sep 17 00:00:00 2001 From: Leendert de Borst Date: Sun, 15 Feb 2026 21:32:42 +0100 Subject: [PATCH] Add minify to web app index.html to save space (#1712) --- .../AliasVault.Client.csproj | 73 ++++++++++++++++++- .../wwwroot/index.template.html | 50 ++++--------- 2 files changed, 85 insertions(+), 38 deletions(-) diff --git a/apps/server/AliasVault.Client/AliasVault.Client.csproj b/apps/server/AliasVault.Client/AliasVault.Client.csproj index cce2c1b8a..e390e131f 100644 --- a/apps/server/AliasVault.Client/AliasVault.Client.csproj +++ b/apps/server/AliasVault.Client/AliasVault.Client.csproj @@ -35,14 +35,83 @@ + (); + var styleBlocks = new System.Collections.Generic.List(); + + content = System.Text.RegularExpressions.Regex.Replace(content, @"(]*>)(.*?)()", + m => { scriptBlocks.Add(m.Groups[2].Value); return m.Groups[1].Value + "___SCRIPT_" + (scriptBlocks.Count - 1) + "___" + m.Groups[3].Value; }, + System.Text.RegularExpressions.RegexOptions.Singleline); + + content = System.Text.RegularExpressions.Regex.Replace(content, @"(]*>)(.*?)()", + m => { styleBlocks.Add(m.Groups[2].Value); return m.Groups[1].Value + "___STYLE_" + (styleBlocks.Count - 1) + "___" + m.Groups[3].Value; }, + System.Text.RegularExpressions.RegexOptions.Singleline); + + // Extract and preserve the header comment (contains ASCII art and license) + var headerMatch = System.Text.RegularExpressions.Regex.Match(content, @"()"); + string headerComment = headerMatch.Success ? headerMatch.Groups[1].Value : ""; + if (headerMatch.Success) + { + content = content.Replace(headerComment, "___HEADER_COMMENT___"); + } + + // Remove all other HTML comments + content = System.Text.RegularExpressions.Regex.Replace(content, @"", "", System.Text.RegularExpressions.RegexOptions.Singleline); + + // Collapse whitespace between tags + content = System.Text.RegularExpressions.Regex.Replace(content, @">\s+<", "><"); + + // Remove leading/trailing whitespace from lines and collapse newlines + content = System.Text.RegularExpressions.Regex.Replace(content, @"^\s+", "", System.Text.RegularExpressions.RegexOptions.Multiline); + content = System.Text.RegularExpressions.Regex.Replace(content, @"\s+$", "", System.Text.RegularExpressions.RegexOptions.Multiline); + content = System.Text.RegularExpressions.Regex.Replace(content, @"\r?\n", ""); + content = System.Text.RegularExpressions.Regex.Replace(content, @" +", " "); + + // Restore script blocks (minify each one) + for (int i = 0; i < scriptBlocks.Count; i++) + { + var script = scriptBlocks[i]; + // Remove JS single-line comments (but not URLs with //) + script = System.Text.RegularExpressions.Regex.Replace(script, @"(?+~])\s*", "$1"); + style = style.Trim(); + content = content.Replace("___STYLE_" + i + "___", style); + } + + // Restore header comment at the end (preserving its formatting) + if (headerMatch.Success) + { + content = content.Replace("___HEADER_COMMENT___", "\n" + headerComment + "\n"); + } + } + File.WriteAllText(OutputFile, content); - Log.LogMessage(MessageImportance.High, "Replaced content in " + OutputFile); + Log.LogMessage(MessageImportance.High, (Minify ? "Minified and replaced" : "Replaced") + " content in " + OutputFile); ]]> @@ -57,7 +126,7 @@ - + diff --git a/apps/server/AliasVault.Client/wwwroot/index.template.html b/apps/server/AliasVault.Client/wwwroot/index.template.html index a30c3c13e..3011815cb 100644 --- a/apps/server/AliasVault.Client/wwwroot/index.template.html +++ b/apps/server/AliasVault.Client/wwwroot/index.template.html @@ -1,26 +1,19 @@ - + AliasVault @@ -157,7 +150,6 @@ if (response.ok) { translations = await response.json(); } else { - // Fallback to English if the language file is not found const fallbackResponse = await fetch('/locales/en.json'); translations = await fallbackResponse.json(); } @@ -200,7 +192,6 @@ } function localizeContent() { - // Localize loading screen const localizations = [ { id: 'loading-title', key: 'loading.title' }, { id: 'loading-message', key: 'loading.message' }, @@ -217,7 +208,6 @@ } }); - // Set random security quote const securityQuotes = getTranslation('quotes.security'); if (securityQuotes && securityQuotes.length > 0) { const quoteElement = document.getElementById('security-quote'); @@ -245,7 +235,7 @@ const minDisplayTime = 1000; const checkInterval = 500; const refreshButtonTimeout = 300000; - const scriptsCheckTimeout = 5000; // Check for blocked scripts after 5 seconds + const scriptsCheckTimeout = 5000; const appElement = document.getElementById('app'); const refreshButton = document.getElementById('refresh-button'); @@ -294,8 +284,6 @@ if (progressText) progressText.classList.add('hidden'); }; - // Detect Blazor boot failures (e.g., after .NET version upgrades) - // This handles transitions between major .NET versions where boot format changes let bootFailureHandled = false; async function handleBlazorBootFailure() { if (bootFailureHandled) return; @@ -304,20 +292,14 @@ console.info('AliasVault: Blazor boot failure detected. Refreshing cached files...'); try { - // Clear service worker caches if ('caches' in window) { const cacheKeys = await caches.keys(); await Promise.all(cacheKeys.map(key => caches.delete(key))); } - - // Unregister service workers if ('serviceWorker' in navigator) { const registrations = await navigator.serviceWorker.getRegistrations(); await Promise.all(registrations.map(r => r.unregister())); } - - // Force browser to fetch fresh versions of critical files - // cache: 'reload' bypasses HTTP cache and updates it with fresh content const criticalFiles = [ '/', '/_framework/blazor.webassembly.js', @@ -329,8 +311,6 @@ } catch (e) { console.error('AliasVault: Cache refresh failed:', e); } - - // Navigate to cache-busted URL to force complete reload with fresh resources const url = new URL(window.location.href); url.searchParams.set('_r', Date.now().toString()); window.location.replace(url.toString()); @@ -347,7 +327,6 @@ if (errorMessage.includes('WebAssembly')) { showError(getTranslation('errors.webAssemblyError')); } - // Detect Blazor boot failures and runtime errors that require a reload else if ( errorMessage.includes('blazor.boot.json') || errorMessage.includes('Failed to load config file') || @@ -387,5 +366,4 @@ }) -