Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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:** 불필요한 번들 다운로드 및 스크립트 실행을 방지하기 위해 사용하지 않는 라이브러리를 식별하고 제거할 것.

## 2026-08-04 - SVG 이미지와 decoding="async"로 인한 LCP 지연
**Learning:** 초기 화면 렌더링에 중요한 위쪽 영역(Above-the-fold)의 SVG 이미지에 `decoding="async"` 속성이 있으면 렌더링이 메인 스레드를 차단하지 않게 되지만, 동시에 브라우저가 화면을 그리는 시점에 이미지가 준비되지 않아 Largest Contentful Paint(LCP) 발생 시점이 늦어질 수 있습니다.
**Action:** Above-the-fold에 위치한 로고나 Hero 이미지 같은 핵심 리소스에서는 `decoding="async"` 속성을 제거하여 렌더링 지연을 막습니다. 반대로 `loading="lazy"` 속성을 가진 오프스크린 이미지는 메인 스레드를 막지 않도록 계속해서 `decoding="async"`를 유지합니다.
6 changes: 4 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
<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">
<!-- ⚡ Bolt: Removed decoding="async" for SVG/LCP optimization -->
<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 +65,8 @@ <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">
<!-- ⚡ Bolt: Removed decoding="async" for SVG/LCP optimization -->
<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
11 changes: 9 additions & 2 deletions tests/test_styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,19 @@ def test_tall_sections_reserve_larger_intrinsic_block_size():


def test_images_decode_without_blocking_rendering():
"""All site images opt into asynchronous decoding."""
"""Lazy loaded images opt into asynchronous decoding, critical SVGs load synchronously."""
parser = _ImageParser()
parser.feed(INDEX.read_text(encoding="utf-8"))

assert parser.images
assert all(image.get("decoding") == "async" for image in parser.images)

# lazy load images should have decoding="async"
lazy_images = [img for img in parser.images if img.get("loading") == "lazy"]
assert all(image.get("decoding") == "async" for image in lazy_images)

# above-the-fold images should not have decoding="async"
critical_images = [img for img in parser.images if img.get("loading") != "lazy"]
assert all("decoding" not in image for image in critical_images)

def test_project_cards_are_fully_clickable_via_pseudo_element():
"""Project cards expand clickable area to entire card without wrapping the whole block in an anchor."""
Expand Down
Loading