ziglog

    Search by

    5월 2주차 기록

    May 11, 2024 • ☕️☕️☕️ 14 min read

    배워가기


    window.matchMediaprefers-color-scheme으로 사용자의 다크/라이트 모드 구분하기

    window.matchMedia로 미디어 쿼리 문자열을 분석할 수 있다.

    Copy
    if (window.matchMedia("(min-width: 400px)").matches) {
      /* 뷰포트 너비가 400 픽셀 이상 */
    } else {
      /* 뷰포트 너비가 400 픽셀 미만 */
    }

    그리고 CSS의 prefers-color-scheme 속성은 사용자의 디바이스가 다크모드인지 라이트모드인지 알려준다.

    Copy
    .theme-a {
      background: #dca;
      color: #731;
    }
    
    @media (prefers-color-scheme: dark) {
      .theme-a.adaptive {
        background: #753;
        color: #dcb;
        outline: 5px dashed #000;
      }
    }

    사용자가 웹페이지에서 다크/라이트 모드를 직접 변경하도록 옵션을 제공하고 싶을 때, 다음과 같이 작성할 수 있다.

    Copy
    window.matchMedia("(prefers-color-scheme: dark)").matches ? ... : ...;

    Ref

    webpack config에서 loader가 적용되는 순서

    webpack config에서 loader가 적용되는 순서는 ‘뒤에서부터’라고 하는데, 잘 이해가 되지 않았다.

    다음과 같이 적용 순서를 표현하면 이해하기 쉽다.

    Copy
    {
      test: /\.ext$/
      use: ['third-loader', 'second-loader', 'first-loader']
    }

    위 코드는 다음과 같이 동작한다.

    Copy
    third(second(first(source)))

    Ref https://kettanaito.com/blog/writing-custom-webpack-loader

    @babel/preset-react

    babel의 @babel/preset-react에서 development를 사용하는 이유는 디버깅의 용이성 때문이다.

    development 옵션을 사용하면 아래 플러그인을 추가로 사용한다.

    • @babel/plugin-transform-react-jsx-self
    • @babel/plugin-transform-react-jsx-source

    그러면 jsx에 __self__source 프로퍼티를 주게 되는데, 각 프로퍼티의 역할은 다음과 같다.

    • __self: JSX 태그에 대한 참조를 나타내고, React가 이벤트핸들러 내에서 발생하는 오류를 디버깅할 때 사용된다.
    • __source: JSX 엘리먼트가 정의된 파일의 위치와 줄 번호 정보를 포함해서 개발자가 문제가 발생한 정확한 위치를 찾을 수 있도록 도움을 제공한다.

    Ref

    iOS에서 input disabled

    iOS에서 input이 disabled인 경우, opacity가 0.4로 적용된다. (native style sheet - safari)

    색상을 정확하게 표시 하기 위해서는 opacity 조정 및 -webkit-text-fill-color 추가로 색상을 고정해야 한다.

    Copy
    color: {color};
    -webkit-text-fill-color: {color};
    -webkit-opacity: 1;
    opacity: 1;

    운영체제에 따른 기본 폰트

    운영체제에 따라 기본 폰트가 다르다.

    Mac에서는 sans-serif 폰트에 대해서 Apple SD 산돌고딕 Neo 폰트가 적용되고, windows 에서는 맑은고딕(Malgun Gothic) 폰트가 적용된다.

    같은 폰트 사이즈를 적용하더라도 실제 width가 같지 않아 문구 적용 시 여유가 거의 없는 경우라면 줄바꿈이 일어날 수 있다.

    Promise.withResolvers

    Promise.withResolversnew Promise를 대체할 수 있다. Promise.withResolversPromise 객체와 resolve, reject 함수를 포함한 객체를 반환한다.

    AS-IS

    Copy
    const delay = (ms: number) =>
      new Promise((resolve) => setTimeout(resolve, ms))

    TO-BE

    Copy
    const delay = (ms: number) => {
      const { promise, reject, resolve } = Promise.withResolvers();
      setTimeout(resolve, ms);
      
      return promise
    }

    Ref https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers

    브라우저 리스트 꿀팁

    • 구글 애널리틱스 데이터로 브라우저 리스트를 만들어 주는 툴 (Ref)
    • 브라우저 리스트를 정의하면 국가별로 얼마나 커버가 가능한지 알려주는 사이트 (Ref)
    • 브라우저 리스트로 서포트하지 않는 스펙을 쓰면 빨간줄이 뜨게하는 린트 플러그인 (Ref)

    ESLint v9

    ESLint v9는 4월 6일에 출시되었으며 현재는 9.2.0이다.

    v9는 Flat Config 지원, 패키지에 ESLint 플러그인 내장 가능, 실행 속도 증가 등의 큰 변화가 있었다.

    다만 생태계가 아직 Flat Config 호환 작업 진행중이기 때문에 실제 적용은 내년에나 하지 않을까 싶다.

    CSS oklch()

    rgb() 혹은 hsl()과 같이 색상을 정의할 때 사용할 수 있는 함수 표현식 중 하나

    보통은 RGB를 많이 사용하지만, OKLCH는 RGB에 비해 코드만으로 색상 정보를 예측할 수 있을 정도로 가독성이 좋다는 장점이 있다.

    Ref https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch

    dirty form confirm 받기

    form이 dirty할 때 navigation을 수행하기 전 confirm을 받을 수 있다.

    client-side 라우팅 시에는 라우터 쪽에서, document를 새로 불러오는 라우팅 시에는 직접 beforeUnload 이벤트를 활용하면 된다.

    cf) react-router-dom v6에는 useBlocker 훅이 존재한다.

    babel, swc는 tsconfig.json을 바라보지 않는다.

    babel, swc는 tsconfig.json을 바라보지 않는다.

    tsc는 타입체킹, 컴파일을 모두 수행하기 때문에 타입 영역, 값 영역을 모두 바라본다.

    그러나 babel, swc 등의 컴파일러는 트랜스파일에만 관심있고 타입체킹은 하지 않기 때문에 tsconfig.json을 필요로 하지 않는다. (값 영역만 사용)

    cf) tsserver는 tsconfig.json을 이용해서 타입체킹을 합니다. (타입영역만 사용)

    사실 생각해보면 당연한게 babel, swc 등의 컴파일러는 값 영역만 바라보기 때문에 tsconfig.json 옵션 거의 대부분이 필요하지 않다!

    ESLint env

    ESLint의 설정중 env 필드는 코드의 실행 환경을 ESLint에 알려주는 역할을 한다.

    Copy
    env: { browser: true, es2020: true }
    • browser: true: 코드가 브라우저 환경에서 실행된다는 것을 나타내며, 브라우저 환경에서 사용 가능한 전역 변수(예: window, document 등)가 정의되어 있다고 가정한다. ESLint는 이러한 전역 변수를 인식하고 해당 변수 사용 시 오류를 발생시키지 않는다.
    • es2020: true: 코드가 ECMAScript 2020 (ES11) 이상의 기능을 사용한다는 것을 나타낸다. 즉, ESLint가 ES2020에 도입된 문법을 인식한다.
      • 만약 es2020: true를 넣지 않으면 ES5가 기본값으로 설정된다.
      • flatConfig에서는 latest가 기본값이다.

    env에서의 es버전과 parserOptions에서의 ecmaVersion도 주의해야 한다. env에서는 특정 es버전의 전역변수를 위해 사용되고, 구문분석은 parserOptions.ecmaVersion를 사용한다.

    react-hook-form의 useForm - criteriaMode

    react-hook-form의 useForm API에 criteriaMode 옵션이 있다.

    발생한 validation을 하나만 잡을지 트래킹할지 고르는 옵션이다. (firstError 또는 all)

    all로 설정하면 실패한 모든 validation을 알 수 있다. 에러 객체에 types 필드 안에 들어간다.

    챗GPT에 의하면 firstError로 설정하면 유효성 검사가 조금은 더 빠르다고 한다.

    페이징 처리를 위한 offset 방식의 단점

    페이징 처리를 위한 서버의 offset 방식과, 이것이 왜 성능에 좋지 않은지 알아보자.

    클라이언트는 보통 페이지네이션을 위해 page(currentPage), pageSize(limit)를 request param으로 보낸다.

    그러면 서버에서 offset 값을 구하게 된다.

    Copy
    offset = (page - 1) * pageSize

    (ex. 3페이지를 요청하는데, 10개까지만 볼래요 -> (3-1) * 10 = 20, offset = 20 )

    그러면 서버에서는 질의를 다음과 같이 한다.

    Copy
    SELECT * FROM table LIMIT 10, OFFSET 20; -- 21 ~ 30 번까지 노출

    앞 부분의 데이터를 조회할때는 문제가 되지 않지만, offset이 매우 클 경우 (ex. 1,000,000 부터 10개를 조회하는 경우)에는 성능상 문제가 될 수 있다.

    이유는 데이터를 반환할 때, 처음 데이터부터 offset에 해당하는 row + limit 개수 까지 조회한 후에 앞에 필요하지 않은 데이터들을 날린 결과를 반환한다.

    (ex. OFFSET: 5000, LIMIT 10인 경우, 5010개의 데이터를 모두 읽은 후, 5000번까지의 데이터는 버림. 이후 5001 ~ 5010까지 반환.)

    react-hook-form 성능 최적화 하기

    watch, formState.errors 대신, useWatch, useFormState를 사용하면 리렌더링 되는 범위를 해당 훅이 있는 컴포넌트로 격리할 수 있다.

    trigger를 사용할때 파라미터를 빈값이나 배열로 넘기면 전체 form 상태가 리렌더링 된다. 필드를 하나만 넘기는 것이 좋다.

    딥링크 vs 앱스킵

    딥링크: 특정 컨텐츠에 직접 도달하는 링크

    예를 들어, https://comic.naver.com 로 들어가서 클릭 클릭을 통해 특정 웹툰 페이지로 들어가지 않고, https://comic.naver.com/webtoon/list?titleId=807178&tab=wed 로 직접 들어갈 때 사용되는 이 링크가 딥링크.

    모바일에서 딥링크를 구현하는 방식은 세 가지가 있다.

    • URI Scheme
    • App Link
    • Universal Link.

    App Link는 안드로이드만 지원, Universal Link는 iOS만 지원한다. URI Scheme은 모바일 앱에서 딥링크를 작동시키는 기술 표준으로, 사용자가 앱 내부의 컨텐츠에 직접 접근할 수 있게 해준다. 세 방식 중 가장 오래되었다.

    하지만 URI Scheme에는 단점도 있다.

    • 앱이 설치되지 않은 경우 실행이 되지 않는다
    • 동일한 스킴을 사용하는 앱이 여러개 있으면 구분을 못한다

    cf) 스킴: URI Scheme을 이용한 딥링크는 앱에 Scheme값을 등록한 후, 특정 Scheme값을 호출하면 특정 앱을 오픈한다.

    앱스킴: URI Scheme 방식을 활용해 구현한, 앱에서 사용하는 Scheme

    (ex. baemin://, baemin-beta://)

    부록: 특정 지면에 사용되는 앱스킴과 달리 함수 또는 기능을 실행하는 action 스킴도 있다. (baemin-action://)

    마진이 겹치는 상황 해결하기

    Copy
    <div style="margin-top: 10px">
      <div style="margin-top: 10px"></div> 
    </div>

    두 개의 <div>가 모두 margin-top: 10px을 갖고 있기 때문에, 결과적으로 margin-top20px이 될 것이라고 생각하기 쉽다. 하지만 실제로는 10pxmargin만 표시된다.

    이를 마진 상쇄(margin collapse) 현상이라고 합니다.

    마진이 상쇄되는 조건은 여러 가지가 있다.

    이를 해결하기 위해서는 display: flow-root를 사용할 수 있다. 해당 속성을 부모 자식 박스에 주면 새로운 BFC(Block Formatting Context)를 생성하게 된다. 부모와 자식은 서로 다른 BFC를 가지게 되어 마진 상쇄 현상이 발생하지 않는다.

    객체 vs Map

    • Map을 사용하는 이유

      • 키로 어떤 데이터 형식이든 사용할 수 있다.
      • 순서가 보장되며, 입력된 순서대로 요소에 접근할 수 있다.
      • 맵은 반복 가능하며, 쉽게 반복할 수 있다.
    • 객체를 사용하는 이유

      • 더 간단하게 정의할 수 있다.
      • 대부분의 경우 키가 문자열이기 때문에 객체를 사용하는 것이 더 편리하다.
      • JSON과 같은 구조를 표현할 때 자연스럽다.

    Ref https://velog.io/@surim014/use-maps-more-and-objects-less

    form 밖에 submit 버튼 두는법

    form attribute를 사용하면 된다

    Copy
    <form id="my-form">
      <input type="text" name="name" />
    </form>
    
    <button type="submit" form="my-form">저장</button>

    Ref https://www.impressivewebs.com/html5-form-attribute/

    구글 SEO 엔진의 특이점

    구글 SEO 엔진은 <meta name="keywords"> 태그를 무시한다.

    keyword stuffing을 방지하기 위함인 것 같다

    keyword stuffing? 검색 엔진에서 높은 우선순위를 얻기 위해 웹 페이지에 특정 키워드를 고의로 다량 삽입하는 행위를 말한다.

    Ref

    eslint.workingDirectories

    vscode의 settings.json 파일에서 eslint.workingDirectories 역할은 다음과 같다.

    • eslint 플러그인이 프로젝트 내에서 어떤 디렉토리를 기준으로 코드 검사를 수행할지 지정한다.
    • 갑자기 나의 import문이 엄한 곳에서 tsconfig를 찾는다면 이를 의심해보자

    INP (Interaction to Next Paint) 지표

    사용자가 페이지에 머무는 동안 발생시키는 모든 인터렉션을 관찰하여 전반적인 응답성을 관찰하는 지표

    구글에서는 첫번째 입력만 체크하는 FID(First Input Delay) 지표를 대체하여 사용하고 있다. 200ms 이내일 때 좋은 INP 수치를 가졌다고 본다.

    이것저것 모음집


    • webpack의 resolveLoader - loader의 alias를 정할 수 있다 (Ref)
    • React의 useEffect는 clean-up 함수부터, 그리고 자식부터 실행된다.
    • 메모리 누수는 크롬 > 작업 관리자 > 자바스크립트 메모리 활성 숫자 () 증가로 쉽게 모니터링할 수 있다.

    (Ref)

    • React Fiber는 current와 WIP Tree 두 가지를 활용해서 변경사항을 반영하는데, 이를 더블 버퍼링 기술이라고 한다. 더블 버퍼링 기술은 React 팀에서 만든게 아니라 컴퓨터 그래픽스에서도 이미 사용하는 용어다.

    기타공유


    ASCII 문자만 가지고 3D 렌더링 만들기

    세상에는 참 신기하고 대단한 사람이 많다.

    Ref https://kciter.so/posts/ascii-3d-renderer/

    토스의 한글 라이브러리

    토스에서 만든 새로운 한글 라이브러리

    k-popo도 유용하다. 은/는/이/가 처리가 필요한 곳에 쓰기 좋다. (Ref)

    Ref https://www.npmjs.com/package/es-hangul

    JSR (the JavaScript Registry)

    npm의 superset으로 deno 팀에서 개발한 자바스크립트 레지스트리

    npm이 출시될 때는 현재의 개발 환경을 염두에 두고 만들어지지 않았기 때문에, 이를 개선하고자 만들어졌다고 한다. 타입스크립트와 ESM 배포에 최적화되어 있다.

    node 뿐만 아니라 deno, bun과 같이 다양한 자바스크립트 런타임 환경을 지원한다.

    Ref https://jsr.io/

    bundlejs

    npm package의 크기를 체크해준다.

    bundlephobia는 (모듈별로 나뉘긴 하지만) 통째로 보여주는 반면, bundlejs는 import하는 코드를 직접 작성하고 그것을 빌드한 결과물을 측정하므로 나무를 흔든 후의 실제 크기를 볼 수가 있다.

    https://bundlejs.com/

    React Conf 2024 Agenda 공개

    React19와 React Sever Component 관련 내용이 많이 보인다.

    Ref https://conf.react.dev/agenda

    마무리


    사내 TIL 챌린지가 끝나지 않고 있다. 매주 새로 배우는 내용, 블로그에 적을 내용이 풍성해져서 좋지만 조금 벅차기도 하다 (ㅋㅋㅋ)

    날씨도 따숩고 왠지 한가한 5월을 적당히 여유롭게 보내고 있는 요즘이다.

    그리고 진짜 가고 싶던 뷰민라를 다녀왔지 🎵

    다음은 펜타포트인가…🎸 큰일났다


    Relative Posts:

    5월 3주차 기록

    May 18, 2024

    5월 첫주차 기록

    May 6, 2024

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon