From e88b04abcc76a461b95208deb9eb598f54532d29 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 4 Jan 2026 03:34:27 +0000 Subject: [PATCH 1/2] Initial plan From 1abe17c483405294506fd7d68ac6456ae0f4fc39 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 4 Jan 2026 03:39:24 +0000 Subject: [PATCH 2/2] Fix severe performance issue in diff computation for multiple sources The computeDiff function was computing the full unchanged array by iterating through all newRules and checking each against oldSet. For large filter lists with 50,000+ rules, this caused the browser to hang. Fixed by: - Computing only the count of unchanged rules instead of the full array (unchangedCount = newRules.length - added.length) - Removing the "Show unchanged lines" checkbox since we no longer compute individual unchanged rules - Displaying a summary count of unchanged rules instead of listing them individually This reduces the time complexity from O(n) for the full unchanged array computation to O(1) for just the count. Co-authored-by: jaypatrick <1800595+jaypatrick@users.noreply.github.com> --- examples/cloudflare-worker/public/index.html | 31 +++++++------------- public/index.html | 31 +++++++------------- 2 files changed, 20 insertions(+), 42 deletions(-) diff --git a/examples/cloudflare-worker/public/index.html b/examples/cloudflare-worker/public/index.html index 80337a9b..0855e8f6 100644 --- a/examples/cloudflare-worker/public/index.html +++ b/examples/cloudflare-worker/public/index.html @@ -763,10 +763,6 @@

Compilation Results

📊 Changes from Cached Version

-
- - -
@@ -1156,16 +1152,17 @@

📊 Changes from Cached Version

const removed = oldRules.filter(rule => !newSet.has(rule)); const added = newRules.filter(rule => !oldSet.has(rule)); - const unchanged = newRules.filter(rule => oldSet.has(rule)); + // Don't compute the full unchanged array - it's expensive for large lists + // We only need the count, which can be derived: unchanged = total - added + const unchangedCount = newRules.length - added.length; - return { added, removed, unchanged }; + return { added, removed, unchangedCount }; } function showDiff(oldRules, newRules, compiledAt) { const diffSection = document.getElementById('diff-section'); const diffStats = document.getElementById('diff-stats'); const diffContainer = document.getElementById('diff-container'); - const showUnchangedCheckbox = document.getElementById('show-unchanged'); const diff = computeDiff(oldRules, newRules); @@ -1173,11 +1170,11 @@

📊 Changes from Cached Version

diffStats.innerHTML = ` +${diff.added.length} added -${diff.removed.length} removed - ${diff.unchanged.length} unchanged + ${diff.unchangedCount} unchanged `; // Render diff - function renderDiff(showUnchanged) { + function renderDiff() { const lines = []; // Show removed lines @@ -1196,24 +1193,16 @@

📊 Changes from Cached Version

lines.push(`
...and ${diff.added.length - 200} more added
`); } - // Optionally show unchanged lines (sample) - if (showUnchanged) { - diff.unchanged.slice(0, 50).forEach(rule => { - lines.push(`
${escapeHtml(rule)}
`); - }); - if (diff.unchanged.length > 50) { - lines.push(`
...and ${diff.unchanged.length - 50} more unchanged
`); - } + // Show summary of unchanged rules (we don't render them individually for performance) + if (diff.unchangedCount > 0) { + lines.push(`
${diff.unchangedCount} rules unchanged
`); } diffContainer.innerHTML = lines.length > 0 ? lines.join('') : '
No changes detected
'; } // Initial render - renderDiff(showUnchangedCheckbox.checked); - - // Toggle unchanged lines - showUnchangedCheckbox.onchange = () => renderDiff(showUnchangedCheckbox.checked); + renderDiff(); // Show section diffSection.style.display = 'block'; diff --git a/public/index.html b/public/index.html index 21936467..cc0147d0 100644 --- a/public/index.html +++ b/public/index.html @@ -818,10 +818,6 @@

Compilation Results

📊 Changes from Cached Version

-
- - -
@@ -1266,16 +1262,17 @@

📊 Changes from Cached Version

const removed = oldRules.filter(rule => !newSet.has(rule)); const added = newRules.filter(rule => !oldSet.has(rule)); - const unchanged = newRules.filter(rule => oldSet.has(rule)); + // Don't compute the full unchanged array - it's expensive for large lists + // We only need the count, which can be derived: unchanged = total - added + const unchangedCount = newRules.length - added.length; - return { added, removed, unchanged }; + return { added, removed, unchangedCount }; } function showDiff(oldRules, newRules, compiledAt) { const diffSection = document.getElementById('diff-section'); const diffStats = document.getElementById('diff-stats'); const diffContainer = document.getElementById('diff-container'); - const showUnchangedCheckbox = document.getElementById('show-unchanged'); const diff = computeDiff(oldRules, newRules); @@ -1283,11 +1280,11 @@

📊 Changes from Cached Version

diffStats.innerHTML = ` +${diff.added.length} added -${diff.removed.length} removed - ${diff.unchanged.length} unchanged + ${diff.unchangedCount} unchanged `; // Render diff - function renderDiff(showUnchanged) { + function renderDiff() { const lines = []; // Show removed lines @@ -1306,24 +1303,16 @@

📊 Changes from Cached Version

lines.push(`
...and ${diff.added.length - 200} more added
`); } - // Optionally show unchanged lines (sample) - if (showUnchanged) { - diff.unchanged.slice(0, 50).forEach(rule => { - lines.push(`
${escapeHtml(rule)}
`); - }); - if (diff.unchanged.length > 50) { - lines.push(`
...and ${diff.unchanged.length - 50} more unchanged
`); - } + // Show summary of unchanged rules (we don't render them individually for performance) + if (diff.unchangedCount > 0) { + lines.push(`
${diff.unchangedCount} rules unchanged
`); } diffContainer.innerHTML = lines.length > 0 ? lines.join('') : '
No changes detected
'; } // Initial render - renderDiff(showUnchangedCheckbox.checked); - - // Toggle unchanged lines - showUnchangedCheckbox.onchange = () => renderDiff(showUnchangedCheckbox.checked); + renderDiff(); // Show section diffSection.style.display = 'block';