Recap
- 프론트엔드 테스트는 비즈니스 로직을 테스트하는 것
성능 측정 툴
Lighthouse, Web Vitals, Performance(개발자 도구), Profiler 알아보기
1. Lighthouse
웹 성능을 분석하는 오픈 소스
- 개발자 도구의 Network 탭의 와이파이 모양 클릭
- No throttling 등 선택 가능
- 성능을 일부러 약간 떨어뜨려서 약간 안 좋은 환경에 있는 상황에서 테스트를 진행
- 모든 유저가 빠른 네트워크에서 사용하는 게 아니기 때문
접근성 검사 (Accessible)
SEO 검사
PWA
- 앱인데 웹처럼 쓸 수 있는지 (프로그레시브 웹앱)
- 성능과는 크게 관련 X
Lighthouse는 측정할 때마다 약간씩 다를 수 있음
- 참고할 만한 지표 정도
- 수치에 집착하지 말고 직접 웹사이트 테스트하면서 사용자가 ‘거슬릴 만한 것’에 대해서 측정
Lighthouse 검사 시점
production 빌드 레벨에서 검사
- production하면서 어느 정도 최적화가 되기 때문
- minification
- 빈칸, 줄바꿈 제거
- js 내용을 모두 한 줄로 합쳐줌 (용량이 줄면서 번들 사이즈 감소)
- Tree shaking
- 안 쓰는 코드 버리기
- unused javascript
- 예: react-query dev-tool
- 어차피 dev 툴이라 production 후 사라짐
- develop에서 확인하면 이걸 포함해서 확인
- yarn run build → yarn run preview 이렇게 터미널에 찍으면 production 빌드 레벨에서 확인 가능
2. Web Vitals
LCP
- 화면에서 제일 큰 이미지가 뜨는 데 걸리는 시간
- 2.5초 이하 초록불
- 2.5초~4초 노란불
- 4초 넘어가면 빨간불
CLS
- 개발자 도구 탭
탭에 들어가서 맨 왼쪽에 있는 '녹음' 버튼 클릭
브라우저 화면을 다시 띄우면서 성능 측정
* 화면이 그려지는 순간들을 보여줌
- Scripting
- Rendering
- Painting
- 현업에서 최적화할 때는 Performance 대신 주로 Lighthouse나 Profiler 사용
- Performance는 육안으로 잘 안 느껴짐
- Lighthouse에서 빨간 불 정도 되어야 사용자들 인지
4. Profiler
- 리액트 내장 기능 (리액트로 만들어진 사이트의 경우 개발자 도구에 Component와 함께 해당 탭 생성)
- 용도: '컴포넌트별' 렌더링 시간 측정
- 사용 방법: 리액트 코드에서 Profiler 컴포넌트로 감싸고 prop으로
onRender={onRender}
추가
- 더 편한 방법으로 Profiler로 안 감싸고 하는 방법도 있음
- 유의: 배포한 곳(production 레벨)에서는 안 됨 (development 레벨에서만 동작)
- 관련 에러 메시지
Profiling not supported.
Profiling support requires either a development or profiling build of React v16.5+.
5. Code Splitting
- 번들 사이즈를 잘개 쪼개는 것
* 100KB를 10KB로 잘게 쪼개서
- 처음부터 100KB를 다 불러오지 않고
- 필요한 10KB, 20KB부터 먼저 불러오는 것
- 장점
* 초기 로딩 시간 감소
- 방법
* React.lazy와 Suspense를 함께 사용 (동적 import)
- lazy로 감싼 컴포넌트를 완전히 불러올 때까지
- Suspense fallback(로딩중 UI)을 보여줌
- 렌더링 컴포넌트가 완전히 불러와지면 그때 로딩 UI 대신 해당 컴포넌트를 보여줌
회사의 레거시 코드를 개선하는 것도 개발자의 중요한 업무 - 좋은 경험
- `npm dedupe (de-deplicate: 중복을 없앰)
- package.json의 ^10.0.2 버전의 의미
- '10.0점 대에서는 아무 거나 설치해도 괜찮아'
- 만약 ^가 없으면? - '무조건 10.0.2만 사용해야 해'
- font 용량 줄이기
- font를 HTML에 script 태그로 추가하면 용량 문제 발생 가능
- build 파일 중 '~chunk'를 포함한 파일
- 예: build/static/js/123124.aejes.chunk.js
- 해당 파일을 브라우저가 기억해두었다가 캐시해두고
- 다른 페이지에서 같은 파일을 요청할 경우 캐시 사용
- 코드 스플리팅은 그냥 되는 게 아니다.
- CRA인 경우 웹팩 설정이 스플리팅을 지원해서 가능
- Vite도 지원해서 가능
- 만약 CRA나 Vite가 아니고 웹팩을 커스텀할 경우 스플리팅이 되도록 설정 필요
질문 타임
- dynamic import로 파일을 나중에 불러오면 화면이 늦게 떠서 사용자 입장에서 안 좋을 것 같다
- 그래서 로딩 UI를 보여주는 것
- 번들 용량이 적기 때문에 빨리 불러오고 그 잠깐 사이에 로딩중 보여주는 것
- 용량적 측면에서의 장점이 더 커서 코드 스플리팅은 단점이 거의 없다고 보면 됨
- 오히려 통째로 가져오면 최초 로딩이 더 길어짐
- 조금씩 불러오는 과정에서 layout shift가 생길 수 있지 않나?
- next.js를 쓰면 shift가 발생하지 않음
- 또 fallback 컴포넌트로 자리를 미리 잡아놓으면 안 생기는데
- 이 경우 fallback과 불러올 컴포넌트의 크기가 동일해야 함
Layout Shift 관련 공식 문서 내용
'각 요소의 개별 레이아웃 이동 점수는 예상치 못한 움직임이 발생하는 경우에만 CLS로 계산됩니다. 새 요소가 DOM에 추가되거나 기존 요소의 크기가 변경되는 경우 로드된 요소가 위치를 유지하면 레이아웃 이동에 포함되지 않습니다.'
=> 로드된 요소가 위치를 유지하게 하는 법
- width, height 설정
- 부모 요소의 명확한 크기 설정
=> 이걸로 해결할 수 있는 현상
- auto가 먹지 않을 때
- next/image에서 fill 옵션을 넣을 때 발생하는 에러
intersectionObserver와 무한 스크롤
- 코드 스플리팅의 목적
- intersectionObserver도 유사한 개념
- 보여줄 부분만 불러오는 것 (바닥에 닿았을 때) - ref와 함께 사용
- 1000개를 다 그리느냐 vs. 화면에 보이는 10개만 그리느냐
- 적용 시 실제 걸리는 시간이 1/10 정도로 감소
무한 스크롤과의 차이
무한 스크롤은 서버에서 뭔가를 해줘야 함
예: 10개씩 계속 서버에서 불러오는 것
애초에 전체를 다 가져오는 건 최적화할 수 없음
무한 스크롤로 서버와 협동해서 가져오는 게 훨씬 성능에 좋음
결국 백엔드에서 적은 양의 데이터를 불러오는게 하도록 하는 게 베스트
react-intersection-observer🔗
이 라이브러리를 쓰면 intersection observer를 매우 쉽게 사용 가능
bandWidth와 latency의 차이
- bandWidth: 대역폭
- 예: 생수의 입구 - 나올 수 있는 구멍, 여기가 막히면 병목 현상 발생
- latency: 지연 시간
- 원래 올 때 1초 걸려야 하는데 3초 걸리면 2초가 latency
원챌 4일차 (230811)
출근 첫 주의 여파로 졸아서 필기가 적음
Cache
- 운영체제 안에 있음
- 자주 사용하는 데이터를 저장해두는 것 (= 가방)
- 관련 에러
- serve static assets with an effecient cache policy
- 캐시 정책을 잘못 했다 (캐시를 하면 더 빨리 불러올 수 있는데)
- cache-control 설정해줘야 함
- Network 탭에 Cache-Control이 있으면 캐시를 한 것
- 첫 로딩에는 디스크 캐시로 들어가고
- 이후 새로고침 하면 (자주 쓰는 것으로 인식해서) 메모리 캐시로 바뀜
종류 (2가지)
메모리 캐시 (가방)
디스크 캐시 (창고)
Font 최적화
- font source 쓰면 asset 파일을 관리할 필요가 없음
- woff2 포맷으로 자동 적용된 폰트 -> 용량이 매우 작)
- Noto Sans와 비교하면 많이 차이남
- @font-face를 쓰면 css로 인식됨
- woff2가 제일 용량이 적음
- 개발자 도구 Sources 들어가서 per function 옆의 녹음 버튼 누르면
purgeCSS
그외 팁
- rm -rf build : 빌드 폴더 지우기
code .
Lock Files
- 패키지 매니저인 npm과 yarn은 같이 쓰면 안 된다.
- npm과 yarn을 같이 쓰면 같은 패키지인데도 다른 lock 파일을 쓰게 됨
- 한 마디로 다른 패키지 버전으로 개발하는 것
=> 이러한 이유로 패키지 매니저는 꼭 하나만 사용한다.
- 또한 Node 버전이 다르면 lock 파일이 달라질 수 있어서
- lock 파일은 건드리지 않는다.
- lock에 문제 생기면 지우고 새로 npm install하기
- lock을 직접 수정하면 꼬일 수 있음
dependency와 devDependency 차이
- dependency
- devdependency
- 개발할 때만 필요한 패키지
- 예: typescript, @testing-library, @types/~, babel 관련 패키지 등
Typescript
- enum은 타입스크립트 시스템상 추천하지 않는 문법
- 런타임 비용 얘기 있음
- enum은 객체여서
- 불필요한 런타임 오버헤드 초래 (규모 커지면 문제 초래)
- 런타임 줄이려면 불변성 필요한데
- 객체는 기본적으로 가변적
=> enum 쓰면 런타임에서 변경 가능성이 있어서 좋지 않다.
잘 읽었습니다. 좋은 정보 감사드립니다.