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

## 2024-07-24 - LCP Image Asynchronous Decoding Issue
**Learning:** Adding `decoding="async"` to above-the-fold or high-priority LCP SVG images can block main thread rendering or delay initial paint, counteracting performance benefits.
**Action:** Remove `decoding="async"` from critical, non-lazy loaded images (such as logos and hero images) to ensure fast loading and optimal Largest Contentful Paint (LCP). Only apply it to `loading="lazy"` images.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@
- **보안 개선**: `i18n.js`의 `setLanguage()` 함수에 허용된 언어인지 확인하는 입력값 검증(Input Validation) 로직을 추가하여 Prototype Pollution 및 유효하지 않은 상태 주입을 방지했습니다.
- **성능 개선**: `i18n.js`에서 초기 로드 시 기본 언어가 한국어(ko)인 경우 불필요한 DOM 순회 및 텍스트 업데이트를 생략하도록 개선했습니다.
- **테스트 추가**: 다국어 처리 로직의 무결성을 검증하기 위해 `test_i18n.html` 테스트 파일을 추가했습니다.

### 변경사항 (2024-07-24)
- ⚡ 성능 향상: above-the-fold SVG 이미지 (로고 및 hero 이미지)에서 `decoding="async"` 속성을 제거하여 LCP(Largest Contentful Paint)를 최적화했습니다.
Comment on lines +15 to +17
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
8 changes: 6 additions & 2 deletions tests/test_styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,13 @@ 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."""
parser = _ImageParser()
parser.feed(INDEX.read_text(encoding="utf-8"))

assert parser.images
assert all(image.get("decoding") == "async" for image in parser.images)
for image in parser.images:
if image.get("loading") == "lazy":
assert image.get("decoding") == "async"
else:
assert image.get("decoding") != "async"
Loading