Skip to content
Open
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@
## 2026-07-10 - Remove unnecessary DOMPurify for performance
**Learning:** 애플리케이션이 `textContent`와 같은 안전한 DOM API만 사용하고 `innerHTML` 등의 위험한 싱크를 사용하지 않는다면 DOMPurify와 같은 라이브러리를 통해 Trusted Types 정책을 생성할 필요가 없음.
**Action:** 불필요한 번들 다운로드 및 스크립트 실행을 방지하기 위해 사용하지 않는 라이브러리를 식별하고 제거할 것.

## 2024-07-16 - SVG 및 LCP 이미지에 대한 decoding="async" 오용 방지
**Learning:** SVG 이미지는 디코딩 과정이 필요 없는 파싱 대상이므로 `decoding="async"` 설정이 무의미합니다. 또한 `fetchpriority="high"`가 부여된 LCP 이미지에 이를 적용하면 크리티컬한 동기 렌더링을 방해하여 성능을 저하시키는 안티패턴이 됩니다.
**Action:** 오프스크린 래스터 이미지에만 `decoding="async"`를 적용하고, SVG 및 핵심 콘텐츠 렌더링 요소에는 사용하지 않도록 주의합니다.
9 changes: 4 additions & 5 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<a href="#top" class="skip-link" data-i18n="nav.skipToContent">본문으로 건너뛰기</a>
<header class="site-header">
<a class="brand" href="#top" aria-label="Contextual Wisdom Lab home">
<img src="assets/context-wisdom-lab-avatar.svg" alt="" width="44" height="44" decoding="async">
<img src="assets/context-wisdom-lab-avatar.svg" alt="" width="44" height="44">
<span>Contextual Wisdom Lab</span>
</a>
<nav class="site-nav" aria-label="Primary navigation">
Expand Down Expand Up @@ -64,7 +64,7 @@ <h1 data-i18n="hero.title">맥락지혜 연구실</h1>
</div>

<div class="hero-visual">
<img class="context-art" src="assets/context-thread-map.svg" alt="" aria-hidden="true" width="760" height="560" fetchpriority="high" decoding="async">
<img class="context-art" src="assets/context-thread-map.svg" alt="" aria-hidden="true" width="760" height="560" fetchpriority="high">
<div class="ladder" role="list" aria-label="Data to wisdom ladder">
<div class="ladder-row" role="listitem">
<span>Data</span>
Expand Down Expand Up @@ -194,7 +194,7 @@ <h2 data-i18n="dikw.title">DIKW는 판단 흐름을 점검하는 질문입니다
</p>
</div>
<!-- ⚡ Bolt: Lazy load off-screen image -->
<img class="section-diagram" src="assets/dikw-checkpoints.svg" alt="" aria-hidden="true" loading="lazy" width="1120" height="330" decoding="async">
<img class="section-diagram" src="assets/dikw-checkpoints.svg" alt="" aria-hidden="true" loading="lazy" width="1120" height="330">
<div class="dikw-grid">
<article>
<span>Data</span>
Expand Down Expand Up @@ -272,7 +272,7 @@ <h2 data-i18n="references.title">참고문헌</h2>
<section id="logo" class="section logo-story">
<div class="logo-mark">
<!-- ⚡ Bolt: Lazy load off-screen image -->
<img src="assets/context-wisdom-lab-avatar.svg" alt="Contextual Wisdom Lab square mark" loading="lazy" width="500" height="500" decoding="async">
<img src="assets/context-wisdom-lab-avatar.svg" alt="Contextual Wisdom Lab square mark" loading="lazy" width="500" height="500">
</div>
<div>
<h2 data-i18n="logo.title">로고는 흩어진 기록을 하나의 흐름으로 묶습니다</h2>
Expand Down Expand Up @@ -425,7 +425,6 @@ <h2 data-i18n="work.title">연구에서 제품으로</h2>
loading="lazy"
width="920"
height="260"
decoding="async"
>
<p>
<span data-i18n="footer.founded">Founded by</span>
Expand Down
4 changes: 2 additions & 2 deletions tests/test_styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ def test_tall_sections_reserve_larger_intrinsic_block_size():


def test_images_decode_without_blocking_rendering():
"""All site images opt into asynchronous decoding."""
"""Only off-screen raster images opt into asynchronous decoding."""
parser = _ImageParser()
parser.feed(INDEX.read_text(encoding="utf-8"))

assert parser.images
assert all(image.get("decoding") == "async" for image in parser.images)
assert all(image.get("decoding") == "async" for image in parser.images if image.get("loading") == "lazy" and not image.get("src", "").endswith(".svg"))
Loading