2024-04-18.md
๐กDIL: ๋ชจ๋ ๋ฆฌ์กํธ ๋ฅ ๋ค์ด๋ธ, 7์ฃผ์ฐจ-4
์คํฐ๋: ์๊ฐ CS, https://github.com/monthly-cs/2024-03-modern-react-deep-dive
์ค๋ ์งํ: ๊ฐ์ธ๊ณต๋ถ
DIL-week7-4_2024-04-18
| DIL ์ฃผ์ฐจ | ๋ฒ์ | ๋ด์ฉ | ์ค๋์ฐจ ์ง๋ | | -------- | ---------- | --------------------------------------------------------------------------------------- | ----------- | | 7์ฃผ์ฐจ | 12์ฅ, 13์ฅ | ๋ชจ๋ ์น ๊ฐ๋ฐ์๊ฐ ๊ด์ฌ์ ๊ฐ์ ธ์ผ ํ ํต์ฌ ์น ์งํ, ์น ํ์ด์ง์ ์ฑ๋ฅ์ ์ธก์ ํ๋ ๋ค์ํ ๋ฐฉ๋ฒ | 799~816p |
์ค๋ ์ฝ์ ๋ด์ฉ์ markdown์ผ๋ก ๊ฐ๋จํ ๋ฉ๋ชจ
์ฝ์ ์๊ฐ: ์ด 50๋ถ
CLS, Cumulative Layout Shift
๊ธฐ์ค ์ ์
| CLS ์ ์ | ๊ธฐ์ค | | -------- | ---- | | <0.1 | ์ข์ | | <0.25 | ๋ณดํต | | >=0.25 | ๋์จ |
๊ฐ์ ๋ฐฉ์
-
์ฝ์ ์ ์ํ ์ถ๊ฐ ๊ณต๊ฐ ํ๋ณด
- useLayouEffect
- ๋ก๋ฉ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ๊ฒ๊ณผ ๊ฐ์ด ๋ณด์ผ ์ ์๋ค.
- ๋๊ธฐ์ ์ผ๋ก ๋ฐ์ํด, ๋ธ๋ผ์ฐ์ ์ ํ์ธํ ์์ ์ ์ํฅ์ ๋ฏธ์น๋ค
- ์ค์ผ๋ ํค UI
- ์ถ์ฒ, ๋์ ๋ ์ด์์ ์ฌํํธ๋ฅผ ์์ ํ ๋ฐฉ์งํ ์ ์๋ค
- ์๋ฒ ์ฌ์ด๋ ๋๋๋ง
- ๋์ ์ธ ์์์ ์ ๋ฌด๋ฅผ ์ฌ์ ์ ํ๋จํด HTML์ ๋ฏธ๋ฆฌ ์ ๊ณต
- ํ์ฌ ์คํฌ๋ฆฝํธ์ ์์กดํ๋ ๊ฒฝ์ฐ, ๋ถ๊ฐ๋ฅํ ์๋ ์๋ค
- useLayouEffect
-
ํฐํธ ๋ก๋ฉ ์ต์ ํ
- FOUT, flash of unstyled text // ๊ธฐ๋ณธ ํฐํธ๋ก ๋ณด์ด๊ณ ์๋ค๊ฐ, ๋ค๋ฆ๊ฒ ํฐํธ๊ฐ ์ ์ฉ๋๋ ํ์
- FOIT, flash of invisible text // ๋ฌธ์์ ์ง์ ํ ํฐํธ๋ ์๊ณ , ๊ธฐ๋ณธ ํฐํธ๋ ์๋ค๊ฐ ๋ค๋ฆ๊ฒ ํฐํธ๊ฐ ๋ก๋ฉ๋๋ฉฐ, ํ์ด์ง์ ๋๋๋ง๋๋ ํ์
-
ํด๊ฒฐ ๋ฐฉ์
-
<link>
์ preload, rel=preload -
font-family
| ์ต์ | ๋ก๋ฉ | ํด๋ฐฑ ํฐํธ | | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | anto | ๋ธ๋ผ์ฐ์ ๊ฐ ๊ฒฐ์ | | | block | ํฐํธ๊ฐ ๋ก๋ฉ๋๊ธฐ ์ ๊น์ง ๋๋๋ง์ ์ค๋จํ๋ค(์ต๋ 3์ด) | | | swap | FOUT, ํด๋ฐฑ ํฐํธ๋ก ๊ธ์๋ฅผ ๋๋๋ง, ์น ํฐํธ์ ๋ก๋ฉ์ด ์๋ฃ๋๋ฉด ์น ํฐํธ๋ฅผ ์ ์ฉ | O | | fallback | 100ms๊ฐ ํ ์คํธ๊ฐ ๋ณด์ด์ง ์๊ณ , ํด๋ฐฑ ํฐํธ๋ก ๋๋๋ง, 3์ด ์์ ํฐํธ๊ฐ ๋ก๋ฉ๋๋ค๋ฉด? ํด๋น ์น ํฐํธ๋ก ์ ํ, ์๋๋ผ๋ฉด? ํด๋ฐฑ ํฐํธ๋ฅผ ๊ณ์ ์ฌ์ฉ | O | | optional | 100ms๊ฐ ํ ์คํธ๊ฐ ๋ณด์ด์ง ์๊ณ , ํด๋ฐฑ ํฐํธ๋ก ๋๋๋ง. 0.1์ด ๋ด๋ก ํฐํธ๊ฐ ๋ค์ด๋ก๋ ๋์ด ์๊ฑฐ๋, ์บ์๋ผ ์์ง ์๋ค๋ฉด ํด๋ฐฑ ํฐํธ๋ฅผ ์ฌ์ฉ, ๋คํธ์ํฌ ์ํ๋ฅผ ํ์ ํด ์ฐ๊ฒฐ์ ์ทจ์ | O |
-
-
์ ์ ํ ์ด๋ฏธ์ง ํฌ๊ธฐ ์ค์
- aspect-ratio: ๋ธ๋ผ์ฐ์ ์ ์ ์ ์์ด์ ํธ ์คํ์ผ์ํธ์ ํฌํจ๋์ด ์๋ค. ์ด๋ฏธ์ง์ ๊ฐ๋ก์ธ๋ก ๋น์จ์ ์๋์ผ๋ก ๋ง์ถฐ์ฃผ๋ ์ญํ ์ ํ๋ค.
- ์ ํํ ์ซ์๋ฅผ ์จ์ฃผ๋ ๊ฒ์ด ์ข๋ค. (๋ฏธ์ง์ ์ค๋๋ ๋ธ๋ผ์ฐ์ , CSS ๋ก๋ฉ ์คํจ)
- srcset
<img width="1000" height="1000" src="image-1000.jpg" srcset="image-1000.jsp 1000w, image-2000 2000w" >
- aspect-ratio: ๋ธ๋ผ์ฐ์ ์ ์ ์ ์์ด์ ํธ ์คํ์ผ์ํธ์ ํฌํจ๋์ด ์๋ค. ์ด๋ฏธ์ง์ ๊ฐ๋ก์ธ๋ก ๋น์จ์ ์๋์ผ๋ก ๋ง์ถฐ์ฃผ๋ ์ญํ ์ ํ๋ค.
ํต์ฌ ์น ์งํ๊ฐ ์๋ ์ฑ๋ฅ ํ์ธ ์งํ๋ค
TTFB, Time To First Byte
- ๋ธ๋ผ์ฐ์ ๊ฐ ์นํ์ด์ง์ ์ฒซ ๋ฒ์งธ ๋ฐ์ดํธ๋ฅผ ์์ ํ๋๋ฐ ๊ฑธ๋ฆฌ๋ ์๊ฐ
- 600ms ์ด์ ๊ฑธ๋ฆด ๊ฒฝ์ฐ? ๊ฐ์ ํ์
- ์ต์ด์ ์๋ต์ด ์ค๋ ๋ฐ์ดํธ๊น์ง ์ผ๋ง๋ ๊ฑธ๋ฆฌ๋
- ์๋ฒ์ฌ์ด๋ ๋๋๋ง์ ๊ฒฝ์ฐ > ์๋ฒ์์ ์ฒซ ๋ฒ์จฐ HTML์ ๊ทธ๋ฆฌ๋ ํ์ํ ์์ ์ด ๋ง๊ฑฐ๋๋๋ฆด ์๋ก, TTFB๊ฐ ๊ธธ์ด์ง๊ฒ ๋๋ค.
- ๊ณ ๋ ค์ฌํญ
- ์๋ฒ์ฌ์ด๋ ๋๋๋ง
- ์ ์ ํ์ด์ง ๋๋๋ง ๋ก์ง์ ์ต์ ํ
- API ํธ์ถ ์ต์ ํ
- CDN
- Stream
- ์๋ฒ์ฌ์ด๋ ๋๋๋ง
FCP, First Contentful Paint
| FCP ์ ์ | ๊ธฐ์ค | | -------- | ---- | | <1.8 | ์ข์ | | <3.0 | ๋ณดํต | | >=3.0 | ๋์จ |
๊ฐ์ ๋ฐฉ์
- ๋ญ๋ผ๋ ๋ค์ด๋ก๋ํด์ TTFB๋ฅผ ๋จ์ถ
- ๋๋๋ง์ ๊ฐ๋ก๋ง๋ ๋ฆฌ์์ค ์ต์ํ: ๋๋๋ง ๋ฐฉํด ์์๋ ๋น๋๊ธฐ๋ก ๋ก๋
- Above the fold: ์คํฌ๋กค ํ์ง ์์๋ ๋ณด์ด๋ ์์ญ์ ๋ ์ด์ง ๋ก๋ฉ์ด๋, ์คํฌ๋ฆฝํธ ์์กด ์ฝ๋๋ฅผ ํผํ๋ค
- ํ์ด์ง ๋ฆฌ๋ค์ด๋ ํธ ์ต์ํ
- ๋ฆฌ๋ค์ด๋ ํธ๋ ๋น์ฉ > ์ฌ์ฉ์์๊ฒ ๋ฌด์ธ๊ฐ๋ฅผ ๋ณด์ฌ์ค ์ ์๋ ์๊ฐ์ด ์ง์ฐ๋๊ธฐ ๋๋ฌธ
- DOM ํฌ๊ธฐ ์ต์ํ: ๊ตฌ๊ธ ๊ธฐ์ค, DOM์์ 1500๊ฐ, depts 32๋จ๊ณ, ์์๋ ธ๋๋ 60๊ฐ
13. ์น ํ์ด์ง์ ์ฑ๋ฅ์ ์ธก์ ํ๋ ๋ค์ํ ๋ฐฉ๋ฒ
- create-react-app:
- reportWebVitals()
- web-vitals ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ ์งํ๋ฅผ ์ธก์ ํ ์ ์๋ค.
- PerformanObserver API๋ฅผ ์ฌ์ฉํด์ ์น ํ์ด์ง ์ฑ๋ฅ์ ์ธก์ ํ ์ ์๋ค.
- reportWebVitals()
import { ReportHandler } from "web-vitals";
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFE }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFE(onPerfEntry);
});
}
};
export default reportWebVitals;
reportWebVitals();
- ์ฝ์ ์ฐ๊ธฐ
reportWebVitals(console.log);
- ๋ถ์ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ณด๋ด๊ณ ์ถ๋ค๋ฉด?
- sendBeacon API
- fetch๋ก ๋ณด๋ด๊ธฐ
function sendToAnalytics(metic: ReportHandler) {
const body = JSON.stringify(metric);
const url = "/api/analytics";
if (navigator.sendBeacon) {
navigator.sendBeacon(url, body);
} else {
fetch(url, { body, method: "POST", keepalive: true });
}
}
reportWebVitals(sendToAnalytics);
- googleAnalytics
function sendToAnalytics({ id, name, value }: ReportHandler) {
ga("send", "event", {
eventCategory: "Web Vitals",
eventAction: Math.round(name === "CLS" ? value * 1000 : value),
eventLabel: id,
nonInteraction: true,
});
}
reportWebVitals(sendToAnalytics);