ziglog

    Search by

    1월 3주차 기록

    January 20, 2023 • ☕️☕️☕️ 13 min read

    설 앞두고 설렌 맘


    배워가기

    Deno의 특징들

    nodejs에서 개발을 하기위해선 lint, testing tool, package manager, transpiler 등이 필요하다. Deno는 개발 환경 설정에 필요한 작업들 중 일부분을 해결해준다.

    • 본질적으로 패키지 매니저가 없으며, 외부 모듈은 url로 import해서 가지고온다.

    • 로컬 캐시에 패키지를 저장한다. (remote HTTP imports)

    • lint도 서브 커맨드로 자체적으로 실행할 수 있다.

    • Node보다 다양한 빌트인 API를 지원한다. (ex. debounce를 자체적으로 지원)

    • 런타임 version과 표준 라이브러리 version이 독립적이다.

      • 예를 들어 node를 사용할 때는 ver 14에서 16으로 버전업할 때 표준라이브러리 API 호환을 걱정해야 하지만, deno에서는 그럴 필요가 없다. 버전을 명시해서 표준 라이브러리를 가져오기 때문이다.
      • import { copy } from "<[https://deno.land/std@0.172.0/fs/copy.ts](https://deno.land/std@0.172.0/fs/copy.ts)>";
    • 원칙적으로는 ESM만 지원한다.

    • Node와의 호환성

      • Node Compatibility mode를 통해 node 코드를 deno에서 실행할 수도 있다.
      • import express from "npm:express@^4.18";와 같은 방식 npm package를 가져올 수 있다.
      • dnt(deno-node transform)에 의해서 deno 코드를 node에서도 실행할 수 있다.
      • Deno 코드를 esbuild와 esbuild-deno-lader를 이용해서 번들링 할 수도 있다.

    받침에 따라 은/는 이/가 을/를 구분하기

    한글 유니코드 조합은, 다음 형식으로 구성되어 있다.

    Copy
    0xAC00(처음 한글 시작값) + (초성 인덱스 x 21 x 28 ) + (중성 인덱스 x 28) + 종성 인덱스
    • 초성 인덱스 = ((한글 유니코드값 - 0xAC00) / 28) / 21
    • 중성 인덱스 = ((한글 유니코드값 - 0xAC00) / 28) % 21
    • 종성 인덱스 = (한글 유니코드값 - 0xAC00) % 28

    종성 인덱스가 0 이상일 경우는 받침이 있는 경우, 그렇지 않은 경우는 받침이 없는 경우다. 따라서 마지막 글자를 가져온 뒤 종성 인덱스를 가지고 있는지 여부를 판단해서 함수를 만들 수 있다.

    예시로 작성해보자.

    Copy
    const 조사를붙여줘 = (name, firstValue, secondValue) => {
      const lastChar = name.charCodeAt(name.length - 1);
    
      if ((lastChar - 0xac00) % 28) {
        return name + firstValue;
      }
    
      return name + secondValue;
    };

    josa라는 이름이 아주 직관적인 라이브러리도 참고해볼 만 하다.

    npm을 대체할 yarn berry

    npm은 파일시스템(node_modules)을 통해서 의존성을 관리한다. 이때 찾고자 하는 모듈이 없다면 상위 폴더의 node_modules를 참조하기 때문에 불필요한 I/O가 많아질 수 있다.

    또한 node_modules 에 패키지가 잘 설치되었는지 확인하기 쉽지않다. 수 백개의 패키지가 서로 의존하고 있는데, 이를 모두 확인해보려면 node_modules를 느린 I/O작업으로 살펴봐야 한다.

    이를 개선하기 위해 Yarn berry에서는 pnp 모드를 지원한다.

    해당 모드에서는 node_modules 를 아예 사용하지 않으며, .pnp.cjs 파일을 사용한다.

    이 파일을 통해 라이브러리가 실제 어디에 존재하는지 경로가 값으로 써져 있어 어떤 패키지가 무엇을 의존하고 있는지 알 수 있으며,

    결과적으로 node가 이미 경로를 알기 때문에 직접 node_modules를 탐색할 필요가 없다. 그러므로 node_modules 파일 트리 형태를 만들지 않아도 된다.

    또한 모든 패키지는 패키지 버젼별로 zip파일로 만들어져 .yarn/cache/로 저장된다. 패키지 버전마다 하나의 zip파일을 가지고 있어서 중복 설치되지 않으며, zip파일로 저장해서 용량도 아낄 수 있다.

    본래 node_modules 는 큰 용량 때문에 git 추적에서 제외하지만 yarn berry에서는 의존성 파일들(.yarn/cache)도 git 추적을 하기도 한다. 이를 통해 zero-install을 구현할 수 있다. (zip 파일이 작은 용량을 가지기 때문) 그 결과, branch를 바꿨다고 해서 yarn install을 하지 않아도 되며, ci에서 의존성 설치 시간을 줄일 수 있다.

    corepack

    ‘package manager manger’, 말 그대로 패키지 매니저를 관리하는 도구다. (volta, nvm의 패키지 매니저 버전)

    LTSv16가 아니라면 npm i -g corepack 으로 다운 받고 corepack enable을 실행해야 활성화된다.

    package.json의 packageManager 필드에서 패키지매니저와 패키지매니저 버젼을 명시해서 강제할 수 있다.

    예로, 폴더 A에서는 pnpm@6, 폴더 B에서는 pnpm@7을 강제하는 상황을 가정해보자. 폴더 A에 접속하면 pnpm은 버젼이 자동으로 6으로 변경되고, 폴더 B에서는 7로 변경된다.

    corepack prepare pnpm@6.24.2 --activate 을 통해서 유동적으로 버젼을 변경할 수도 있다.

    String.prototype.replace의 두 번째 인자

    String.prototype.replace의 두 번째 인자에는 함수가 올 수도 있다.

    그리고 두번째 인자의 타입이 string이라면, 특수한 값이 허용된다.

    • $$ : $ 기호를 삽입
    • $& : 매치된 문자열을 삽입
    • `$“ : 매치된 문자열 앞쪽의 문자열 삽입
    • $\’ : 매치된 문자열 이후의 문자열 삽입
    Copy
    const sentence = "안녕하세요 저는 지그입니다.";
    
    sentence.replace("지그", "$$");
    // 안녕하세요 저는 $입니다.
    sentence.replace("지그", "$&지그");
    // 안녕하세요 저는 지그지그입니다.
    sentence.replace("지그", "$`");
    // 안녕하세요 저는 안녕하세요 저는 입니다.
    sentence.replace("지그", "$'");
    // 안녕하세요 저는 입니다.입니다.

    svg fill 알아보기

    SVG의 fill 속성은 css로 override가 가능하다.

    다음과 같은 svg 요소가 있을 때,

    Copy
    <svg>
      <path class="icon" fill="#fff" ... />
      {/* ... */}
    </svg>

    다음 CSS로 요소의 fill 속성을 override 할 수 있다.

    Copy
    .icon {
      fill: yellow;
    }

    하지만 그 하위 태그의 fill 속성까지는 override 하지 못한다. 또 fill 속성이 아니라 inline-css로 적용된 fill은 우선순위가 더 높으므로 override 되지 않는다.

    Storybook의 Template.bind()

    Storybook에서 Story를 만들 때 bind를 쓰는 이유는 Template 함수를 복제해서 사용하기 위해서다. Template을 복제하면 각 복제본의 속성을 독립적으로 관리할 수 있다 (또한 속성에 args를 추가해 여러 버전을 만들 수 있다).

    Storybook이 이런 추가적인 조치를 하는 것은 args를 기반으로 live-edit 기능이 동작하기 때문이다.

    cf) Template.bind({})에서 인자 {}는 넘겨주지 않아도 된다 (하지만 타입스크립트는 싫어한다.)

    시각적 회귀 테스트

    시각적 회귀 테스트는 e2e와는 다르다. e2e는 컴포넌트 존재 유무를 판단하지만 시각적 회귀 테스트는 해당 레이아웃이 제대로 보여지는지 혹은 깨졌는지를 파악할 수 있다.

    최근에 캡처한 스크린샷과 현재 스크린샷을 비교해 리포트를 작성하는 방식으로 테스트를 한다. 시각적 회귀 테스트 서비스로는 cypress, LOKI 가 있다.

    회귀 테스트를 이용하지 않는다면 디자인시스템 라이브러리의 버전이 달라질 때마다 계속 확인해줘야 한다.

    selection API

    에디터에서 많이 사용되는 WEB API다. 예를 들어, 에디터에서 “안녕하세요”에서 “안녕”을 마우스로 드래그하고 cmd+b 하면 “안녕”으로 변경해주는 API다.

    document.getSelection()을 통해 현재 셀렉션을 알 수 있다. selection은 anchorNode(시작)와 focusNode(끝)로 나눠진다.

    cf) firefox는 멀티 셀렉션이 된다.

    form control에서는 또 다른 형태로 selection API를 제공하며, domElement 자체에서도 메소드를 사용할 수 있다.

    • input.selectionStart – input안에 활성화되어있는 selection start 위치
    • input.selectionEnd – input안에 활성화되어있는 selection end위치
    • input.selectionStart === input.selectionEnd - 그곳이 커서의 위치이다.

    input에 text를 추가하는 예시를 들어보자.

    Copy
    button.onclick = () => {
      // setRangeText: election에 포함되어있는 text를 replace하는 메소드
      input.setRangeText("HELLO", input.selectionStart, input.selectionEnd, "end");
      input.focus();
    };

    BigInt

    • BigInt 값은 TypeScript에서 bigint 타입으로 추론된다.

    • 숫자 뒤에 n 을 붙여 Bigint 리터럴을 사용할 수 있다.

      Copy
      typeof 1n === "bigint"; // true
      typeof BigInt("1") === "bigint"; // true
    • BigInt는 BigInt끼리의 사칙연산이 가능하다. (>>>를 제외한 비트연산자나 제곱연산자도 사용이 가능하다)

      • 단, + 단항연산자는 지원하지 않는다.

    sed 리눅스 쉘 명령어

    sed는 stream editor의 준말로, input stream (file이나 pipeline을 통한 input)에서 문자 transformation을 수행한다.

    input 파일을 한줄한줄 읽고 명령을 따라서 해당하는 줄(line)을 변경한다. 그리고 그 결과를 standard output으로 반환해준다.

    • 사용하는 상황
      • search & replace
      • text pattern matching
      • simple data extraction
    Copy
    # file.txt에 있는 old를 new로 변경
    # s: search와 replace를 하겠다는 명령어
    sed 's/old/new/g' file.txt

    File vs FileList

    • File 객체

      • Blob의 인터페이스를 확장해서 사용하는 객체이다. (Blob: Binary large object)
        • 따라서 Blob을 쓸 수 있다면 File도 쓸 수 있다.
          • 예) FileReader, URL.createObjectURL()
      • lastModified, name, size, type 등의 프로퍼티를 갖는다.
    • FileList 객체

      • 주로 input type=‘files’나 드래그앤드롭 DataTransfer 객체에서 가져온다.
      • item() 메서드로 인덱스를 넘기면, 위의 File 객체를 얻을 수 있다.

    HTMLCollection.item

    [HTMLCollection](https://developer.mozilla.org/ko/docs/Web/API/HTMLCollection) 의 메소드 item() 은 컬렉션 안의 특정 인덱스에 위치한 노드를 반환한다.

    Copy
    var c = document.images; // HTMLCollection입니다
    var img0 = c.item(0); // 이렇게 item() 메소드를 이용할 수 있지만
    var img1 = c[1]; // 이렇게 표기하는게 쉽고 더 보편적입니다

    Ref https://developer.mozilla.org/ko/docs/Web/API/HTMLCollection/item

    WAI-ARIA role=”grid”

    role="grid"는 시각적으로는 표 형태이지만, 방향키 등을 통해 탐색하거나 인터랙션이 필요할 때 사용할 수 있는 role이다.

    전체 컨테이너 역할을 하는 <table> 요소에 role="grid"를 삽입하고 각각의 <th>role="columnheader", <tr>role="row", <td>role="gridcell"을 삽입한다.

    주로 날짜를 선택하는 DatePicker 등에 사용한다.

    Ref https://aoa.gitbook.io/skymimo/aoa-2018/2018-aria/datepicker

    Next.js 프로젝트 세부 경로에서 reload 시 403 에러 나는 이슈

    이때는 trailingSlash를 붙여줘야 한다.

    기본적으로 브라우저에서는 URL의 주소 끝에 슬래시가 붙어있으면 디렉토리라는 의미고, 없다면 여기가 끝, 즉 파일이라는 것을 의미한다.

    Next.js에서는 기본으로 url 끝에 / 가 있다면, 제거해서 페이지를 이동한다. 이를 바꿔주기 위해 next.config.js에서 trailingSlash: true 를 명시해줘야 한다.

    Ref https://nextjs.org/docs/api-reference/next.config.js/trailing-slash

    브라우저 캐시

    브라우저 캐시에는 두 종류가 있다.

    • memory cache
      • RAM에 저장한다. (더 빠르다)
      • 브라우저를 종료하면 휘발된다.
    • disk cache
      • 하드에 저장한다.
      • 브라우저를 종료해도 유지된다.

    이것저것

    • SKU - stock keeping unit의 약자로, 재고관리를 위한 최소한의 단위다. 재고관리 시 쓰이는 재고 관리 코드로 주로 사용되며, 각각의 제품을 유닛화해서 상품코드로 지정해서 재고관리가 용이하게 함
    • semantic-release 를 사용해 자동 버저닝 할 때, 기본으로는 v1.0.0 부터 버전이 시작한다. 그러나 main 브랜치 시작에 v0.0.0 버전으로 시작하게 되면 해당 버저닝을 따라간다. (ex. v0.1.0-beta.1)
    • 이미지를 URL 로 바꿀 때, window.URL.createObjectURL(file) 을 사용할 수 있다. url을 모두 사용하고 나면 window.URL.revokeObjectURL 메소드로 없애줘야 한다. (메모리 관리를 위해서) rollup 버전 2까지는 빌드 결과물이 어느 모듈 시스템(esm, cjs)에서 사용되더라도 동작하도록 보조하는 헬퍼를 지원했는데, 버전 3부터는 헬퍼를 디폴트로 제공하지 않는다. 이 때문에 모듈 시스템 관리를 제대로 하지 않으면 에러가 발생할 수도 있다 (rollup 3를 사용하는 vite 4도 마찬가지)
    • pnpm add vs pnpm install
      • pnpm add: 프로젝트에 새로운 종속성을 추가할 때 사용
      • pnpm install: lockfile이 존재하는 프로젝트에서 lockfile에 존재하는 종속성을 설치할 때 사용
    • aws의 sync 명령어는 없는 데이터에 대해서는 복사를 수행하나, 같은 데이터는 복사하지 않는다. 이때 ‘같은 데이터’의 판단 기준은 수정날짜와 파일 사이즈로 판단한다. (cf. -delete 옵션으로 원본에서 삭제된 데이터를 타겟에서도 삭제할 수 있다.)
    • React 18에서는 React.FC 에 children이 없어서, PropsWithChildren<Props> 으로 prop의 타입을 지정하여 children 이 있는 prop을 사용할 수 있다.
    • Vite에서 Storybook을 쓰기 위해서는 tsconfig-path 설정을 추가해주어야 한다. (Ref )
    • Vite 관련 플러그인들을 모아놓는 레포 (본인이 플러그인을 만들어 직접 PR할 수도 있다.)

    기타공유

    gRPC란?

    gRPC는 Google에서 개발한 RPC(Remote Procedure Call) 시스템이다. 전송을 위해 TCP/IP 프로토콜과 HTTP 2.0 프로토콜을 사용하고 IDL(Interface Definition language)로 protocol buffer를 사용한다.

    … 🤷‍♀️?

    배경지식부터 짚고 가자.

    • RPC(원격 프로시저 호출) - 한 프로그램이 네트워크의 세부 정보를 이해하지 않고도 네트워크 안의 다른 컴퓨터에 있는 프로그램에서 서비스를 요청하는 프로토콜로, client-server 모델을 사용한다.
    • HTTP(Hypertext Transfer Protocol) - 웹에서 쓰이는 통신 프로토콜로, TCP/IP 프로토콜 위의 레이어(Application layer)에서 동작한다. HTTP 프로토콜은 stateless 프로토콜로, 각각의 데이터 요청이 서로 독립적으로 관리된다. HTTP는 기본적으로 서버-클라이언트 구조를 따른다.
      • HTTP 1.1 - 1999년 출시 이후 지금까지 웹에서 가장 많이 사용되고있는 프로토콜로, 기본적으로 연결당 하나의 Request과 Response를 처리하기 때문에 동시전송 문제와 다수의 리소스를 처리하기에 속도 및 성능 이슈를 가지고 있습니다.
      • HTTP2.0 - HTTP1.1의 프로토콜을 계승하면서도 성능 향상에 초점을 맞추어, Multiplexed Streams, Stream Prioritization, Header Compression 등의 기능을 제공한다.
    • IDL(Interface Definition Language) - 정보를 저장하는 규칙으로, 대표적인 IDL로는 다음 3가지가 있다.
      • XML(eXtensible Markup Language) - 어떠한 데이터를 설명하기 위해 이름을 임의로 지은 태그로 데이터를 감싸며, 태그로 사용자가 직접 데이터 구조를 정의 할 수 있다.
      • JSON(JavaScript Object Notation) - javascript의 부상으로 많이 쓰이고 있는 데이터 구조다. XML이 가진 읽기 불편하고 복잡하고 느린 속도 문제를 해결했으며, 특히나 key-value로 정의된 구조 자체가 굉장히 사람에게 직관적이다.
      • Protocol buffers(proto) - 구조화(structured)된 데이터를 직렬화(serialization)하기 위한 프로토콜로 XML보다 작고 빠르고 간단하다.

    그래서 gRPC가 뭐냐면…

    gRPC는 구글에서 만든 RPC 플랫폼이며 protocol buffer와 RPC를 사용한다. 최신 버전의 IDL로 proto3를 사용한다. Java, C ++, Python, Java Lite, Ruby, JavaScript, Objective-C 및 C#에서 사용 가능하다.

    SSL/TLS를 사용하여 서버를 인증하고 클라이언트와 서버간에 교환되는 모든 데이터를 암호화한다. HTTP 2.0을 사용하여 성능이 뛰어나고 확장 가능한 API를 지원한다.

    gRPC에서 클라이언트 응용 프로그램을 서버에서 함수를 바로 호출 할 수 있어 분산 MSA(Micro Service Architecture)를 쉽게 구현 할 수 있다. 서버 측에서는 서버 인터페이스를 구현하고 gRPC 서버를 실행하여 클라이언트 호출을 처리한다.

    RPC 플랫폼 + 배경지식에 나온 모든 좋은 기능들을 때려박은 시스템이다!

    Ref https://chacha95.github.io/2020-06-15-gRPC1/

    You don’t need Next.js

    SEO가 필요한 사이트가 아니라면, Next.js가 필요없다는 이야기다.

    • Next.js의 설계는 굉장히 폐쇄적이다.
    • 하나의 큰 앱을 (같은 도메인을 유지한 채) 작은 단위의 앱들로 쪼개기 어렵다.
    • Next 기반의 앱을 패키징하기가 어렵다.
    • 서버-클라이언트-빌드 단계가 강결합되어 있다.
    • 다른 소프트웨어 툴들과 결합하기 어렵다.
    • 풀스택도 아니고, 프론트엔드 프레임워크도 아니고?
    • Next 앱은 12-factor 방법론을 따르기가 어렵다.
    • Hydration은 투머치하다.
    • SSR을 사용하려면 결국 코드를 끼워맞춰야 한다.

    …등등의 수도 없는 악설을 퍼붓고 있다 🤷‍♀️

    그러나 Next.js의 SSG나 ISR을 이용한 렌더링은 꽤나 훌륭한 선택지가 될 수 있으므로, SEO나 OG가 중요한 웹사이트들에서는 사용하는 것을 추천한다고 한다~

    Ref https://blog.webf.zone/you-dont-need-next-js-and-ssr-7c6bd27e78d8


    마무리

    민족 대명절 설이다. 🐰 계묘년 새해… 올해는 왠지 설이 너무 빨라서 아쉬워버리기도 하지만 (아직 일도 제대로 안 해서 쉬는 기분이 안 날 줄 알았다.) 막상 또 쉬니까 좋다. 설 연휴 안 끝났으면… 그치만 평상시에 일도 공부도 열심히 해야 또 쉬는 맛이 나는 거겠지 😎

    설 연휴 직전엔 오이도 드라이브 갔다왔다. 찬바람 미쳤다. 조개구이는 아주 맛있게 먹고왔다. 배터져부러


    Relative Posts:

    1월 4주차 기록

    January 28, 2023

    1월 2주차 기록

    January 14, 2023

    zigsong

    지그의 개발 블로그

    RotateLinkImg-iconRotateLinkImg-iconRotateLinkImg-icon