ziglog

    Search by

    3월 5주차 기록

    April 1, 2023 • ☕️☕️ 10 min read

    고오-급 스테이크🥩와 동물 친구들🦘🐨


    배워가기

    vite의 env

    vite는 import.meta.env를 통해 환경변수에 접근하도록 하고 있다 (공식문서)

    다만 외부 라이브러리가 process.env를 사용한다면 process is not defined 에러를 마주할 수 있는데, vite.configdefined['process.env'] : {} 로 빈 env를 정해서 넘어갈 수 있다.

    다만 실제로 process.env가 비어있기 때문에 빈값에 대한 오류가 발생할 수 있으니 적절한 값을 채워넣음으로써 해결해야할 수도 있다.

    Copy
    export default defineConfig({
      // ...
      define: {
        "process.env": {},
      },
    });

    storybook과 exports

    storybook은 기본적으로 webpack 4를 사용하기 때문에, package.json의 exports field를 지원하지 않는다.

    package.json의 exports field는 패키지가 node_modules lookup이나 이름으로 import되었을 때의 엔트리 포인트를 지정해준다. 패키지 모듈을 여러 환경에서 사용하게 해주면서도, 내부 파일에 대한 접근을 제한할 수 있는 방법을 제공한다.

    Copy
    {
      "exports": {
         ".": "./main.js",
         "./sub/path": "./secondary.js",
         "./prefix/": "./directory/",
         "./prefix/deep/": "./other-directory/",
         "./other-prefix/*": "./yet-another/*/*.js"
     }
    }

    👆 webpack4까지는 위 기능이 지원되지 않았던 것 같다.. 😕

    따라서 storybook으로 빌드하는 외부 의존성 모듈이 exports field를 사용한다면 storybook이 webpack5를 사용하도록 추가 구성을 해줘야한다.

    cf) storybook 6.2버전부터 webpack 5를 지원한다

    Ref https://nodejs.org/api/packages.html#exports

    react 버전이 다른 라이브러리의 충돌

    emotion 등의 라이브러리의 같은 버전을 사용하더라도, react를 17을 쓰냐 18을 쓰냐에 따라서 내부적으로 다른 버전의 resolution을 사용한다. 이 경우 emotion은 버전이 같더라도 아예 다른 모듈로 취급돼서 문제가 발생한다.

    예를, 들어 프로젝트 환경은 emotion 11.10.0, react 17.0.0인데, 가져오는 라이브러리 A가 emotion 11.10.0, react 18.0.0이라고 가정하면 라이브러리에서 사용하는 emotion과 프로젝트에서 사용하는 emotion은 다르다.

    pnpm같은 non-flat 패키지 매니저의 경우 이 두가지 모듈을 모두 가지고 있다. 이때, 아래와 같은 경우 타입에러가 발생할 수 있다.

    Copy
    // library-A. react 18.0.0 emotion 11.10.0
    import styled from "@emotion/styled";
    const A_Component = styled.div``;
    
    // project. react 17.0.0 emotion 11.10.0
    import { A_Component } from "@library-A";
    import styled from "@emotion/styled";
    const Component = styled(A_Component)``; // 🚨 Type Error

    같은 emotion 버전의 styled 키워드로 선언했더라도, react 버전이 다르기 때문에 내부에서 사용하는 resolution이 다르기 때문에 styled의 타입이 아예 다르다. 그렇기에 상속이 불가능하다는 타입 에러가 발생한다.

    👉 해결방법: react 버전을 맞춘다.

    Axios Adapter

    axios에서는 adapter를 이용해 HTTP 요청을 처리한다. adapter는 브라우저와 node 환경에서 서로 다른 구현을 가진다.

    • 브라우저

      • XMLHttpRequest를 사용한 adapter로 HTTP 요청 처리
    • Node.js

      • Node.js의 http 모듈을 사용한 adapter로 HTTP 요청 처리
    • axios adapter가 하는 일 요약

    1. HTTP 요청을 준비한다.
    2. 각 환경(브라우저, Node)에 맞는 방식으로 HTTP 요청을 전송하고 응답을 받는다.
    3. 응답을 axios가 사용할 수 있는 형태로 반환한다.

    adapter를 커스터마이징해서 사용할 수도 있다.

    Copy
    const customAdapter = (config) => {
      const defaultAdapter = axios.defaults.adapter;
      return defaultAdapter(config);
    };
    
    const axiosInstance = axios.create({
      adapter: customAdapter,
    });

    🔫 트러블슈팅 기록

    [TypeError: adapter is not a function] axios를 사용할 때 이 에러가 발생한다면 axios adapter를 만들지 못 했을 수 있다.

    window global이 undefined일 경우 이런 에러가 발생할 수 있다. (ex. Next.js middleware 내부)

    Next.js middleware

    Next.js middleware는 서버 사이드에서 실행된다. window 객체는 웹 브라우저의 전역 객체로 브라우저 환경에서만 존재하기 때문에 서버 사이드에서 실행 되는 middleware는 브라우저 환경이 없기 때문에 window 객체에 접근할 수 없다.

    🤔 Next.js middleware가 서버 사이드에서 실행되면 SSG만 사용할 때는 서버가 없으니 사용을 못 하나? 👉 가능하다. Edge Functions을 통해 Middleware를 엣지 레이어에서 실행할 수 있다. (Vercel은 자동으로 해주고, AWS CF를 사용중이라면 Lambda@Edge를 사용하면 된다.)

    moduleResolution: "bundler"

    TypeScript 5에서는 moduleResolution의 옵션으로 bundler가 추가되었다.

    TypeScript는 자바스크립트의 동작을 모델링한다. 마찬가지로 자바스크립트의 module resolution 동작도 모델링한다.

    4.7에서는 node16nodenext 들이 등장했지만, 제약이 있었다. ESModule방식으로 module을 resolution할 때 항상 파일의 확장자를 붙여줘야 한다는 것이었다. 많은 모던 번들러들이 ECMAScript 모듈과 CommonJS lookup rules을 합쳐서 사용하는 데에 비하면 너무 불편한 방식이다.

    그래서 이런 모듈 번들러들의 동작을 모델링해서 bundler라는 옵션을 추가했다. (원래 이름은 hybrid였는데 최종적으로는 bundler가 되었다.)

    vite, esbuild, swc, webpack, parcel 등을 사용할 때는 bundler라는 옵션을 사용해볼 수도 있을 것 같다!

    다음은 moduleResolution 옵션들을 비교한 표.

    01

    비슷한듯 다른 CloudFront Function과 Lambda@Edge

    • 공통점

      • CloudFront에서 서비스를 확장 하고 사용자 정의 기능을 추가하기 위해 사용
    • 차이점

      • 지원 언어
        • CloudFront Function: JavaScript 런타임 사용, JS만 지원
        • Lambda@Edge: AWS Lambda에서 지원하는 다양한 언어 사용 가능 JS, Python, Java, Go 등등
      • 실행 시간
        • CloudFront Function: 최대 1MB의 페이로드, 1초 이내에 완료되어야 함
        • Lambda@Edge: 최대 50MB의 페이로드, 5초 이내에 완료되어야 함
      • 비용
        • 대체적으로 CloudFront Function이 더 싸다.
    • 사용 사례

      • CloudFront Function: 주로 가벼운 요청 및 응답 처리 작업을 수행 - ex) 헤더 조작, URL 리디렉션, 캐싱 키 정규화 등
      • Lambda@Edge: 더 복잡한 작업 처리 - ex) 원본에 대한 요청 및 응답 처리 사용자 인증, A/B 테스트, 동적 콘텐츠 생성 등

    제로데이 공격

    • 개발자가 인지하지 못한 소프트웨어 취약점을 대상으로 하는 매우 위험한 공격 기법이다.
    • 제로데이 공격이 발생했다는 것은 개발자가 아직 약점을 해결하거나 보안 패치를 만들 시간이 없었다는 말이다. 일단 공격이 발생하면 취약점에 대한 해결책을 개발할 시간이 없다.

    최근에 꽤 주목할 만한 제로데이가 열린 듯 하다 👉 http://m.boannews.com/html/detail.html?idx=115658

    DB indexing

    테이블에 대한 검색의 속도를 높여주는 자료 구조로, 메모리 영역의 일종의 목차를 생성하는 개념이다. 목차를 이용하여 검색 범위를 줄여 속도를 높일 수 있습니다.

    nest.js에서는 @Index 데코레이터로 DB indexing을 해줄 수 있다! 😲

    Ref

    ErrorBoundary reset하기

    어느 페이지에서 에러가 발생하여 ErrorBoundary의 fallback으로 떨어지고 페이지를 이동했는데도(라우터 변경) 여전히 fallback 페이지를 렌더링하고 있는 이유는…

    ErrorBoundary에서 render가 어떻게 생겼는지부터 보자.

    Copy
    render() {
      if (this.state.hasError) {
        return <h1>An error has occurred.</h1>
      }
    
      return this.props.children;
    }

    ErrorBoundary의 state가 정해지면, state가 바뀔 때까지 에러 메시지만 보여줄 것이다. 그러면 히스토리가 바뀌어도 자식 컴포넌트들은 렌더링되지 않는다.

    따라서 히스토리가 변경되면 에러 state를 초기화시켜주는 방법을 써야 하는데, history 객체에 이벤트리스너를 붙여주는 방법이 있지만 react-router v6부터는 사용이 쉽지 않다. 😕

    이때 ErrorBoundarykey를 넣어주면, 각 페이지마다 서로 다른 컴포넌트로 인식해 에러 상태를 새로 리셋해줄 수 있다.

    Copy
    <ErrorBoundary onReset={reset} fallback={fallback} key={pathname}>
      {children}
    </ErrorBoundary>

    Ref https://stackoverflow.com/questions/71762507/reset-error-boundary-on-back-journey-using-useerrorhandler-hook-from-react-error/71884022#71884022

    구글 태그매니저

    웹사이트에 사용되는 태그를 관리하는 툴로, GTM을 통해 추가한 태그를 통해 웹사이트 사용자의 행동을 분석 및 판단할 수 있다. 컨테이너라는 통로를 통해 웹사이트와 GTM이 연결되고, GTM에서 설정한 태그를 통해 웹사이트 행동 관련 데이터를 수집한다.

    초기 세팅 이후에는 개발자의 도움 없이 간단하게 태그를 추가, 삭제할 수 있다.

    → 사이트 및 사용자 분석을 위해 데이터 수집이 필요할 때, 개발자가 아니더라도 손쉽게 스크립트 태그를 생성하고 관리할 수 있게 해주는 툴

    Next.js Automatic Static Optimization (자동 정적 최적화)

    Next.js는 blocking data 요청이 없다면 자동으로 페이지가 정적인지(prerender될 수 있는지)를 결정한다. 페이지에 getServerSidePropsgetInitialProps가 없다면 정적 페이지라고 판단한다.

    이 기능을 통해 Next.js는 서버 렌더링 페이지(SSR)와 정적 생성 페이지(SSG)를 모두 포함하는 하이브리드 앱을 만들 수 있다.

    Response.json()

    Response 인터페이스의 json() 메서드는 Response 스트림을 받은 후 읽어서 완료한다. body text를 JSON으로 파싱한 결과물을 resolve하는 promise를 리턴한다.

    메서드 이름은 json() 이지만, 반환값은 JSON이 아니라 JSON을 input으로 받아서 새로운 자바스크립트 객체로 파싱한 결과물이다.

    axios 말고 오랜만에 fetch 쓰면서 .json()을 사용하다 보니까 괜히 낯설어서… 🫠

    Ref https://developer.mozilla.org/en-US/docs/Web/API/Response/json


    이것저것

    • 프론트엔드 개발자에게 인프라란?
      • 애플리케이션의 보이는 영역을 개발하기 위한 기초적인 시설과 시스템
      • 예) 프로젝트의 구조, 협업하기 위한 브랜치 전략, 배포 파이프라인, 서버 아키텍쳐 등
    • next.js 를 cli로 실행할 때 H 를 통해 호스트 네임을 줄 수 있다.
      Copy
      npx next dev -H 192.168.1.2
    • 부모에 min-height 만 적용되어있으면 자식 속성의 height: 100% CSS 가 먹지 않는다. 부모에 height: 1px 이라도 주면 정상적으로 동작한다.
    • <dialog> tag는 생각보다 많은 기능들을 지원하고 있다. (dialog 요소가 가진 슈퍼 파워 알아보기)

    기타공유

    개발자를 위한 검색엔진 파인드(Phind)

    그냥 구글링과의 차이점이라면, 문맥을 파악하여 원하는 답을 내준다는 것. 그리고 답의 출처를 알려줘서 추가 학습이 가능하게끔 해준다는 것! 잘 사용하면 써볼 만도 하겠다.

    Ref https://yozm.wishket.com/magazine/detail/1944/

    프론트엔드 디자인 패턴 정리

    또 좋은 정리 문서가 나왔다! 오히려 우테코하며 더 전전긍긍했던 프론트엔드 디자인 패턴… 지금은 그런 거 하나도 모른다. (🙃) 디자인 패턴 뿐 아니라 렌더링, 퍼포먼스 관련해서도 정리가 되어있다. 틈틈이 읽어나가볼 아이템이 생겼다!

    벌써 한글로 번역해주시는 분도 계신다… 역시 머릿수는 적지만 부지런한 K-한국인들.

    Ref


    마무리

    1분기가 끝났다. 팀원들 회식하는 기념으로(?!) 나도 호주 와서 첨으로 고오급 스테이크에 와인 잔뜩(2잔..) 내돈내산으로 마시고 취했다… 20만원 나왔지만 행복한 저녁이었다. 🍷🥩

    주말엔 코알라, 캥거루도 만났다! 코알라 생츄어리에 진짜 아무데나 널린 코알라와 캥거루들… 이렇게 아무데나 풀어놔도 되나, 가까이 가면 캥거루가 근육질 다리로 차버리는 거 아닌가 걱정했는데 넘 재밌었다. 캥형들은 우락부락 무서버서, 잠만 자는 졸귀탱 코알라 사진으로 🐨

    02

    Relative Posts:

    4월 1주차 기록

    April 8, 2023

    3월 4주차 기록

    March 24, 2023

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon