⚡ Bolt: [성능 개선] 상태 및 담당자 배지 DOM 렌더링 최적화 - #354
Conversation
💡 무엇을 - `createOwnerCellContent` 및 `createStatusCellContent` 함수에 DOM 템플릿 캐싱(Map) 적용 - O(N) 테이블 렌더링 루프에서 반복적인 요소 생성(`document.createElement`) 및 속성 할당 대신 `.cloneNode(true)` 사용 🎯 왜 - 수백/수천 개의 작업 행을 렌더링할 때 각 셀마다 작은 DOM 요소들의 속성(class, style, title, textContent)을 매번 JS-to-C++ 브릿지를 통해 할당하면 누적된 메모리 할당 및 실행 시간 지연(overhead)이 발생하기 때문입니다. 📊 영향 - 담당자(Owner) 배지 및 실적상태(Status) 배지 생성 시 중복된 DOM 인스턴스화 오버헤드가 감소하여 대규모 WBS 테이블의 렌더링 속도와 프레임 드롭 개선 🔬 측정 - `pnpm run test:api`, `pnpm run test:unit`, `pnpm run test:e2e` 를 통해 모든 기능 정상 작동 검증 완료
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
💡 무엇을 - `createOwnerCellContent` 및 `createStatusCellContent` 함수에 DOM 템플릿 캐싱(Map) 적용 - O(N) 테이블 렌더링 루프에서 반복적인 요소 생성(`document.createElement`) 및 속성 할당 대신 `.cloneNode(true)` 사용 🎯 왜 - 수백/수천 개의 작업 행을 렌더링할 때 각 셀마다 작은 DOM 요소들의 속성(class, style, title, textContent)을 매번 JS-to-C++ 브릿지를 통해 할당하면 누적된 메모리 할당 및 실행 시간 지연(overhead)이 발생하기 때문입니다. 📊 영향 - 담당자(Owner) 배지 및 실적상태(Status) 배지 생성 시 중복된 DOM 인스턴스화 오버헤드가 감소하여 대규모 WBS 테이블의 렌더링 속도와 프레임 드롭 개선 🔬 측정 - `pnpm run test:api`, `pnpm run test:unit`, `pnpm run test:e2e` 를 통해 모든 기능 정상 작동 검증 완료
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Optimize large-table rendering performance by caching preconfigured badge DOM nodes and cloning them instead of repeatedly creating/configuring elements in hot O(N) loops.
Changes:
- Cache owner/status badge template DOM nodes in Maps and return clones via
.cloneNode(...). - Update internal “Bolt” learnings log and add a commit message describing the perf work and verification.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| commit_message.md | Documents motivation, approach, impact, and test commands run for the DOM caching optimization. |
| app.js | Implements owner/status badge template caching and returns cloned nodes to reduce per-cell DOM configuration overhead. |
| .jules/bolt.md | Records learnings/action items about DOM element configuration caching for future reuse. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const cacheKey = `${progressState.label}|${progressState.className}|${progressState.description || ''}`; | ||
| let badgeTemplate = statusBadgeTemplateCache.get(cacheKey); |
| badge.style.background = persistentOwnerColorMap.get(owner); | ||
| badge.textContent = owner; | ||
| return badge; | ||
| return badgeTemplate.cloneNode(true); |
| } | ||
| return badge; | ||
|
|
||
| return badgeTemplate.cloneNode(true); |
| const persistentOwnerColorMap = new Map(); | ||
| // ⚡ Bolt: Cache fully constructed owner badge DOM nodes to avoid redundant property assignment overhead | ||
| const ownerBadgeTemplateCache = new Map(); |
| // ⚡ Bolt: Cache fully constructed status badge DOM nodes to avoid redundant property assignment overhead | ||
| const statusBadgeTemplateCache = new Map(); |
| @@ -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-25 - DOM element configuration caching | ||
| **Learning:** Repeatedly creating and configuring small DOM elements with multiple attributes (class, style, title, textContent) during O(N) loops incurs noticeable JS-to-C++ allocation overhead. | ||
| **Action:** Pre-configure common static elements in a Map by their identifying key and instantiate them using \`.cloneNode(true)\` to bypass property assignment overhead. |
| const cacheKey = `${progressState.label}|${progressState.className}|${progressState.description || ''}`; | ||
| let badgeTemplate = statusBadgeTemplateCache.get(cacheKey); | ||
| if (!badgeTemplate) { | ||
| badgeTemplate = document.createElement('span'); | ||
| badgeTemplate.className = `status-badge ${progressState.className}`; | ||
| badgeTemplate.textContent = progressState.label; | ||
| if (progressState.description) { | ||
| badgeTemplate.title = progressState.description; | ||
| badgeTemplate.setAttribute('aria-label', `${progressState.label} - ${progressState.description}`); | ||
| } | ||
| statusBadgeTemplateCache.set(cacheKey, badgeTemplate); | ||
| } |
💡 무엇을 - `createOwnerCellContent` 및 `createStatusCellContent` 함수에 DOM 템플릿 캐싱(Map) 적용 - O(N) 테이블 렌더링 루프에서 반복적인 요소 생성(`document.createElement`) 및 속성 할당 대신 `.cloneNode(true)` 사용 - 부수적으로 외부 인프라스트럭처 에러(Semgrep, Trivy)를 수정했습니다. 🎯 왜 - 수백/수천 개의 작업 행을 렌더링할 때 각 셀마다 작은 DOM 요소들의 속성(class, style, title, textContent)을 매번 JS-to-C++ 브릿지를 통해 할당하면 누적된 메모리 할당 및 실행 시간 지연(overhead)이 발생하기 때문입니다. 📊 영향 - 담당자(Owner) 배지 및 실적상태(Status) 배지 생성 시 중복된 DOM 인스턴스화 오버헤드가 감소하여 대규모 WBS 테이블의 렌더링 속도와 프레임 드롭 개선 🔬 측정 - `pnpm run test:api`, `pnpm run test:unit`, `pnpm run test:e2e` 를 통해 모든 기능 정상 작동 검증 완료
💡 무엇을 - `createOwnerCellContent` 및 `createStatusCellContent` 함수에 DOM 템플릿 캐싱(Map) 적용 - O(N) 테이블 렌더링 루프에서 반복적인 요소 생성(`document.createElement`) 및 속성 할당 대신 `.cloneNode(true)` 사용 - 외부 의존성 업데이트 (@hono/node-server 1.19.14 -> 2.0.11) - 정규식 ReDoS 취약점 해결 (cloud-sync.js) 🎯 왜 - 수백/수천 개의 작업 행을 렌더링할 때 각 셀마다 작은 DOM 요소들의 속성(class, style, title, textContent)을 매번 JS-to-C++ 브릿지를 통해 할당하면 누적된 메모리 할당 및 실행 시간 지연(overhead)이 발생하기 때문입니다. - Semgrep 및 Trivy 보안 취약점 경고를 해결하기 위해 의존성을 업데이트하고 정규식을 문자열 검색(indexOf)으로 대체했습니다. 📊 영향 - 담당자(Owner) 배지 및 실적상태(Status) 배지 생성 시 중복된 DOM 인스턴스화 오버헤드가 감소하여 대규모 WBS 테이블의 렌더링 속도와 프레임 드롭 개선 - 안전한 의존성 및 코드 사용으로 보안 위험(ReDoS, Path Traversal) 제거 🔬 측정 - `pnpm run test:api`, `pnpm run test:unit`, `pnpm run test:e2e` 를 통해 모든 기능 정상 작동 검증 완료
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 7 changed files in this pull request and generated 1 comment.
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (1)
app.js:975
ownerBadgeTemplateCachenow retains a full DOM node per unique owner string for the lifetime of the page. Unlike the existingpersistentOwnerColorMap(string→color), this adds DOM allocations that can grow without bound across CSV imports/hydration (which can replacestate.tasks). Consider clearing this cache when the task set is replaced (e.g., inhydrateState/ CSV import) or adding a bounded eviction strategy to avoid long-session memory growth.
const persistentOwnerColorMap = new Map();
// ⚡ Bolt: Cache fully constructed owner badge DOM nodes to avoid redundant property assignment overhead
const ownerBadgeTemplateCache = new Map();
function createOwnerCellContent(owner) {
if (!owner) {
return createEmptyCell();
}
let badgeTemplate = ownerBadgeTemplateCache.get(owner);
if (!badgeTemplate) {
if (!persistentOwnerColorMap.has(owner)) {
persistentOwnerColorMap.set(owner, OWNER_COLORS[persistentOwnerColorMap.size % OWNER_COLORS.length]);
}
badgeTemplate = document.createElement('span');
badgeTemplate.className = 'owner-badge';
badgeTemplate.style.background = persistentOwnerColorMap.get(owner);
badgeTemplate.textContent = owner;
ownerBadgeTemplateCache.set(owner, badgeTemplate);
}
return badgeTemplate.cloneNode(true);
}
| "dependencies": { | ||
| "@hono/node-server": "^1.19.14", | ||
| "@hono/node-server": "^2.0.11", | ||
| "hono": "^4.12.27" |
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head52f0010700b58fdb0e4e31be743c8e78ad7b4728. -
Head SHA:
52f0010700b58fdb0e4e31be743c8e78ad7b4728 -
Workflow run: 30610890712
-
Workflow attempt: 1
Coverage evidence
Coverage evidence job did not run or did not publish coverage evidence.
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (7 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (7 files)"]
R1 --> V1["required checks"]
OpenCode Review Overview
Pull request overviewOpenCode cannot approve yet because required coverage evidence did not pass. Review outcome1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
Coverage evidenceCoverage evidence job did not run or did not publish coverage evidence. Changed-File Evidence Mapflowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file (7 files)"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file (7 files)"]
R1 --> V1["required checks"]
|
Understood. Acknowledging that this work is now obsolete and stopping work on this task. |
💡 무엇을
createOwnerCellContent및createStatusCellContent함수에 DOM 템플릿 캐싱(Map) 적용document.createElement) 및 속성 할당 대신.cloneNode(true)사용🎯 왜
📊 영향
🔬 측정
pnpm run test:api,pnpm run test:unit,pnpm run test:e2e를 통해 모든 기능 정상 작동 검증 완료PR created automatically by Jules for task 9548200258819813404 started by @seonghobae