ziglog

    Search by

    2월 3주차 기록

    February 18, 2023 • ☕️☕️ 11 min read

    수요일 꿀휴가


    배워가기

    IP 주소로 aws 리소스 찾는법

    1. AWS 콘솔에 접속한다.
    2. EC2 콘솔에 접속한다.
    3. Network Interfaces(네트워크 인터페이스) 탭으로 접속한다.
    4. 검색상자에서 Primary private IPv4 address(기본 프라이빗 IPv4 주소)를 선택(찾으려는 IP 주소에 따라 public을 검색해도 된다.)
    5. 검색상자에서 IP 주소를 입력해서 찾자.

    vite ?raw

    vite에서 이미지, 미디어, 폰트 파일 타입 이외의 asset을 import하려면 [assetsInclude](https://vitejs-kr.github.io/config/shared-options.html#assetsinclude) 설정이 필요하다.

    assetsInclude 없어도 가능한 방법이 있는데, 바로 접미사를 이용해 URL로 에셋을 가져오는 것이다.

    ?raw 도 그중 하나의 접미사인데, 이 접미사로 import하는 애셋은 문자열로 취급한다.

    Copy
    import shaderString from "./shader.glsl?raw";

    타입스크립트 satisfy operator

    기존에는, 표현식이 특정 타입과 매칭되는지 체크하는 것과 표현식의 추론 타입에서 가장 구체적인 타입을 정상적으로 추론하는 것이 상충됐다.

    Copy
    type Colors = "red" | "green" | "blue";
    
    type RGB = [red: number, green: number, blue: number];
    
    const palette: Record<Colors, string | RGB> = {
      red: [255, 0, 0],
      green: "#00ff00",
      bleu: [0, 0, 255],
      // ✅ 'blue'를 'bleu'라고 잘못 적은 typo는 잡힌다.
    };
    
    // 🚨 Property 'at' does not exist on type 'string | RGB'.
    const redComponent = palette.red.at(0);

    객체의 키를 Colors 타입으로 한정했기 때문에, palette 객체에 잘못 작성한 'blue' typo의 오타는 잡힌다.

    그러나 palette.red의 타입이 number[]가 아닌 string이 될 수 있어서, at() 메서드에서 타입 에러가 난다.

    타입스크립트 4.9에 추가된 satisfies 연산자는 표현식의 결과 타입을 바꾸지 않으면서, 표현식의 타입이 특정한 타입과 매칭되는지 검증한다.

    Copy
    type Colors = "red" | "green" | "blue";
    
    type RGB = [red: number, green: number, blue: number];
    
    const palette = {
      red: [255, 0, 0],
      green: "#00ff00",
      bleu: [0, 0, 255],
      // ✅ 'blue'를 'bleu'라고 잘못 적은 typo는 잡힌다.
    } satisfies Record<Colors, string | RGB>;
    
    // ✅ 이제 에러가 나지 않는다!
    const redComponent = palette.red.at(0);
    const greenNormalized = palette.green.toUpperCase();

    satisfies 연산자를 통해 palette의 모든 프로퍼티가 string | number[]와 호환될 수 있음을 보장한다.

    Ref https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html

    vanilla-extract의 Sprinkles

    vanilla-extract는 ‘바닐라 추출액’으로 식재료를 가리키긴 하는데… 😖 자바스크립트 세계에서는 vanilla-extract라는, 타입스크립트로 작성된 제로-런타임 스타일시트를 가리킨다.

    vanilla-extract의 Sprinkles는 제로-런타임 아토믹 CSS 프레임워크로, 커스텀 유틸리티 클래스들을 만들고 빌드타임이나 런타임에 이들을 조합해서 사용할 수 있다.

    sprinkles.css.ts 파일을 만들고, sprinkles 함수를 설정하고 export한다.

    Copy
    // sprinkles.css.ts
    
    import { defineProperties, createSprinkles } from "@vanilla-extract/sprinkles";
    
    const responsiveProperties = defineProperties({
      conditions: {
        mobile: {},
        tablet: { "@media": "screen and (min-width: 768px)" },
        desktop: { "@media": "screen and (min-width: 1024px)" },
      },
      defaultCondition: "mobile",
      // ...
    });
    
    const colors = {
      "blue-50": "#eff6ff",
      "blue-100": "#dbeafe",
      "blue-200": "#bfdbfe",
      // ...
    };
    
    const colorProperties = defineProperties({
      conditions: {
        lightMode: {},
        darkMode: { "@media": "(prefers-color-scheme: dark)" },
      },
      defaultCondition: "lightMode",
      properties: {
        color: colors,
        background: colors,
        // etc.
      },
    });
    
    export const sprinkles = createSprinkles(responsiveProperties, colorProperties);

    Ref https://vanilla-extract.style/documentation/sprinkles-api/

    React.suspense의 비밀

    React.suspense는 Promise가 발생하면 자식의 스타일을 display: none으로 바꾼다. Promise가 resolve 되면 display: none 속성은 삭제된다.

    Ref https://github.com/facebook/react/issues/14536

    useEffect의 clean up

    React useEffect의 clean up 함수는 useEffect가 실행되고, 다음 실행되기 전에 다시 실행된다.

    • 의존 배열이 없을땐 마운트 해제될 때 실행된다.
    • 의존 배열이 있다면 의존 배열이 변경될 때 실행된다.

    react-hook-form

    • dynamic field를 만들 때에는 useFieldArray를 쓸 수 있다.
    • fieldArray는 객체의 배열 형태로 된 필드만 만들 수 있다.
      • string[]은 안 되고, { id: string }[]은 가능하다. 말 그대로 필드의 배열이기 때문에 각각이 필드여야 한다.
    • fieldArray와 controller를 함께 사용할 때는 fieldArray의 대상이 되는 필드, 몇 번째 input인지를 나타내는 index, 내부 속성까지 prop의 name으로 전달해야 제대로 값을 컨트롤할 수 있다.
      • 위 케이스의 경우 ~field.${index}.id를 useController hook의 name prop으로 전달한다.

    module federation에서 chunk 파일

    module federation을 사용해서 여러 remote app을 불러올 때, 각 자바스크립트 chunk 파일의 이름은 다를 수 있지만, id는 동일할 수 있다.

    만약 동일한 id의 chunk를 호출하면 위에서 chunkId를 불러온 기록이 남겨져서 호출에 실패할수도 있다. 따라서 chunk 파일의 이름이 다르다고 안심하지 말고 id가 같다면 optimize 내용을 바꿔 빌드하거나, chunkId 길이를 바꿔서 id를 서로 다르게 해줘야 한다.

    onBluronClick

    • onBlur 이벤트가 onClick보다 이벤트 우선순위가 높다
    • onMouseDown 이벤트는 onBlur 이벤트보다 이벤트 우선순위가 높다

    따라서 onClick 핸들러를 onBlur 보다 먼저 사용하고 싶다면, onMouseDown을 사용한다.

    자바스크립트 모든 이벤트의 순서를 알고 싶었는데, 못 찾겠다 😵‍💫

    Ref https://velog.io/@broccoliindb/onBlur-on-react

    new Axios() vs axios.create()

    new Axios() 로 axios 인스턴스를 생성하면, 배열이나 객체 등의 데이터가 JSON.stringify() 된 형식의 string으로 내려오는 경우가 있다. 🥲

    대신 axios.create() 로 axios 인스턴스를 생성하면 똑바로 내려온다.

    이유는… axios 깃헙 코드에서 찾을 수 있다.

    new Axios()를 호출하면 transformResponse()의 설정 기본값이 없기 때문에 문자열 응답을 그냥 내려준다. 하지만 axios.create()는 내부적으로 axios.createInstance() 함수를 호출하여 기본 설정을 넣어주기 때문에 응답이 정상적으로 JSON 형태로 반환된다.

    react-query의 suspense 옵션

    을 true로 켜두니 리액트 컴포넌트의 state를 deps로 받는 dependent query를 실행할 때 자꾸 이전 state 값으로 쿼리를 보내는 문제가 발생했다.

    suspense를 켜놓기만 하고 fallback을 제공하는 <Suspense /> 컴포넌트로 감싸지 않아서 버그가 난 듯… 싶었지만?

    리액트 컴포넌트의 setState가 바라보고 있는 state는 최초 mount된 컴포넌트의 state이고, 우리가 변경하고자 하는 state는 API call이 성공한 후 다시 re-mount된 컴포넌트의 state이기 때문에, 이전 state의 값으로 api call을 하고 있었기 때문이다.

    suspense를 유지하면서 이 문제를 해결하려면 어떻게 해야할까? 다음 링크로 알아보자 🤗

    Ref https://sangminnn.tistory.com/76

    Next.js에서 router query id가 처음에 undefined인 이유

    정적 파일 최적화(Automatic Static Optimization)에 의해 정적으로 최적화된 페이지는 루트 매개 변수가 제공되지 않아서, query가 빈 객체가 된다

    Next ver.10부터는 router.isReady 를 사용해서 router 필드가 클라이언트 측에서 업데이트되고 사용할 준비가 되었는지 여부를 체크할 수 있다.


    이것저것

    • Web Proxy 툴 Charles와 Proxyman 이라는 Web Proxy 툴이 있다.
    • isFinite() - parameter로 전달받은 값이 유한한 숫자인지를 판별헤주는 내장 메서드
    • astro에서는 vue,svelte,react 모두 사용가능하다.
    • typescript website는 TwoSlash를 사용해서 코드예시에서 타입을 나타내준다.
    • CSS에서 :root 의사 클래스를 사용해서 전역 root tag를 명시적으로 선택할 수 있다. (html의 {}과 기능적으로 동일하다.)
    • Storybook7은 전반적으로 타입 안정성이 개선되었다. 특히 satisfies 를 사용하면 required prop이 빠졌을 때 에러를 표시해주는 것은 유용해 보인다.
    • bash shell -
      • 쉘에서 커맨드 라인이 종료되고 이 다음부턴 인수가 나오는 걸 명시할 때 사용한다.
      • ex) npm run swizzle @docusaurus/theme-classic Footer -- --eject
    • vite에서는 import.meta.env 로 환경변수에 접근할 수 있다.
    • vscode files association - 다음과 같이 vscode의 settings.json 에서 설정하면 myformat 확장자를 json처럼 인식한다.
      Copy
        "files.associations": {
          "*.myformat": "json"
        }
    • .d.ts 파일에서 import나 export를 하면 다른 파일에서  .d.ts 파일에서 선언된 전역 타입에 자동으로 접근할 수 없게 된다.
    • .md에 [[_TOC_]] 를 쓰면 목차가 튀어나온다. Gitlab 전용 문법이고, 일부 목차를 제외하는 기능은 아직 없다. 누군가 깃랩에 건의했으나 4년째 묵혀있다.
    • vite가 dev모드로 실행중일 때 vite는 서버 역할을 하고 index.html 파일은 application의 entry point가 된다.
    • webpack은 자바스크립트의 파일 내용들을 module로 분해해서 관련 있는 module끼리 모아 chunk로 분리한다. 이때 module은 moduleId로, chunk는 chunkId로 구분하며, 이는 각 3~5자리의 숫자이다. (ex. 70518)
    • chunkId는 한번 불러오고나면 전역에 불러왔다고 기록을 남겨서 여러번 불러오는 경우를 막는다. 불러오지 않았다면 script tag로 해당 chunk js 파일을 불러온다.
    • width: fit-content 속성으로 flex component의 자식의 크기를 딱 맞게 지정할 수 있다.
    • elastic search - 분산 검색 엔진으로, 확장성과 유연성이 뛰어나다. (Ref)
    • querySelector는 live한 DOM을 잡아주지만, querySelectorAll은 static DOM을 잡는다. 여러 개의 live한 DOM을 잡으려면 getElementsByTagName 을 사용한다. 왜 이렇게 헷갈리게 뒤죽박죽 해놨어! 🤯 (Ref)
    • Sentry N+1 Calls - 동시적으로 같은 URL에 네트워크 요청을 많이 보낼 때 발생하는 성능상의 문제로, 하나의 요청을 list item 모두에 대해서 보낼 때 발생한다. (Ref)
    • typeorm upsert() - ON CONFLICT DO UPDATE 쿼리를 대신하는 함수로, 이미 존재하지 ‘않는’ 경우에만 새 엔티티를 삽입해준다. 짱! 👍

    기타공유

    노션 AI

    구글의 ChatGPT, MS의 Bing을 잇는 AI의 붐… 노션AI가 발빠르게 탄생해버렸다.

    원하는 주제로 입력하면, 글을 대신 써준다. 아이디어 브레인스토밍도 같이 해주고, 메일도 대신 써준다. 꽤나 재밌어 보인다. 알파 버전을 사용해보기 위해 웨이팅리스트에 넣고 기다려야 한다.

    근데 이렇게 기계가 글 다 써주면 인간은 이제 모하나 🤷‍♀️

    Ref https://www.notion.so/product/ai

    core-js 개발자의 이야기…

    전 세계 많은 웹사이트들에서, 그리고 나도 사용하는 core-js가 한 사람에 의해 시작된 오픈소스 라이브러리였다니 믿기지 않는다. 그리고 이 메인테이너가 큰 사고를 당하며 잠시 사라졌던 이야기, 돈이 되지 않는 오픈소스를 붙들고 온갖 미친 사람들한테 욕을 먹어가며 금전적으로 어려움을 겪어왔던 이야기들을 읽으며 충격을 받았다.

    그의 말대로, 요즘 인터넷 세상을 장악한 온갖 대단한 사이트들이 core-js에 지탱하고 있는데, 아직도 고쳐야 할 코드들이 산더미인데 아무런 펀딩 없이 이렇게 진행되어왔다니 놀랍고 안타까울 따름이다… ‘익숙함에 속아 소중함을 잃지 말자’라는 말이 떠오른다. core-js가 무너지지 않았으면, 그리고 그가 그의 가족을 지킬 수 있었으면 좋겠다.

    Ref https://github.com/zloirock/core-js/blob/master/docs/2023-02-14-so-whats-next.md

    구글에서 만든 wireit

    어떻게 읽는..? 처음에 ‘와이렛’ -> ‘와이래’ -> ‘와이라노…’라고 생각했다.

    npm 스크립트를 더 똑똑하고 효율적으로 업그레이드 시켜주는 툴이라고 한다.

    머하는 앤진 잘 모르겠다.

    Ref https://github.com/google/wireit?fbclid=IwAR030-MC7NYE5oS6MuNxX412aGbJztWMG_96LtY0b4ifHUpj0Byt_Dcdts4&mibextid=S66gvF

    webcontainers

    Node.js를 브라우저에서 실행하게 해주는 런타임이다. 익숙한 단어들의 조합이지만 오… 좀 혁신적인 것 같다.

    사용자 코드를 실행하기 위해 가상머신(VM)을 사용했던 앱들은 이제 WebContainer를 사용해서 클라이언트에서 돌릴 수 있다.

    Copy
    import { WebContainer } from "@webcontainer/api";
    
    // Call only once
    const webcontainerInstance = await WebContainer.boot();

    요렇게… 인스턴스를 만들어서 실행시키나 보다.

    Copy
    webcontainerInstance.on("server-ready", (port, url) => (iframeEl.src = url));

    😲😲😲

    Ref https://webcontainers.io/


    마무리

    수요일에 휴가를 써서 그런가, 일주일이 더 빨리 사라졌다. 평일 동안에 잠을 많이 잔 건지, 주말에 뻗어서 꿀낮잠을 오래오래 자버리고 말았다. 그래도 늦은 밤 잠이 또 온다 🥱

    시간은 잘만 흐르고, 호주 갈 날이 점점 다가오고 있다… 기대 반 걱정 반 🙃


    Relative Posts:

    2월 4주차 기록

    February 24, 2023

    2월 2주차 기록

    February 11, 2023

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon