diff --git a/.jules/bolt.md b/.jules/bolt.md index b08b203a..8857c3b6 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -4,3 +4,6 @@ ## 2026-07-12 - Optimize renderTaskRow DOM allocations **Learning:** Caching unattached template nodes and instantiating them via `.cloneNode(false)` reduces DOM instantiation overhead in O(N) render loops significantly. **Action:** Apply this optimization to other hot-path rendering elements such as rows, cells, and stack containers. +## 2026-07-27 - Optimize badge DOM allocations +**Learning:** Expanding the caching strategy (caching unattached template nodes and instantiating them via `.cloneNode(false)`) to cell renderers like owner and status badges reduces JS-to-C++ instantiation overhead during O(N) DOM rendering loops. +**Action:** Always apply template caching to any repeatedly constructed DOM elements in list or table rendering loops. diff --git a/app.js b/app.js index b8c62279..82077364 100644 --- a/app.js +++ b/app.js @@ -952,6 +952,8 @@ function createWarningBadge(warning) { const persistentOwnerColorMap = new Map(); +let ownerBadgeTemplate = null; + function createOwnerCellContent(owner) { if (!owner) { return createEmptyCell(); @@ -961,18 +963,26 @@ function createOwnerCellContent(owner) { persistentOwnerColorMap.set(owner, OWNER_COLORS[persistentOwnerColorMap.size % OWNER_COLORS.length]); } - const badge = document.createElement('span'); - badge.className = 'owner-badge'; + if (!ownerBadgeTemplate) { + ownerBadgeTemplate = document.createElement('span'); + ownerBadgeTemplate.className = 'owner-badge'; + } + const badge = ownerBadgeTemplate.cloneNode(false); badge.style.background = persistentOwnerColorMap.get(owner); badge.textContent = owner; return badge; } +let statusBadgeTemplate = null; + function createStatusCellContent(progressState) { if (!progressState.label) { return createEmptyCell(); } - const badge = document.createElement('span'); + if (!statusBadgeTemplate) { + statusBadgeTemplate = document.createElement('span'); + } + const badge = statusBadgeTemplate.cloneNode(false); badge.className = `status-badge ${progressState.className}`; badge.textContent = progressState.label; if (progressState.description) {