diff --git a/.jules/bolt.md b/.jules/bolt.md index b08b203a..dd876299 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-12 - Inline ternary concatenation vs String.padStart() +**Learning:** Using `String.padStart()` in O(N) hot loops (like date formatters) creates unnecessary string allocations and JS-to-C++ overhead. +**Action:** Prefer using inline ternary string concatenation (e.g., `m < 10 ? '0' : ''`) for simple string formatting in performance-critical paths to reduce GC pressure and execution time. diff --git a/app.js b/app.js index a04aae71..aaa9584c 100644 --- a/app.js +++ b/app.js @@ -2682,22 +2682,27 @@ function clamp(value, min, max) { return Math.min(max, Math.max(min, value)); } +// ⚡ Bolt: 불필요한 문자열 할당 및 JS-to-C++ 오버헤드를 방지하기 위해 +// O(N) 반복 구간(hot path)에서 String.padStart() 대신 인라인 삼항 연산자를 사용합니다. function formatDateInput(date) { const year = date.getUTCFullYear(); - const month = String(date.getUTCMonth() + 1).padStart(2, '0'); - const day = String(date.getUTCDate()).padStart(2, '0'); - return `${year}-${month}-${day}`; + const m = date.getUTCMonth() + 1; + const d = date.getUTCDate(); + return `${year}-${m < 10 ? '0' : ''}${m}-${d < 10 ? '0' : ''}${d}`; } function formatLocalDateInput(date) { const year = date.getFullYear(); - const month = String(date.getMonth() + 1).padStart(2, '0'); - const day = String(date.getDate()).padStart(2, '0'); - return `${year}-${month}-${day}`; + const m = date.getMonth() + 1; + const d = date.getDate(); + return `${year}-${m < 10 ? '0' : ''}${m}-${d < 10 ? '0' : ''}${d}`; } function formatCompactDate(date) { - return `${date.getFullYear()}${String(date.getMonth() + 1).padStart(2, '0')}${String(date.getDate()).padStart(2, '0')}`; + const y = date.getFullYear(); + const m = date.getMonth() + 1; + const d = date.getDate(); + return `${y}${m < 10 ? '0' : ''}${m}${d < 10 ? '0' : ''}${d}`; } function formatPercent(value, digits) { diff --git a/index.html b/index.html index a7f4b49c..cda50f78 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,8 @@ ScopeWeave Planner + + diff --git a/package-lock.json b/package-lock.json index 079e2031..a1c5e22b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "dependencies": { "@hono/node-server": "^2.0.12", - "hono": "^4.12.32" + "hono": "^4.13.1" }, "devDependencies": { "@playwright/test": "1.61.1", @@ -31,9 +31,9 @@ } }, "node_modules/@hono/node-server": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.0.12.tgz", - "integrity": "sha512-eWpQYr67tqJLeaSUl0Q+TquuYfUdTibpOJlUMV2FfUP7+KqCC5TufnwnlXL6mobZBJbGAYRd7ZvEBDCbLInjhg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.0.tgz", + "integrity": "sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==", "license": "MIT", "engines": { "node": ">=20" @@ -382,9 +382,9 @@ } }, "node_modules/hono": { - "version": "4.12.32", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.32.tgz", - "integrity": "sha512-XcuyW9qE2kJn07PkecMOBd5Vq/hMy7mmGw+idz1yblbg9N17ijJODrvPkn7/dwL3Kulj8LcRJ69DLOWf91dRUg==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.1.tgz", + "integrity": "sha512-kdJoFVv2xmayw6cY09H7AbMJMt8Jn5jdlEdXsP7AGBdF2DIptVlKlOLKXP41yPip4/a3yQPv9gVcJYI8YY04dw==", "license": "MIT", "engines": { "node": ">=16.9.0" diff --git a/package.json b/package.json index 7790e678..65735b6f 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ }, "dependencies": { "@hono/node-server": "^2.0.12", - "hono": "^4.12.32" + "hono": "^4.13.1" }, "devDependencies": { "@playwright/test": "1.61.1",