ziglog

    Search by

    5월 3주차 기록

    May 20, 2023 • ☕️☕️ 8 min read

    오늘도 놀고 내일도 놀고 🎡


    배워가기

    pnpm 공식문서에서, window에서는 symbolic link를 다루는게 약간의 문제가 있다고 한다.

    대부분의 Windows 도구, 유틸리티 및 셸은 최대 260자를 초과하는 파일 및 폴더 경로를 처리할 수 없는 것이 문제인 듯하다.(2014년 기준)

    ~npm@2 버전까지는 non-flat 구조였으나, 중첩되는 node_modules마다 패키지를 설치했기 때문에 중복 설치되어 비효율적이었다. 그래서 npm@3~ 부터는 node_modules를 flat하게 만들었는데(최상위 node_modules로 모두 끌어올림), 서로다른 버전의 같은 패키지의 경우 문제가 발생하거나, 그 과정 자체가 쉽지 않다.

    pnpm은 npm@~2의 구조를 가지지만, 패키지를 직접 설치하지 않고 symbolic link로 연결한다.

    hover 효과 작성할 때 주의할 점

    모바일에서는 hover가 데스크탑 달리 정상적으로 동작하지 않기 때문에 따로 처리해주어야 한다.

    대응 CSS 코드

    • 데스크탑만 효과 주려면
      • @media (hover: hover) { … }
    • 모바일에 다른 효과 주려면
      • @media (hover: none) { … }

    Ref MDN - hover

    height: auto vs height: fit-content

    • auto

      • 브라우저가 특정 요소의 높이를 계산해서 결정한다.
      • 부모 요소로부터 주어진 가용 높이에서 margin을 제외한 높이를 가리킨다.
    • fit-content

      • auto의 하이브리드 모드처럼 동작한다.
      • 가용 높이가 부족하지 않은 경우에는 담고 있는 컨텐츠의 최대 높이를 요소의 height값으로 사용한다.
      • 그러나 가용 높이가 부족하다면 auto 키워드처럼 가용 높이에서 margin을 제외한 높이를 가리킨다.

    👩‍🏫 autodisplay: inline-block인 요소에만 먹는다.

    타입스크립트에서의 집합론

    extendsis subtype of으로 패러프레이즈할 수 있다.

    예시)

    • Array extends readonly Array
      • 👩‍🏫 readonly Array는 push pop 메서드가 없으다.
    • 1 extends number
    • { children: ReactNode } extends { children?: ReactNode }

    React18의 useDebugValue

    hook에 custom label을 붙여준다.

    Copy
    import { useDebugValue } from "react";
    
    function useOnlineStatus() {
      // ...
      useDebugValue(isOnline ? "Online" : "Offline");
      // ...
    }

    Ref https://react.dev/reference/react/useDebugValue

    React ref의 비밀

    React에서 ref는 첫 번째 렌더에 값을 가지지 않을 수도 있다.

    ref의 값은 componentDidMount 이후에 설정되며, useRef에서 ref는 함수 컴포넌트가 반환되고 컨텐츠가 렌더되기 전까지 값을 가지지 않을 수 있다. 즉 첫 번째 렌더 시에는 ref.currentnull 이 나올 수도 있다.

    그렇다면 useEffect의 deps에 ref.current 값을 넣고 ref.current 값이 바뀌면 useEffect가 호출될까?

    아니다.

    리렌더링이 발생하여 useEffect가 호출되는 경우는 다음 경우 뿐이다.

    • state가 바뀌었을 때
    • prop이 바뀌었을때
    • 부모 컴포넌트가 리렌더링했을 때

    ref 변화에 따라 리렌더링을 하고자 한다면 ref 대신 useCallback을 사용하는 방법도 있다

    Copy
    const itemRef = useCallback((node) => {
      if (node !== null) {
        // do something...
      }
    }, []);
    
    return <div ref={itemRef}>메뉴 아이템</div>;

    Tanstack 라이브러리의 메인테이너도 배신 당했다고 한다. (Ref)

    01

    다음 글도 읽어보면 좋다.

    When React attaches the refs

    벡터 그래픽 vs 래스터 그래픽

    • 벡터(.svg)
      • 그리드에 점을 설정하는 수학 공식과 선, 곡선을 사용하여 이미지를 만든다.
      • 벡터 파일에는 픽셀이 없으며, 벡터 파일의 수학 공식이 도형, 테두리, 칠 색상을 이용하여 이미지를 만든다.
      • 수학 공식에 따라 크기를 변경할 수 있으므로 벡터 이미지를 확대하거나 축소해도 이미지 품질에는 영향을 주지 않는다.
    • 래스터(.jpeg, .gif, .png)
      • 픽셀로 구성된 이미지 (비트맵으로 이미지를 저장)
      • 작은 컬러 사각형인 픽셀이 무수히 많이 모여 사진처럼 세부 정보가 많은 이미지가 만들어진다.
      • 픽셀이 많을수록 품질이 좋으며, 적을수록 품질이 낮아진다.
      • 이미지의 픽셀 수는 파일 유형(예: jpeg, gif, png)에 따라 다르다.

    벡터는 표시해야할 이미지(데이터)가 많으면 그것을 그대로 코드(점,선,면)로 들고있어야 하는데, 그럼 당연히 크기가 커질수 밖에 없다. 반면 래스터는 이미지(데이터)를 표현하는 방식이 픽셀 기반으로, 비교적 많은 데이터를 표현하기 쉽다.(포맷 알고리즘에 따라 압축도 가능하다)

    Ref https://www.adobe.com/kr/creativecloud/file-types/image/comparison/raster-vs-vector.html

    react-router-dom v6에서의 타이핑

    react-router-dom v6부터는 generic을 지원하지 않아 <> 제네릭이 아닌 as 타입 단언을 사용해야 한다.

    Copy
    // ❌
    const location = useLocation<{ state: { isNewMember: boolean } }>();
    
    // ✅
    const location = useLocation() as { state: { isNewMember: boolean } };

    이것저것

    • changesets - 버전 관리 및 변경 로그를 관리하는 도구
    • 테스트용 메일로 사용하기 좋은 YOPmail
    • macOS terminal에서 homebrew tree 패키지를 통해 프로젝트 폴더 구조를 출력할 수 있다.
      • npm을 사용하는 프로젝트에서 그냥 tree 를 출력하면 node_modules 때문에 스압이 장난 아니다…
      • 이럴 때는 tree -I 'node_modules' 명령어로 node_modules 를 제외하고 깔끔하게 출력할 수 있다.

    기타공유

    네이버 홈 개편

    02

    React로 마이그레이션한 것 같다. 위젯 형태로 옹기종기 이쁘구만

    Before You memo()

    오랜만의 Dan의 overreacted 블로그에서 다시 본 글

    https://overreacted.io/before-you-memo/

    React의 memo()useMemo()를 사용하지 않으면서도 일반적인 방법으로 렌더링 최적화를 할 수 있는 방법들을 소개한다.

    1. state를 해당 값을 사용하는 자식 컴포넌트로 내린다. state가 변해도 자식 컴포넌트만 렌더링할 수 있다.
    2. 컨텐츠를 부모 컴포넌트로 옮긴다. (이건 코드 예제가 필요할 듯하다)
    Copy
    export default function App() {
      let [color, setColor] = useState("red");
      return (
        <div style={{ color }}>
          <input value={color} onChange={(e) => setColor(e.target.value)} />
          <p>Hello, world!</p>
          <ExpensiveTree />
        </div>
      );
    }

    위처럼 color 값을 부모 div에 부여하여 <ExpensiveTree />의 불필요한 리렌더링이 발생하는 상황이라면?

    Copy
    export default function App() {
      return (
        <ColorPicker>
          <p>Hello, world!</p>
          <ExpensiveTree />
        </ColorPicker>
      );
    }
    
    function ColorPicker({ children }) {
      let [color, setColor] = useState("red");
      return (
        <div style={{ color }}>
          <input value={color} onChange={(e) => setColor(e.target.value)} />
          {children}
        </div>
      );
    }

    App 컴포넌트를 두 부분으로 나누어, color 값에 의존하는 컴포넌트는 ColorPicker로 분리한다. color 값이 변하면 ColorPicker는 리렌더링하지만, App에서 받은 children은 변하지 않기 때문에 React는 해당 subtree를 방문하지 않는다. 따라서 ExpensiveTree는 리렌더링되지 않는다.

    👩‍🏫 memouseMemo를 사용하기 전에, 바뀌지 않는 부분들을 분리하여 최적화할 수 있는지 방법을 찾아보자!

    리소스 로딩 순서 최적화

    리소스 로딩 순서 최적화가 어려운 이유

    • 리소스 순서 처리 - 종종 리소스가 올바른 순서로 제공되지않거나 파이프라인되지 않는 경우가 있다.
    • 네트워크/CPU 활용성 - 리소스들이 네트워크나 CPU가 적절히 활용되도록 파이프라이닝되지 않는다. 그 결과 네트워크 처리 과정에는 CPU가 놀고, CPU가 처리중일 땐 네트워크가 노는 “Dead Time”이 발생하게 된다.
    • 서드파티(3P) 패키지들 - 3P들은 웹사이트들의 로딩 성능 최적화보다는 제공되는 기능에 초점을 맞추고 있다.
    • 플랫폼별 특이사항들 - 각 브라우저들은 요청의 우선순위 처리 및 관련 힌트 처리의 구현이 다를 수 있다.
    • HTTP2의 우선순위 처리 - HTTP2 프로토콜은 자체적으로 리소스들의 우선순위나 순서를 설정하기 위한 옵션들을 제공하지 않는다.
    • 리소스별 최적화 - CSS 인라인이나 JS 코드 스플리팅이 어려운 경우들이 있다.

    각 리소스들에 대한 관계, 제약사항 및 우선순위들

    • 중요 CSS - FCP에 필요한 최소 CSS로, 별도의 파일로 포함되기보다 HTML 자체에 인라인으로 포함되는 것이 좋다. 인라이닝이 불가한 경우 중요 CSS들은 문서 다운로드와 동시에 preload되어 서빙될 수도 있다.
    • 폰트 - 중요 폰트를 위한 CSS 역시 인라인 처리 되어야 한다. 인라이닝이 어려울 경우 스크립트는 preconnect처리되어 로드되어야 한다.
    • ATF(Above the Fold) 이미지들 - ATF이미지는 뷰포트 내에 존재하여 페이지 로드 시 사용자에게 처음 표시되는 이미지를 뜻한다(예: hero image) ATF 이미지들은 크기가 명시되어 있어야 한다.
    • BTF(Below the Fold) 이미지들 - 페이지 로드 직후 뷰포트에 보여지지 않는 이미지로, lazyloading 적용 대상이 된다.
    • 1P JavaScript - 1P JS들은 앱의 상호작용이 준비되는 것에 관련되어 있다. 1P JS들은 ATF 이미지 전에 로드되어야 하며, 3P보다 먼저 메인스레드에서 실행되어야 한다.
    • 3P JavaScript - HTML <head>에 동기적으로 포함된 3P스크립트는 CSS 및 폰트 파싱을 블록하여 FCP에 악영향을 준다. 메인 스레드에서 실행되는 3P 스크립트는 1P 스크립트의 실행을 지연시키고 hydration도 지연시켜 FID를 지연시킨다.

    이상적인 리소스 로딩 순서

    👇 아래 링크에서 확인해보자 😋

    Ref https://patterns-dev-kr.github.io/performance-patterns/loading-sequence/


    마무리

    하루는 팀원들과 롯데월드, 다음날은 스타필드 스포츠몬스터에 다녀왔다. 이틀 연속으로 신나게 놀다니 🤸‍♀️

    주말에도 너무 예쁘고 평화로웠던 서래섬에 놀러가 힐링했다. 🌼

    단합력(?)도 기르고, 리프레쉬도 제대로 한 만큼 다시 열일해야겠다!


    Relative Posts:

    5월 4주차 기록

    May 27, 2023

    5월 2주차 기록

    May 13, 2023

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon