@wooojin/forgen 0.4.8 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/assets/dev-guide/be/README.md +226 -0
- package/assets/dev-guide/be/adapters/build-agents-md.sh +63 -0
- package/assets/dev-guide/be/principles/common.md +433 -0
- package/assets/dev-guide/be/principles/go.md +469 -0
- package/assets/dev-guide/be/principles/node.md +388 -0
- package/assets/dev-guide/be/skills/go/be-build/SKILL.md +262 -0
- package/assets/dev-guide/be/skills/go/be-perf/SKILL.md +308 -0
- package/assets/dev-guide/be/skills/go/be-review/SKILL.md +119 -0
- package/assets/dev-guide/be/skills/go/be-security/SKILL.md +362 -0
- package/assets/dev-guide/be/skills/node/be-build/SKILL.md +239 -0
- package/assets/dev-guide/be/skills/node/be-perf/SKILL.md +272 -0
- package/assets/dev-guide/be/skills/node/be-review/SKILL.md +118 -0
- package/assets/dev-guide/be/skills/node/be-security/SKILL.md +355 -0
- package/assets/dev-guide/be/sources/12factor/INDEX.md +53 -0
- package/assets/dev-guide/be/sources/api-design/INDEX.md +56 -0
- package/assets/dev-guide/be/sources/ddia/INDEX.md +55 -0
- package/assets/dev-guide/be/sources/go-runtime/INDEX.md +62 -0
- package/assets/dev-guide/be/sources/node-runtime/INDEX.md +60 -0
- package/assets/dev-guide/be/sources/otel/INDEX.md +53 -0
- package/assets/dev-guide/be/sources/owasp-api/INDEX.md +52 -0
- package/assets/dev-guide/be/sources/postgres/INDEX.md +55 -0
- package/assets/dev-guide/be/sources/sre-book/INDEX.md +48 -0
- package/assets/dev-guide/fe/README.md +197 -0
- package/assets/dev-guide/fe/adapters/build-agents-md.sh +63 -0
- package/assets/dev-guide/fe/adapters/refresh.sh +68 -0
- package/assets/dev-guide/fe/principles/common.md +160 -0
- package/assets/dev-guide/fe/principles/react.md +183 -0
- package/assets/dev-guide/fe/principles/vue.md +196 -0
- package/assets/dev-guide/fe/skills/react/fe-build/SKILL.md +139 -0
- package/assets/dev-guide/fe/skills/react/fe-perf/SKILL.md +179 -0
- package/assets/dev-guide/fe/skills/react/fe-review/SKILL.md +141 -0
- package/assets/dev-guide/fe/skills/vue/fe-build/SKILL.md +148 -0
- package/assets/dev-guide/fe/skills/vue/fe-perf/SKILL.md +163 -0
- package/assets/dev-guide/fe/skills/vue/fe-review/SKILL.md +136 -0
- package/assets/dev-guide/fe/sources/a11y-dx/INDEX.md +41 -0
- package/assets/dev-guide/fe/sources/a11y-dx/chrome-devtools-memory.md +150 -0
- package/assets/dev-guide/fe/sources/a11y-dx/chrome-devtools-performance.md +99 -0
- package/assets/dev-guide/fe/sources/a11y-dx/lighthouse-audits.md +146 -0
- package/assets/dev-guide/fe/sources/a11y-dx/react-devtools-profiler.md +128 -0
- package/assets/dev-guide/fe/sources/a11y-dx/wcag22-new-criteria.md +174 -0
- package/assets/dev-guide/fe/sources/perf/01-core-web-vitals.md +58 -0
- package/assets/dev-guide/fe/sources/perf/02-inp.md +83 -0
- package/assets/dev-guide/fe/sources/perf/03-lcp-cls.md +130 -0
- package/assets/dev-guide/fe/sources/perf/04-speculation-rules.md +148 -0
- package/assets/dev-guide/fe/sources/perf/05-view-transitions.md +153 -0
- package/assets/dev-guide/fe/sources/perf/06-nextjs-caching.md +188 -0
- package/assets/dev-guide/fe/sources/perf/07-server-components.md +181 -0
- package/assets/dev-guide/fe/sources/perf/08-ppr.md +133 -0
- package/assets/dev-guide/fe/sources/perf/09-nextjs-image.md +200 -0
- package/assets/dev-guide/fe/sources/perf/10-optimize-lcp.md +201 -0
- package/assets/dev-guide/fe/sources/perf/INDEX.md +88 -0
- package/assets/dev-guide/fe/sources/react/INDEX.md +41 -0
- package/assets/dev-guide/fe/sources/react/keeping-components-pure.md +135 -0
- package/assets/dev-guide/fe/sources/react/no-effect-patterns.md +183 -0
- package/assets/dev-guide/fe/sources/react/react-compiler.md +182 -0
- package/assets/dev-guide/fe/sources/react/server-components.md +194 -0
- package/assets/dev-guide/fe/sources/react/server-functions.md +192 -0
- package/assets/dev-guide/fe/sources/react/suspense.md +218 -0
- package/assets/dev-guide/fe/sources/react/use-action-state.md +123 -0
- package/assets/dev-guide/fe/sources/react/use-form-status.md +158 -0
- package/assets/dev-guide/fe/sources/react/use-hook.md +153 -0
- package/assets/dev-guide/fe/sources/react/use-optimistic.md +194 -0
- package/assets/dev-guide/fe/sources/toss-ff/INDEX.md +58 -0
- package/assets/dev-guide/fe/sources/toss-ff/cohesion-code-directory.md +79 -0
- package/assets/dev-guide/fe/sources/toss-ff/cohesion-form-fields.md +110 -0
- package/assets/dev-guide/fe/sources/toss-ff/cohesion-magic-number.md +47 -0
- package/assets/dev-guide/fe/sources/toss-ff/coupling-item-edit-modal.md +124 -0
- package/assets/dev-guide/fe/sources/toss-ff/coupling-use-bottom-sheet.md +57 -0
- package/assets/dev-guide/fe/sources/toss-ff/coupling-use-page-state.md +71 -0
- package/assets/dev-guide/fe/sources/toss-ff/overview-4-principles.md +77 -0
- package/assets/dev-guide/fe/sources/toss-ff/predictability-hidden-logic.md +59 -0
- package/assets/dev-guide/fe/sources/toss-ff/predictability-http.md +77 -0
- package/assets/dev-guide/fe/sources/toss-ff/predictability-use-user.md +110 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-comparison-order.md +52 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-condition-name.md +64 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-login-start-page.md +183 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-magic-number.md +53 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-submit-button.md +73 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-ternary-operator.md +38 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-use-page-state.md +77 -0
- package/assets/dev-guide/fe/sources/toss-ff/readability-user-policy.md +98 -0
- package/assets/dev-guide/fe/sources/vue/INDEX.md +17 -0
- package/assets/dev-guide/fe/sources/vue/composition-api.md +251 -0
- package/assets/dev-guide/fe/sources/vue/nuxt-data-fetching.md +232 -0
- package/assets/dev-guide/fe/sources/vue/pinia-state-management.md +134 -0
- package/assets/dev-guide/fe/sources/vue/reactivity-pitfalls.md +261 -0
- package/assets/dev-guide/fe/sources/vue/style-guide-priority-a.md +117 -0
- package/assets/dev-guide/fe/sources/vue/style-guide-priority-b.md +231 -0
- package/assets/dev-guide/fe/sources/vue/style-guide-priority-c.md +86 -0
- package/assets/dev-guide/fe/sources/vue/style-guide-priority-d.md +72 -0
- package/dist/cli.js +42 -0
- package/dist/core/dashboard-cli.d.ts +12 -0
- package/dist/core/dashboard-cli.js +226 -0
- package/dist/core/dev-guide-injector.d.ts +26 -0
- package/dist/core/dev-guide-injector.js +137 -0
- package/dist/core/init.js +53 -0
- package/dist/core/lifecycle-classifier.d.ts +23 -0
- package/dist/core/lifecycle-classifier.js +104 -0
- package/dist/core/observability-backfill.d.ts +31 -0
- package/dist/core/observability-backfill.js +178 -0
- package/dist/core/observability-store.d.ts +58 -0
- package/dist/core/observability-store.js +195 -0
- package/dist/core/session-store.js +4 -0
- package/dist/core/spawn.d.ts +17 -0
- package/dist/core/spawn.js +179 -2
- package/dist/core/statusline-cli.js +34 -1
- package/dist/engine/compound-extractor.js +39 -0
- package/dist/engine/compound-loop.js +6 -0
- package/dist/engine/compound-retire.d.ts +20 -0
- package/dist/engine/compound-retire.js +85 -0
- package/dist/hooks/context-guard.js +25 -1
- package/dist/hooks/post-tool-use.js +48 -0
- package/dist/hooks/solution-injector.js +93 -0
- package/dist/host/install-claude.d.ts +6 -2
- package/dist/host/install-claude.js +74 -2
- package/dist/host/install-codex.d.ts +4 -0
- package/dist/host/install-codex.js +71 -0
- package/dist/host/install-orchestrator.js +1 -0
- package/package.json +6 -6
- package/plugin.json +1 -1
- package/scripts/postinstall.js +134 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Core Web Vitals 2024 — 전체 개요 (LCP, INP, CLS)
|
|
3
|
+
source: https://web.dev/articles/vitals
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: web-vitals
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 개요
|
|
9
|
+
|
|
10
|
+
Google Web Vitals는 사용자 경험의 핵심 신호를 로딩·인터랙션·시각 안정성의 세 축으로 측정한다.
|
|
11
|
+
측정 기준: **75번째 백분위수** (모바일+데스크톱 세그먼트 기준).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 세 가지 Core Web Vitals
|
|
16
|
+
|
|
17
|
+
### 1. LCP — Largest Contentful Paint (로딩)
|
|
18
|
+
- **Good**: ≤ 2.5초
|
|
19
|
+
- **Needs Improvement**: 2.5 ~ 4.0초
|
|
20
|
+
- **Poor**: > 4.0초
|
|
21
|
+
|
|
22
|
+
### 2. INP — Interaction to Next Paint (인터랙션)
|
|
23
|
+
- **Good**: ≤ 200ms
|
|
24
|
+
- **Needs Improvement**: 201 ~ 500ms
|
|
25
|
+
- **Poor**: > 500ms
|
|
26
|
+
- 2024년 3월 FID 대체로 Core Web Vital 공식 승격
|
|
27
|
+
|
|
28
|
+
### 3. CLS — Cumulative Layout Shift (시각 안정성)
|
|
29
|
+
- **Good**: ≤ 0.1
|
|
30
|
+
- **Needs Improvement**: 0.1 ~ 0.25
|
|
31
|
+
- **Poor**: > 0.25
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 측정 도구
|
|
36
|
+
|
|
37
|
+
**필드(실사용자) 도구**: Chrome UX Report, PageSpeed Insights, Search Console, Chrome DevTools
|
|
38
|
+
|
|
39
|
+
**랩 도구**: Lighthouse, Chrome DevTools, WebPageTest
|
|
40
|
+
> Lighthouse는 INP 직접 측정 불가 → Total Blocking Time을 proxy로 사용
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## JavaScript 구현
|
|
45
|
+
|
|
46
|
+
```javascript
|
|
47
|
+
import {onCLS, onINP, onLCP} from 'web-vitals';
|
|
48
|
+
|
|
49
|
+
function sendToAnalytics(metric) {
|
|
50
|
+
const body = JSON.stringify(metric);
|
|
51
|
+
(navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
|
|
52
|
+
fetch('/analytics', {body, method: 'POST', keepalive: true});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
onCLS(sendToAnalytics);
|
|
56
|
+
onINP(sendToAnalytics);
|
|
57
|
+
onLCP(sendToAnalytics);
|
|
58
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: INP (Interaction to Next Paint) — FID 대체 신 지표
|
|
3
|
+
source: https://web.dev/articles/inp
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: web-vitals
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 왜 INP인가?
|
|
9
|
+
|
|
10
|
+
FID(First Input Delay)는 첫 번째 입력의 지연만 측정했다. INP는 페이지 전체 생애주기에 걸친 **모든 인터랙션**을 관찰하고, 최댓값(outlier 제외)을 최종 점수로 사용한다.
|
|
11
|
+
2024년 3월 Core Web Vital로 공식 승격, FID 은퇴.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 임계값
|
|
16
|
+
|
|
17
|
+
| 등급 | 값 |
|
|
18
|
+
|------|-----|
|
|
19
|
+
| **Good** | ≤ 200ms |
|
|
20
|
+
| **Needs Improvement** | 201 ~ 500ms |
|
|
21
|
+
| **Poor** | > 500ms |
|
|
22
|
+
|
|
23
|
+
기준: 모바일+데스크톱 75번째 백분위수
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 측정 대상 인터랙션
|
|
28
|
+
|
|
29
|
+
포함:
|
|
30
|
+
- 마우스 클릭
|
|
31
|
+
- 터치스크린 탭
|
|
32
|
+
- 키보드 키 입력
|
|
33
|
+
|
|
34
|
+
제외 (INP 미반영):
|
|
35
|
+
- 스크롤
|
|
36
|
+
- 호버(hover)
|
|
37
|
+
- 확대/축소
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 인터랙션 구성 3단계
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
[ 입력 이벤트 ]
|
|
45
|
+
↓
|
|
46
|
+
1. Input Delay — 이벤트 핸들러 실행 전까지의 대기 시간
|
|
47
|
+
↓
|
|
48
|
+
2. Processing Time — 이벤트 핸들러 콜백 실행 시간
|
|
49
|
+
↓
|
|
50
|
+
3. Presentation Delay — 다음 프레임 렌더링까지의 시간
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**총 INP = Input Delay + Processing Time + Presentation Delay**
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## JavaScript 측정
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
import {onINP} from 'web-vitals';
|
|
61
|
+
|
|
62
|
+
onINP(console.log);
|
|
63
|
+
// metric.value: 밀리초 단위 INP 점수
|
|
64
|
+
// metric.attribution: 어떤 인터랙션이 원인인지 상세 정보
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`web-vitals` 라이브러리가 백분위수 계산, BFCache 리셋, visibility-change 추적을 자동 처리한다.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 최적화 방향
|
|
72
|
+
|
|
73
|
+
1. **Input Delay 줄이기**: 긴 태스크(Long Task) 분할, `scheduler.yield()` 활용
|
|
74
|
+
2. **Processing Time 줄이기**: 이벤트 핸들러 경량화, 메인 스레드 외부(Web Worker) 이동
|
|
75
|
+
3. **Presentation Delay 줄이기**: DOM 크기 최소화, Layout Thrashing 방지, `requestAnimationFrame` 적절 사용
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## INP가 0으로 보고되지 않는 경우
|
|
80
|
+
|
|
81
|
+
- 적격 인터랙션 없음 (스크롤·호버만 발생)
|
|
82
|
+
- 봇 접근 (스크립트 인터랙션 없음)
|
|
83
|
+
- 페이지 진입 후 즉시 이탈
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: LCP · CLS 최신 가이드라인
|
|
3
|
+
source: https://web.dev/articles/lcp, https://web.dev/articles/cls
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: web-vitals
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## LCP — Largest Contentful Paint
|
|
9
|
+
|
|
10
|
+
### 임계값
|
|
11
|
+
|
|
12
|
+
| 등급 | 값 |
|
|
13
|
+
|------|-----|
|
|
14
|
+
| **Good** | ≤ 2.5초 |
|
|
15
|
+
| **Needs Improvement** | 2.5 ~ 4.0초 |
|
|
16
|
+
| **Poor** | > 4.0초 |
|
|
17
|
+
|
|
18
|
+
### 측정 대상 요소
|
|
19
|
+
- `<img>` (애니메이션: 첫 프레임 기준)
|
|
20
|
+
- SVG 내 `<image>`
|
|
21
|
+
- `<video>` (poster 이미지 또는 첫 프레임 중 먼저 로드된 것)
|
|
22
|
+
- CSS `background-image: url(...)` 배경 요소
|
|
23
|
+
- 텍스트를 포함한 블록 레벨 요소
|
|
24
|
+
|
|
25
|
+
제외: `opacity: 0` 요소, 뷰포트 전체를 채우는 배경 처리 요소, 낮은 엔트로피 플레이스홀더 이미지
|
|
26
|
+
|
|
27
|
+
### 측정 특이사항
|
|
28
|
+
사용자가 탭·스크롤·키 입력 시 측정 **중단** (이미 인터랙션한 뒤 로드되는 요소는 무관).
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## LCP의 4가지 하위 구성 요소 (최적화 우선순위 순)
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
LCP = TTFB + Resource Load Delay + Resource Load Duration + Element Render Delay
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
| 구성 요소 | 목표 비중 | 설명 |
|
|
39
|
+
|-----------|-----------|------|
|
|
40
|
+
| TTFB | ~40% | 서버 응답 시간 |
|
|
41
|
+
| Resource Load Delay | <10% | TTFB ~ LCP 리소스 로딩 시작까지 |
|
|
42
|
+
| Resource Load Duration | ~40% | 실제 리소스 전송 시간 |
|
|
43
|
+
| Element Render Delay | <10% | 리소스 완료 ~ 화면 렌더까지 |
|
|
44
|
+
|
|
45
|
+
**핵심**: Resource Load Delay + Element Render Delay는 합쳐서 <10%가 이상적.
|
|
46
|
+
어느 구간도 리소스가 로딩되지 않는 시간 = 낭비.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## LCP 최적화 기법
|
|
51
|
+
|
|
52
|
+
### 1. Resource Load Delay 제거
|
|
53
|
+
```html
|
|
54
|
+
<!-- HTML에 직접 src/srcset 포함 (preload scanner 활성화) -->
|
|
55
|
+
<img fetchpriority="high" src="/hero.webp" alt="hero">
|
|
56
|
+
|
|
57
|
+
<!-- CSS/JS에서만 참조되는 경우 preload 추가 -->
|
|
58
|
+
<link rel="preload" fetchpriority="high" as="image"
|
|
59
|
+
href="/hero.webp" type="image/webp">
|
|
60
|
+
```
|
|
61
|
+
- LCP 이미지에 `loading="lazy"` 절대 금지
|
|
62
|
+
|
|
63
|
+
### 2. Element Render Delay 제거
|
|
64
|
+
- Critical CSS 인라인화 또는 CSS 파일 크기 최소화
|
|
65
|
+
- `<head>` 내 동기 스크립트 제거
|
|
66
|
+
- 서버사이드 렌더링으로 HTML에 이미지 포함
|
|
67
|
+
|
|
68
|
+
### 3. Resource Load Duration 단축
|
|
69
|
+
- WebP/AVIF 포맷 사용
|
|
70
|
+
- 반응형 `srcset` 적용
|
|
71
|
+
- CDN/Image CDN 활용
|
|
72
|
+
- 공격적 캐싱 정책
|
|
73
|
+
|
|
74
|
+
### 4. TTFB 단축
|
|
75
|
+
- 서버 처리 시간 최소화
|
|
76
|
+
- 불필요한 리다이렉트 제거
|
|
77
|
+
- CDN 엣지 캐싱
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## CLS — Cumulative Layout Shift
|
|
82
|
+
|
|
83
|
+
### 임계값
|
|
84
|
+
|
|
85
|
+
| 등급 | 값 |
|
|
86
|
+
|------|-----|
|
|
87
|
+
| **Good** | ≤ 0.1 |
|
|
88
|
+
| **Needs Improvement** | 0.1 ~ 0.25 |
|
|
89
|
+
| **Poor** | > 0.25 |
|
|
90
|
+
|
|
91
|
+
기준: 페이지 전체 생애주기 중 최대 레이아웃 이동 버스트 점수의 75번째 백분위수
|
|
92
|
+
|
|
93
|
+
### 주요 원인
|
|
94
|
+
- 크기 미지정 이미지/비디오
|
|
95
|
+
- 폴백 폰트보다 크거나 작은 웹폰트
|
|
96
|
+
- 동적으로 리사이즈되는 광고·위젯
|
|
97
|
+
- 비동기 리소스 삽입
|
|
98
|
+
- 기존 콘텐츠 앞에 동적 DOM 삽입
|
|
99
|
+
|
|
100
|
+
### 최적화 기법
|
|
101
|
+
|
|
102
|
+
```css
|
|
103
|
+
/* 1. CSS transform 사용 (레이아웃 재계산 없음) */
|
|
104
|
+
.moving-element {
|
|
105
|
+
transform: translate(0, 10px); /* top/left 변경 대신 */
|
|
106
|
+
transform: scale(1.1); /* width/height 변경 대신 */
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* 2. 동적 콘텐츠 공간 미리 확보 */
|
|
110
|
+
.ad-slot {
|
|
111
|
+
min-height: 250px;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/* 3. 폰트 로딩 중 레이아웃 변화 방지 */
|
|
115
|
+
@font-face {
|
|
116
|
+
font-display: optional; /* 또는 swap + size-adjust */
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
// 사용자 인터랙션 후 이동은 CLS 제외 (hadRecentInput 확인)
|
|
122
|
+
new PerformanceObserver((list) => {
|
|
123
|
+
for (const entry of list.getEntries()) {
|
|
124
|
+
if (!entry.hadRecentInput) {
|
|
125
|
+
// 이 shift만 CLS에 카운트됨
|
|
126
|
+
console.log('CLS shift:', entry.value);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}).observe({type: 'layout-shift', buffered: true});
|
|
130
|
+
```
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Speculation Rules API — 즉시 페이지 전환(Prerender/Prefetch)
|
|
3
|
+
source: https://developer.chrome.com/docs/web-platform/prerender-pages
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: navigation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 개요
|
|
9
|
+
|
|
10
|
+
Chrome이 재도입한 완전한 페이지 프리렌더링 API. 구식 `<link rel="prerender">` 대체.
|
|
11
|
+
사용자 탐색 전에 페이지를 비가시 백그라운드 탭으로 로드 → 활성화 시 즉시 전환.
|
|
12
|
+
LCP 사실상 0, CLS 대폭 개선 효과.
|
|
13
|
+
|
|
14
|
+
**브라우저 지원**: Chrome 109+, Edge 109+ | Firefox 미지원 | Safari 실험적
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 기본 문법
|
|
19
|
+
|
|
20
|
+
```html
|
|
21
|
+
<script type="speculationrules">
|
|
22
|
+
{
|
|
23
|
+
"prerender": [{
|
|
24
|
+
"urls": ["/next-page.html", "/about.html"]
|
|
25
|
+
}]
|
|
26
|
+
}
|
|
27
|
+
</script>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## URL 목록 vs 문서 규칙
|
|
33
|
+
|
|
34
|
+
### URL 목록 (정적)
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"prerender": [{ "urls": ["/page1.html", "/page2.html"] }]
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 문서 규칙 (동적 — CSS/URL 패턴 매칭)
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"prerender": [{
|
|
45
|
+
"where": {
|
|
46
|
+
"and": [
|
|
47
|
+
{ "href_matches": "/*" },
|
|
48
|
+
{ "not": { "href_matches": "/admin/*" } },
|
|
49
|
+
{ "not": { "selector_matches": ".no-prerender" } }
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"eagerness": "moderate"
|
|
53
|
+
}]
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Eagerness 레벨 (Chrome 121+)
|
|
60
|
+
|
|
61
|
+
| 레벨 | 데스크톱 | 모바일 |
|
|
62
|
+
|------|---------|--------|
|
|
63
|
+
| `immediate` | 즉시 | 즉시 |
|
|
64
|
+
| `eager` | 10ms 호버 | 뷰포트 진입 50ms 후 |
|
|
65
|
+
| `moderate` | 200ms 호버 또는 pointerdown | 스크롤 후 500ms |
|
|
66
|
+
| `conservative` | pointer/touch down만 | pointer/touch down만 |
|
|
67
|
+
|
|
68
|
+
**권장 구현** (대부분 사이트에 적합):
|
|
69
|
+
```html
|
|
70
|
+
<script type="speculationrules">
|
|
71
|
+
{
|
|
72
|
+
"prerender": [{
|
|
73
|
+
"where": { "href_matches": "/*" },
|
|
74
|
+
"eagerness": "moderate"
|
|
75
|
+
}]
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## 브라우저 할당량 (리소스 낭비 방지)
|
|
83
|
+
|
|
84
|
+
| Eagerness | Prefetch 한도 | Prerender 한도 |
|
|
85
|
+
|-----------|--------------|----------------|
|
|
86
|
+
| `immediate` | 50 | 10 |
|
|
87
|
+
| `eager` / `moderate` / `conservative` | 2 (FIFO) | 2 (FIFO) |
|
|
88
|
+
|
|
89
|
+
한도 초과 시 가장 오래된 speculation이 취소되고 새 것으로 교체.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Prefetch (경량 대안)
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"prefetch": [{
|
|
98
|
+
"urls": ["/next.html"],
|
|
99
|
+
"eagerness": "moderate"
|
|
100
|
+
}]
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
기존 `<link rel="prefetch">`와 달리, 탐색으로서의 문서를 prefetch하여 non-cacheable 콘텐츠도 처리.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## HTTP 헤더로 전달
|
|
109
|
+
|
|
110
|
+
```http
|
|
111
|
+
Speculation-Rules: "/speculationrules.json"
|
|
112
|
+
```
|
|
113
|
+
JSON 파일 MIME 타입: `application/speculationrules+json`
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 동적 삽입 (JavaScript)
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
const rules = document.createElement('script');
|
|
121
|
+
rules.type = 'speculationrules';
|
|
122
|
+
rules.textContent = JSON.stringify({
|
|
123
|
+
prerender: [{ urls: [getNextPageUrl()] }]
|
|
124
|
+
});
|
|
125
|
+
document.head.appendChild(rules);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 주요 제약
|
|
131
|
+
|
|
132
|
+
- 서브프레임(iframe) 내 규칙 무시
|
|
133
|
+
- 활성화 전까지 알림·권한 팝업 등 "침습적" API 불가
|
|
134
|
+
- 크로스 오리진 iframe은 페이지 활성화 전까지 렌더링 안 됨
|
|
135
|
+
- Save-Data, 에너지 절약 모드, 사용자 "페이지 프리로드" 설정 자동 준수
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 고급 기능
|
|
140
|
+
|
|
141
|
+
### Tags (Chrome 136+)
|
|
142
|
+
```json
|
|
143
|
+
{ "tag": "my-rules", "prerender": [{ "urls": ["/next.html"] }] }
|
|
144
|
+
```
|
|
145
|
+
서버사이드 필터링을 위한 레이블링.
|
|
146
|
+
|
|
147
|
+
### Target Hint (Chrome 138+)
|
|
148
|
+
투기 대상 컨텍스트 지정으로 정확도 향상.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: View Transitions API — 페이지 전환 애니메이션 (Chrome 111+)
|
|
3
|
+
source: https://developer.chrome.com/docs/web-platform/view-transitions
|
|
4
|
+
fetched: 2026-05-18
|
|
5
|
+
category: navigation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 개요
|
|
9
|
+
|
|
10
|
+
DOM 업데이트(SPA) 또는 페이지 간 이동(MPA) 시 부드러운 시각적 전환을 제공하는 API.
|
|
11
|
+
브라우저가 전환 전후 스냅샷을 찍고 CSS 애니메이션으로 보간한다.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 두 가지 구현 유형
|
|
16
|
+
|
|
17
|
+
### 1. 동일 문서 전환 (Same-Document / SPA)
|
|
18
|
+
**지원**: Chrome 111+, Edge 111+, Firefox 144+, Safari 18+
|
|
19
|
+
|
|
20
|
+
JavaScript API로 트리거:
|
|
21
|
+
```javascript
|
|
22
|
+
// DOM 업데이트를 감싸기만 하면 됨
|
|
23
|
+
document.startViewTransition(() => updateTheDOMSomehow());
|
|
24
|
+
|
|
25
|
+
// 비동기 업데이트도 지원
|
|
26
|
+
document.startViewTransition(async () => {
|
|
27
|
+
await fetchNewContent();
|
|
28
|
+
updateTheDOMSomehow();
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. 크로스 문서 전환 (Cross-Document / MPA)
|
|
33
|
+
**지원**: Chrome 126+, Edge 126+, Safari 18.2+ | Firefox 미지원
|
|
34
|
+
|
|
35
|
+
CSS만으로 opt-in (JS 불필요):
|
|
36
|
+
```css
|
|
37
|
+
/* 양쪽 페이지 모두에 추가 */
|
|
38
|
+
@view-transition {
|
|
39
|
+
navigation: auto;
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
같은 오리진 페이지 간 탐색 시 자동으로 전환 효과 적용.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 핵심 CSS: view-transition-name
|
|
47
|
+
|
|
48
|
+
개별 요소를 캡처하여 독립 애니메이션 처리:
|
|
49
|
+
```css
|
|
50
|
+
.hero-image {
|
|
51
|
+
view-transition-name: hero;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.page-title {
|
|
55
|
+
view-transition-name: page-title;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**주의**: `view-transition-name` 값은 페이지 전체에서 고유해야 함.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 생성되는 Pseudo-Elements
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
::view-transition /* 루트 오버레이 */
|
|
67
|
+
└── ::view-transition-group(name) /* 개별 요소 래퍼 */
|
|
68
|
+
├── ::view-transition-old(name) /* 이전 상태 스냅샷 */
|
|
69
|
+
└── ::view-transition-new(name) /* 새 상태 스냅샷 */
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
기본 전환은 cross-fade. 커스터마이즈:
|
|
73
|
+
```css
|
|
74
|
+
/* 슬라이드 전환 예시 */
|
|
75
|
+
::view-transition-old(root) {
|
|
76
|
+
animation: 300ms ease-out both slide-to-left;
|
|
77
|
+
}
|
|
78
|
+
::view-transition-new(root) {
|
|
79
|
+
animation: 300ms ease-out both slide-from-right;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@keyframes slide-to-left {
|
|
83
|
+
to { transform: translateX(-100%); }
|
|
84
|
+
}
|
|
85
|
+
@keyframes slide-from-right {
|
|
86
|
+
from { transform: translateX(100%); }
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## View Transition Types (Chrome 125+)
|
|
93
|
+
|
|
94
|
+
네비게이션 방향에 따라 다른 애니메이션:
|
|
95
|
+
```javascript
|
|
96
|
+
document.startViewTransition({
|
|
97
|
+
update: updateTheDOMSomehow,
|
|
98
|
+
types: ['forwards'] // 'backwards', 'reload' 등
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
CSS에서 타입별 스타일:
|
|
103
|
+
```css
|
|
104
|
+
:active-view-transition-type(forwards) ::view-transition-old(root) {
|
|
105
|
+
animation-name: slide-to-left;
|
|
106
|
+
}
|
|
107
|
+
:active-view-transition-type(backwards) ::view-transition-old(root) {
|
|
108
|
+
animation-name: slide-to-right;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## JavaScript 애니메이션 (Web Animations API)
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
const transition = document.startViewTransition(() => updateDOM());
|
|
118
|
+
|
|
119
|
+
// pseudo-element가 생성된 후 JS 애니메이션 적용
|
|
120
|
+
transition.ready.then(() => {
|
|
121
|
+
document.documentElement.animate(
|
|
122
|
+
{ transform: ['translateY(-100%)', 'translateY(0)'] },
|
|
123
|
+
{
|
|
124
|
+
duration: 300,
|
|
125
|
+
easing: 'ease-out',
|
|
126
|
+
pseudoElement: '::view-transition-new(root)'
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 주요 활용 사례
|
|
135
|
+
- 썸네일 → 상세 이미지 확대
|
|
136
|
+
- 네비게이션 persistent 요소 (헤더, 탭바)
|
|
137
|
+
- 필터링 시 그리드 재정렬
|
|
138
|
+
- 페이지 간 영웅 이미지 공유 트랜지션
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 접근성 고려
|
|
143
|
+
|
|
144
|
+
```css
|
|
145
|
+
/* 모션 감소 선호 사용자 대응 */
|
|
146
|
+
@media (prefers-reduced-motion: reduce) {
|
|
147
|
+
::view-transition-group(*),
|
|
148
|
+
::view-transition-old(*),
|
|
149
|
+
::view-transition-new(*) {
|
|
150
|
+
animation-duration: 0.01ms !important;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|