23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
안녕하세요. 이정민입니다.
웹 프론트엔드 성능 최적화 스터디에 참여하게되어 영광이였습니다.
제가 조사하고 발표했던 부분에 대해서 블로그로 작성하게 되었습니다.
저희 교재 4장의 이미지 갤러리 최적화의 CLS부분과, 뒷부분에 나오게될 React-Dev-Tool을 톺아보았습니다.
메인 화면 | 이미지 클릭 |
|---|---|
|
|
네번째 장은 이미지 간단한 이미지 갤러리입니다. 헤더를 통해서 이미지들을 필터링합니다. 이미지를 클릭하면 평균 픽셀값을 계산하면 오버레이로 띄어줍니다.
CLS 발생 | 퍼모먼스 측정 |
|---|---|
이번장에서는 위와 같이 lighthouse를 통해서 CLS가 발생하는 것을 명확히 알 수 있고, performance Tab을 통해서도 확인 할 수 있습니다.
CLS는 아래와 같은 요인들로 발생하는데요, 이번 장에서는 이미지에 치수가 들어가 있지않아 발생하는 경우에 대해 다룹니다.
광고, 임베드와 같은 동적 컨텐츠
애니메이션
웹 폰트
치수가 없는 이미지 - ✅ 이번장
치수가 정확하게 한 사이즈로만 렌더링이 된다면, 문제는 간단하게 해결될 것입니다.
<img src="/image/url.png" alt="placeholder" width="300px" height="300px" />이렇게 먼저 width와 height 속성을 추가하면 브라우저가 이미지를 가져오기전에 공간을 먼저 할당해 놓기때문에, Reflow가 최소화될 것입니다.
하지만 반응형 웹 디자인의 도입으로 width와 height를 생략하고 아래와 CSS로 이미지 크기를 제어하고자 하기 시작합니다.
img {
width: 100%;
height: auto;
}하지만 이미지 크기가 지정되지 않으므로 브라우저에서 다운로드를 시작하고 크기를 확인할 때까지는 공간을 할당할 수 없게됩니다.
이런 상황때문에 비율이라는 개념이 들어오게 되는데, 크기 중 하나를 알면 브라우저가 관련 영역에 충분한 공간을 잡아 줄 수 있습니다.
둘중에 하나만이라도 특정값을 명시해놓으면 브라우저는 이를 기반으로 이미지의 비율을 추가합니다.
<!-- 16:9 비율을 위한 width, height 설정 -->
<img src="devocean.png" width="640" height="360" alt="Devocean open lab" />하지만 저희는 자동으로 계산되는 것보다 디자인이 나온대로 대응을 해주어야합니다.
저희가 원하는 비율로 나오게끔 해야하는 거죠. 대부분의 경우 반응형으로 디자인이 설계가 되어있고, 이미지의 비율이 그와 맞지않을때가 많습니다.
교재에서는 두가지 방식을 제안합니다.
Padding-hack 기법 | Aspect Ratio 프로퍼티 사용 |
|---|---|
|
|
|
|
각각의 트레이드오프가 있는 것 같아서, 개인적으로 좋아하는 Radix UI에서는 어떻게 적용하고 있는지 궁금해서 찾아봤습니다.
Aspect Ratio라는 래퍼 컴포넌트에서는 Padding-hack 기법을 통해서 구현되있는 것을 확인할 수 있었어요. 아무래도 호환성 때문인 것 같습니다.
const AspectRatio = (props, forwardedRef) => {
const { ratio = 1 / 1, style, ...aspectRatioProps } = props;
return (
<div
style={{
position: "relative",
width: "100%",
paddingBottom: `${100 / ratio}%`,
}}
>
<Primitive.div
{...aspectRatioProps}
ref={forwardedRef}
style={{
...style,
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
}}
/>
</div>
);
};
앞장에서 사용한 network, performance, lighthouse 특히 performance는 써본적 없을 수 있지만 프론트엔드 개발자라면 써본적이있는 React Developer Tools를 이번 챕터에서 다룹니다.
하지만 safari나 지원하지 않는 브라우저에서는 패키지를 다운받아 사용할 수 있습니다. ( 특히 React native )
# yarn
yarn global add react-devtools
# npm
npm install -g react-devtools
# 실행
react-devtoolsglobal로 설치한다음 react-devtools 커맨드를 입력해서 실행합니다.

