diff --git a/.jules/bolt.md b/.jules/bolt.md index f74ef2f..f01aff0 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,3 +1,7 @@ ## 2024-06-20 - Unnecessary initial DOM updates for default language **Learning:** The simple static i18n implementation runs `node.textContent = dict[node.dataset.i18n]` for every translatable node on the initial script load, even when the HTML is already written in the target language (Korean). This creates unnecessary layout/paint operations and blocking time on the main thread for elements that don't need text changes. **Action:** Always check if the current value matches the desired value before updating the DOM (`node.textContent !== newText`), and add early exits when setting state to the same value to avoid redundant DOM traversal and writes. + +## 2024-06-29 - 초기 로딩 시 불필요한 DOM 쿼리 생략 +**Learning:** HTML이 이미 기본 언어로 렌더링된 상태에서 초기화할 때, 변경할 필요가 없는 140개 이상의 노드를 모두 탐색하는 것은 메인 스레드를 낭비하는 작업이었습니다. +**Action:** 현재 상태가 서버가 렌더링한 초기 DOM 언어와 일치할 때는 무거운 텍스트 노드 탐색(querySelectorAll)을 조건부로 완전히 건너뛰도록 구현하여 성능을 개선합니다. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5e5cc0f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# 변경 이력 (Changelog) + +## [Unreleased] +### 성능 개선 (Performance) +- `i18n.js`: 초기 페이지 로딩 시, 기본 언어와 브라우저 언어가 동일할 때 불필요하게 140여 개의 노드를 탐색하는 DOM 쿼리(`querySelectorAll("[data-i18n]")`)를 생략하도록 최적화하여 렌더링 성능을 개선했습니다. diff --git a/i18n.js b/i18n.js index 2393774..4106f0a 100644 --- a/i18n.js +++ b/i18n.js @@ -315,14 +315,20 @@ function setLanguage(lang) { const dict = messages[lang] || messages.ko; - if (!i18nNodes) { - i18nNodes = document.querySelectorAll("[data-i18n]"); + // ⚡ Bolt: Skip expensive DOM query and updates if setting the default language on first load + const isInitialDefaultLoad = !currentLang && document.documentElement.lang === lang; + + if (!langButtons) { langButtons = document.querySelectorAll("[data-lang]"); metaDesc = document.querySelector('meta[name="description"]'); ogDesc = document.querySelector('meta[property="og:description"]'); footerLogo = document.querySelector("#footer-logo"); } + if (!i18nNodes && !isInitialDefaultLoad) { + i18nNodes = document.querySelectorAll("[data-i18n]"); + } + if (document.documentElement.lang !== lang) { document.documentElement.lang = lang; } @@ -347,12 +353,14 @@ function setLanguage(lang) { } // Only update textContent if it actually changed to avoid layout recalculations - i18nNodes.forEach((node) => { - const newText = dict[node.dataset.i18n]; - if (newText && node.textContent !== newText) { - node.textContent = newText; - } - }); + if (i18nNodes) { + i18nNodes.forEach((node) => { + const newText = dict[node.dataset.i18n]; + if (newText && node.textContent !== newText) { + node.textContent = newText; + } + }); + } langButtons.forEach((button) => { const pressed = String(button.dataset.lang === lang); diff --git a/test_i18n.html b/test_i18n.html new file mode 100644 index 0000000..c189a58 --- /dev/null +++ b/test_i18n.html @@ -0,0 +1,17 @@ + + +
+ +