
에디 오스마니,하산 지르데의 대규모 리액트 웹앱 개발 책을 읽고 중요한 부분을 정리하기
대규모 리액트 웹앱 개발
대규모 웹 어플리케이션 : 유지보수에 개발자의 상당한 노력을 요구하는, 사소하지 않은 어플리케이션
- 문제 해결을 위해 올바른 추상화의 선택은 매우 중요하다
- “잘못된 추상화보다는 추상화가 없는 편이 낫다”
- 자바스크립트 프레임워크 or 추상화의 역할
- 개발자들이 ‘성공할 수 있도록’ 강력한 기본값들을 제공해야 한다.
- 새로운 프레임워크를 사용하기 시작하는 시점에는 대규 앱의 특정한 측면에 간한 모범사례나 최적의 설정에 관해 인지하지 못할 수 있다.
- 강력한 기본값은 개발자 경험과 사용자 경험의 균형을 맞추도록 도와준다.
- 고품질 어플리케이션을 보장하는 데 도움을 줄 수 있다.
- 어플리케이션의 품질은 ‘크기’가 아니라, 마찰을 일으키지 않고 사용자와 비즈니스 니즈를 충족시킬 수 있는 가와 관계된다.
프론트엔드 모듈성
"대규모 애플리케이션을 구축하는 비밀, 그것은 절대로 대규모 어플리케이션을 구축하지 않는 것이다. 여러분의 애플리케이션을 작은 조각으로 나누라. 그리고 테스트할 수 있는, 바이트 크기의 그 조각들을 합쳐 큰 애플리케이션을 만들라". -저스틴 마이어
대규모 웹앱을 만드는 핵심
→ 애플리케이션을 작고 독립된, 다시말해 독립적으로 개발 및 테스트할 수 있는 모듈 또는 컴포넌트로 나누는 것.
모듈성(Modularity)
- 코드의 재사용성을 높인다.
- 캡슐화를 하여 공개적으로 필요한 기능만 익스포트 해서 내부의 구현은 프라이빗 모듈 범위로 숨기기 가능
JS에서의 모듈
- 코드를 작은 파일로 나누어 기능을 익스포트/임포트 가능
- export: 함수, 객체, 프리미티브 등 모든 것을 익스포트
- import: 다른 모듈을 임포트
리액트에서의 컴포넌트화
- 리액트는 본질적으로 컴포넌트를 사용해 생각할 것을 권장.
- 각 컴포넌트는 UI의 구분된 조각이며, 재사용 가능
- 일관된 형태와 동작을 보장하는 동시에 각 컴포넌트의 로직과 상태관리를 중앙 집중화한다.
- 재사용 가능한 컴포넌트 식별
- 버튼, 메뉴, 카드 같은 반복되는 요소들
- 헤더, 콘텐츠 영역, 푸터 같은 페이지의 구역들
- 기능의 논리적 덩어리
- 적응성과 확장성을 높이는 컴포넌트 자르기
- ex) Post 컴포넌트를 PostHeader,PostContent,PostFooter등으로 나누기
- Post 컴포넌트는 이 작은 컴포넌트들을 모두 조합해 하나의 응집된 포스트 요소를 만드는 책임을 진다.
- 컴포넌트화 고려사항
- 재사용성: 특정 UI 요소를 여러 부분에서 반복하기를 원할 때
- 단순성,가독성: 가독성을 고려할 때.(각각의 책임에 집중하게 만들기)
- 개선된 테스트 가능성: 보다 효과적으로 테스트할 수 있는지
- 성능 고려사항: 렌더링 최적화를 하거나 불필요한 조작을 줄일 수 있는지
- 디자인 시스템 구현
- 디자인 시스템을 구축하면 컴포넌트 설계와 개발을 표준화하는 데 도움이 된다
지연로딩
→ 지연로딩(lazy-loading)은 리소스가 필요할 때만 로딩하는 기법. 초기에 로딩되는 리소스의 데이터양을 줄임으로써 애플리케이션의 성능을 효과적으로 개선
- lazy: 요청이 있을 때 컴포넌트를 로딩할 수 있게 하는 함수
- impot()함수(promise를 반환)를 사용하여 지연로딩 되는 컴포넌트 생성
- Suspense: 지연 컴포넌트가 로딩되는 동안 대체 컴포넌트를 표시하기 위해 사용하는 컴포넌트
- 지연로딩 패턴은 상호작용이나 클릭이 발생할 때 컴포넌트를 동적으로 로딩할 때도 사용 가능
- 리액트의 lazy() 함수를 사용한 동적 임포트는 즉시 필요하지 않은 큰 컴포넌트에만 사용해아 한다
- 코드에 약간의 복잡성이 추가되고 서버사이드 렌더링과 관련된 이슈를 야기할 수 있기에
- Intersection Observer API: 뷰포트에 어떤 요소가 표시되는 시점을 식별할 수 있다
코드분할
→ 코드 분할(code-splitting)은 애플리케이션 코드 전체를 보다 작은, 관리 가능한 덩어리로 나눔으로써 대규모 애플리케이션의 성능을 최적화하는 기법. 모듈화된 구조를 갖추는 것이 효율적인 코드 분할을 위한 토대를 닦는 것.
코드 분할을 구현하기 전 *크리티컬 패스(사용자에게 표시되기 전에 반드시 로딩되어야 하는 리소스의 순서)를 식별하여 어떤 리소스를 먼저 로딩해야 하는지, 지연 로딩할 지를 결정하기
- 리액트에서의 코드분할 패턴
- 라우트에 따라 분할: 사용자의 탐색에 따라 페이지 모듈을 로딩
- 컴포넌트에 따라 분할: 그래프나 테이블 같은 큰 컴포넌트를 지연 로딩
- 온디맨드 로딩: 사용자가 버튼, 드롭다운 등을 클릭할 때 코드를 로딩
- 엔트리 포인트 분할 → 엔트리 포인트는 사용자가 웹사이트를 방문했을 때 로딩되는 첫 번째 자바스크립트 파일
- 초기 자바스크립트 파일을 작은 덩어리로 자른다
- 더 빠른 로딩 시간과 더 나은 사용자 경험 제공
- 벤더 분할 → 코드에서 서드파티 의존성을 분리할 때 사용하는 기법
- 서드파티 의존성과 관련된 코드를 별도의 덩어리로 잘라내 독립적으로 캐싱 가능
- 코드를 업데이트했을 때, 캐싱되어 있기에 전체 라이브러리를 다시 다운로드할필요 X
- 더 빠른 로딩 시간과 더 나은 사용자 경험 제공
- 동적 분할 → 자바스크립트 코드를 필요할 때 필요한 만큼 로딩할 때 사용하는 기법
- 미리 정해진 엔트리 포인트에만 의존하지 않는다는 점에서 엔트리 포인트 분할과 다르다
- 컴포넌트 수준 분할 → 각 컴포넌트를 필요할 때만 지연로딩
- 현재 페이지에서 요청된 컴포넌트만 로딩
- 지연이 증가되기도 함
- 라우트 기반 분할 → 애플리케이션이 라우트에 기반해 각각의 번들로 나뉜다.
- 사용자가 다른 라우트에 방문하면 적절한 번들을 필요에 따라 로딩하며, 초기에 다운로드해야 할 코드의 양을 줄인다
- 네트워크 대역폭 사용 관점에서는 컴포넌트 수준 코드 분할보다 효율적이지 않을 수 있다
- 공격적인 코드분할의 트레이드 오프 → js를 수많은 작은 덩어리로 과도하게 자르는 것.