위와 같이 실행이되고, React Native같은 경우는 이 가이드이 가이드에 따라서 진행하시면 될 것 같습니다.
그 외, safari 환경에서 실행해야하는 경우는 위에서 요구하는 script 태그를 본문에 넣어주면 해당 응용 애플리케이션에서 실행이 됩니다.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="http://localhost:8097"></script>
<title>React App</title>
<body></body>
</html>컴포넌트 계층 구조를 시각적으로 확인
컴포넌트 상태와 프롭스 조회 및 조작
컴포넌트 훅 검사 가능 ex) useState, useMemo
function App() {
return (
<ErrorBoundary fallback={'Error...'}>
<Suspense fallback={'Loading...'}>
<Child>
</Suspense>
</ErrorBoundary>
)
}컴포넌트 탭에서가면 우측상단에 디버그 아이콘이 최대 5개까지 확장되는 것을 보실 수 있습니다. 모르시고 넘어갈 수 있어서 각각 어떤 버튼인지 보겠습니다.
위와 같은 코드가 있다고 가정했을 때 총 버튼이 5개가 생깁니다.

1️⃣ Error Toggle: Error 상태를 활성화하여 화면에 "Error..." 메시지를 표시합니다.
2️⃣ Suspense Toggle: Suspense를 활성화하여 화면에 "Loading..." 메시지를 표시합니다.
3️⃣ Jump to Elements: 선택한 컴포넌트를 개발자 도구의 Elements 탭으로 이동합니다.
4️⃣ Log Component Info: 현재 컴포넌트의 Props, Hooks, Nodes를 console에 출력합니다.
5️⃣ View Source Code: 소스맵을 통해 컴포넌트의 원본 코드로 바로 접근합니다.
그리고 최근에는 서버컴포넌트도 지원이 된다고 합니다 ~ !

컴포넌트 렌더링 시간 측정 및 시각화
Flame Graph와 Ranked Chart를 통해 렌더링 비용 확인
Timeline을 통해 렌더링 이벤트와 CPU 사용량 분석
각 렌더링 이벤트의 원인 확인 (props, state 변경 등)
불필요한 리렌더링 감지 (컴포넌트의 과도한 재렌더링 파악)

간단하게 4개만 정리해보았습니다.
1️⃣ FlameGraph | 2️⃣ Ranked |
|---|---|
|
|
컴포넌트가 | 순위가 매겨진 차트 뷰는 단일 커밋을 나타냅니다. 차트의 각 막대는 React 구성 요소(예: App, Nav)를 나타냅니다. 차트는 |
3️⃣ Timeline | 4️⃣ Commit Page |
|---|---|
|
|
| React는 |
렌더 단계란 ?
DOM에 필요한 변경 사항을 결정하고, render 호출 및 이전 렌더와 비교합니다.
커밋 단계란 ?
렌더 단계에서 결정된 변경 사항을 적용하며, 이 과정에서 componentDid Mount, componentDidUpdate 라이프사이클 메서드가 호출됩니다.
프로그래밍 방식으로도 React 트리의 렌더링 성능을 측정할 수 있습니다.
import React, { Profiler } from 'react';
function onRenderCallback(
id, // Profiler의 "id" prop에 전달된 값
phase, // "mount" (처음 렌더링) 또는 "update" (재렌더링)
actualDuration, // 해당 업데이트에 소요된 렌더링 시간
baseDuration, // 메모이제이션 없이 렌더링하는 데 걸리는 예상 시간
startTime, // 렌더링이 시작된 시점
commitTime, // 렌더링이 커밋된 시점
interactions // 렌더링과 관련된 상호작용들
) {
console.log({ id, phase, actualDuration, baseDuration, startTime, commitTime, interactions });
}
function MyComponent() {
return (
<Profiler id="test-app" onRender={onRenderCallback}>
<div>프로파일링할 컴포넌트 내용</div>
</Profiler>
);
}id: test-app, phase: update, actualDuration: 5.30ms, baseDuration: 8.00ms, startTime: 8482.50ms, commitTime: 8487.90ms막상 현업에서는 백오피스 업무를 많이 다루다보니, 최적화에 관련되서 공부할 기회가 없었습니다. 그렇게 지원해서 운좋게 합류하게 되었는데요.
스터디를 통해 좋은 분들을 많이 알아가고, 본인들마다 맡으신 부분을 아무래도 다른 팀원들보다 조사도 많이하시고 준비하신걸 쏙-쏙 먹여주시니
일반적인 북스터디보다 훨씬 유익하고 밀도가 있다고 생각했습니다.
최적화 외 프론트엔드관련 토픽과 프로님들이 현업에서 어떻게 하셨는지 경험을 곁들여서 말씀해주시는게 너무 좋았던 것 같았습니다.
책을 보면서 단편적으로 알게된 지식들도 많았지만 발표 준비 및 블로그를 작성하면서 많은 파생지식들을 얻게 되는 것 같아서 머리에 오래 남는 것 같아 좋았습니다.
주변 지인한테 담 기수 넣어보라구 해야겠습니다 ! 읽어주셔서 감사합니다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.