ziglog

    Search by

    12월 3주차 기록

    December 23, 2023 • ☕️ 6 min read

    올해 마지막 근무일 ✌️


    배워가기

    webpack config의 assetModuleFilename

    파일을 출력 디렉터리로 내보낼 때 asset/resource 모듈은 기본적으로 [hash][ext][query] 파일명을 사용한다.

    webpack 설정에서 [output.assetModuleFilename](https://webpack.kr/configuration/output/#outputassetmodulefilename)을 설정하여 이 템플릿을 수정할 수 있다.

    Copy
    const path = require("path");
    
    module.exports = {
      entry: "./src/index.js",
      output: {
        filename: "main.js",
        path: path.resolve(__dirname, "dist"),
        assetModuleFilename: "images/[hash][ext][query]",
      },
      module: {
        rules: [
          {
            test: /\.png/,
            type: "asset/resource",
          },
        ],
      },
    };

    Ref https://webpack.kr/guides/asset-modules/#custom-output-filename

    webpack config devServer의 proxy 설정

    proxy를 쓰지 않았을 때는 클라이언트에서 서버 요청 시 CORS 에러가 발생할 수 있다.

    proxy 속성을 설정하면 서버에서 해당 요청을 받아준다.

    Copy
    module.exports = {
      //...
      devServer: {
        proxy: {
          "/api": "http://localhost:3000",
        },
      },
    };

    Ref

    scrollIntoViewIfNeeded

    요소가 브라우저 창의 visible 영역에 있지 않다면 요소를 visible 영역으로 스크롤해준다.

    비표준 스펙으로, 지원하지 않는 브라우저가 많다

    Ref https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoViewIfNeeded

    RTL에서 Promise.all 테스트를 할 때

    async~await 구문을 여러 개 테스트할 때, 다음 워닝이 뜰 수 있다

    Warning: You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one.

    waitFor 키워드를 통해 순차적으로 테스트를 하면 된다.

    Copy
    await waitFor(() => [
      screen.getByTestId("my-id-1"),
      screen.getByTestId("my-id-2"),
    ]);

    Ref https://github.com/testing-library/react-testing-library/issues/615

    jest의 toHaveStyle은 CSS module에서 작동하지 않는다

    • sass와 css는 일반적으로 jest에서 제외된다.
    • identity-obj-proxy가 style의 className을 잡고 있긴 하지만, mock 데이터일 뿐이다

    identity-obj-proxy

    • css 파일을 import해서 사용하는 사람에게 필요한 library
    • jest는 identity-obj-proxy로 객체를 CSS module로 import할 수 있다. 그러면 style 객체 값을 갖고 있는 className들을 그대로 사용할 수 있다
    • jest.config.module에 다음과 같이 설정한다
    Copy
    moduleNameMapper: {
      '.*.(css|scss)$': 'identity-obj-proxy',
      // ...
    },

    Ref

    sleep vs loop

    빠른 시간 내에 수행되어 시간을 측정하기 어려운 경우 Promise를 이용해서 sleep 함수를 구현하여 테스트하는 방법이 있다.

    그러나 이렇게 만들어진 sleep 함수의 경우 컨텍스트 스위칭이 발생한다.

    sleep 대신 아래처럼 loop를 통해서 cpu 점유를 이어가는 형태로 테스트를 해볼 수 있다.

    Copy
    
    function delay(ms: number) {
      const start = Date.now();
      for (;;;) {
        if (Date.now() - start > ms) {
        return;
      }
      }
    }

    이것저것

    점점 없어진다 🫠

    기타공유

    A Chain Reaction

    Dan Abramov의 오랜만의 블로그 글!

    <p> 태그나 <i> 태그처럼 HTML에서 기본으로 제공되는 간편한 태그들은, 개발자들로 하여금 그 뒤의 복잡한 로직을 무시할 수 있게 해준다. 이와 같은 맥락에서 여러 빌트인 툴에서는 text-2xl 또는 font-sans 등의 preset className을 제공하기도 한다.

    JSX로 컴포넌트를 작성할 때도 이름을 짓는다.

    Copy
    <Greeting person={alice} />

    위 코드는 Greeting을 그 자체의 의미로 이해하게끔 만들다.

    하지만 사람이 이해하는 ‘언어’와 브라우저가 이해하는 ‘언어’는 조금 다르다. 브라우저는 Greeting과 더불어 alice를 어떻게 해석해야 하는지도 모를 것이다.

    그래서 개발자는 alice를 정의해줘야 한다.

    Copy
    const alice = {
      firstName: "Alice",
      birthYear: 1970,
    };

    그리고 Greeting도 정의해준다.

    Copy
    function Greeting({ person }) {
      return (
        <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
          Hello, <i>{person.firstName}</i>!
        </p>
      );
    }

    이제 다음 코드를 봤을 때,

    Copy
    <Greeting person={alice} />

    브라우저는 개발자 머리속 개념인 Greeting을 이해하진 못하더라도, 화면에 어떻게 보여줘야 할지 알 수 있게 된다.

    JSX는 내부적으로 다음과 같이 구성되어 있다.

    Copy
    const originalJSX = <Greeting person={alice} />;
    console.log(originalJSX.type); // Greeting
    console.log(originalJSX.props); // { firstName: 'Alice', birthYear: 1970 }

    브라우저는 JSX를 다음과 같은 과정을 거쳐 해석할 것이다.

    Copy
    function translateForBrowser(originalJSX) {
      const { type, props } = originalJSX;
      return type(props);
    }

    translateForBrowser가 좀 더 복잡한 빌트인 태그들(ex. details)과 컴포넌트의 조합으로 이루어진 코드들도 해석할 수 있게 만들어보자.

    Copy
    function translateForBrowser(originalJSX) {
      if (originalJSX == null || typeof originalJSX !== "object") {
        return originalJSX;
      }
      if (Array.isArray(originalJSX)) {
        return originalJSX.map(translateForBrowser);
      }
      const { type, props } = originalJSX;
      if (typeof type === "function") {
        const returnedJSX = type(props);
        return translateForBrowser(returnedJSX);
      } else if (typeof type === "string") {
        return {
          type,
          props: {
            ...props,
            children: translateForBrowser(props.children),
          },
        };
      }
    }

    그러면 다음과 같이 사람의 관점에서 작성한 JSX 코드는

    Copy
    <ExpandableGreeting person={alice} />

    이렇게 바뀔 것이고,

    Copy
    <details>
      <Greeting person={alice} />
    </details>

    최종적으로 다음 코드로 변환될 것이다.

    Copy
    <details>
      <p className="text-2xl font-sans text-purple-400 dark:text-purple-500">
        Hello, <i>Alice</i>!
      </p>
    </details>

    이와 같은 과정을 chain reaction이라 부르고 싶다.

    개발자는 데이터와 코드를 함께 작성하고, 브라우저는 더 이상 실행할 코드가 없을 때까지 이를 변환한다.

    그런데 이 변환 과정은 어디서 발생하는 걸까?

    컴퓨터? 아니면 내 자신?

    열린 결말인가? 이대로 글이 끝나버렸다…

    Ref https://overreacted.io/a-chain-reaction/

    TextSniper

    이미지에 있는 글자를 OCR로 따주는 앱

    Ref https://textsniper.gumroad.com/l/TXSGR?offer_code=FREEFOR24H


    마무리


    Relative Posts:

    1월 첫주차 기록

    January 6, 2024

    12월 2주차 기록

    December 16, 2023

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon