최근에 Enzyme을 제거하고 React Testing Library로 교체하는 작업을 진행했습니다. JSX 영역은 별 문제 없이 진행되었으나, state나 props를 다루는 구현 부분에서 약간의 애매함이 있었습니다. 개인적으로는 기존 접근 방식이 나쁘지 않았다고 생각했기 때문에, 새로운 접근 방식으로 전환하는 데 주저하게 되었습니다.

결론적으로, state와 props의 JSON 결과물을 렌더링하고 getByTestId를 사용하여 이를 참조하는 방식으로 테스트를 진행하기로 했습니다. 다음은 그 예시입니다:

render() {
  return <>
    {process.env.NODE_ENV === 'test' && (
      <pre data-testid="ThumbnailDebug">
        {JSON.stringify({
          props: this.props,
          state: this.state,
        })}
      </pre>
    )}
  </>
}

이 방법을 통해 Enzyme을 제거한다는 목표를 달성했기 때문에, 어느 정도는 해결된 것처럼 보이며, 추후 더 나은 테스트 코드를 작성하기 위한 고민을 할 수 있을 것 같습니다.

#309

전통적인 비즈니스 모델이나 판매 전략을 통해 성장한 기업들이 기술적인 면에서 열등감을 느끼며, 표면적인 변화에 집착하고 기술 도입에 실패하는 등 여러 문제를 겪는다. 이러한 기업들은 기술 전환 과정에서 자주 자원 낭비와 재정 악화를 경험한다. 불필요하거나 과도한 기술 도입 시도는 상당한 자원 낭비를 초래하며, 이는 기업의 재정 상태를 악화시키고 중요한 프로젝트나 핵심 사업에 필요한 자원이 부족해지는 결과를 초래한다.

내부적으로도 갈등과 사기 저하가 발생한다. 기술 전환 과정에서 역할과 책임이 명확히 정의되지 않으면, 직원들 사이에 갈등이 발생하고, 새로운 기술 도입에 대한 교육 부족이나 명확한 비전 부재는 직원들의 사기를 저하시키고 이직률을 높이는 요인이 된다. 이러한 혼란은 결국 고객 이탈을 가속화한다. 기술 도입이 미흡하거나 중단되는 경우, 고객들은 기업의 신뢰성을 의심하게 되고, 특히 디지털 서비스가 부실하면 고객 경험이 악화되어 경쟁사로 이탈하게 된다. 이는 매출 감소로 직결되고 기업의 시장 점유율을 급격히 떨어뜨린다.

경영진의 신뢰 손상도 큰 문제가 된다. 기술 전환의 실패는 경영진의 판단력에 대한 의문을 불러일으키며, 이는 주주들과 투자자들의 신뢰를 흔들리게 하고, 주가 하락과 함께 기업의 시장 가치를 떨어뜨린다. 장기적인 재무 안정성에도 부정적인 영향을 미친다. 또한, 잘못된 기술 도입으로 인해 기업이 기술에 지나치게 의존하게 되면 본래의 영업 중심 모델이 약화되고, 기술적 문제가 발생할 때마다 더 큰 리스크에 노출된다.

이 과정에서 혁신 저해가 일어난다. 무분별한 기술 도입이 오히려 조직의 혁신 문화를 저해하고, 기술 도입이 실패로 끝날 경우 조직 내에서는 새로운 시도를 꺼리게 되어 전체적인 혁신 역량이 저하된다. 결과적으로 기업은 변화하는 시장 환경에 적응하지 못하게 된다. 이러한 실패와 고객 신뢰 상실은 장기적으로 회복 불가능한 손실을 초래한다. 브랜드 이미지가 심각하게 손상되고, 시장에서의 입지가 약화되어 재도약이 어려워진다.

이와 같은 부정적인 결과는 영업 중심의 기업들이 기술적 역량을 무리하게 키우려 할 때 나타나는 전형적인 문제들이다. 이러한 함정에 빠지지 않기 위해서는, 기술 도입에 있어 신중하고 체계적인 접근이 필요하며, 기존의 강점을 유지하면서 기술을 보완하는 전략을 세워야 한다. 기술적 열등감을 극복하려는 시도가 오히려 기업의 몰락을 초래할 수 있음을 인지하고, 보다 현실적이고 균형 잡힌 접근을 해야 한다.

#308
if (!data) {
  throw fetch()
}
  1. 컴포넌트가 렌더링될 때, 비동기 작업(예: 데이터 패칭)이 시작됩니다. 이 작업은 일반적으로 promise를 반환합니다.
  2. 비동기 작업이 완료되지 않은 경우, 컴포넌트는 promise를 던집니다. 이는 JavaScript에서 예외를 던지는 것과 유사합니다. Suspense는 promise가 던져질 때 이를 캐치하고 fallback UI를 표시하는 역할을 합니다.
  3. React는 컴포넌트가 promise를 던졌을 때 이를 감지하고, Suspense 컴포넌트에서 이를 “캐치”합니다. Suspense는 이 promise가 해결될 때까지 대체 UI (fallback)를 렌더링합니다. Concurrent Mode에서는 React가 이 promise를 추적하고, 비동기 작업이 완료될 때까지 렌더링을 중단합니다.
  4. Promise가 해결되면(즉, 비동기 작업이 완료되면) React는 컴포넌트를 다시 렌더링합니다. Suspense는 현재 데이터 패칭 라이브러리(예: React Query, SWR)와 함께 사용되어 비동기 작업의 상태를 쉽게 관리할 수 있도록 도와줍니다.

#307

Next.js의 router-loader.ts #prefetchViaDom()

function prefetchViaDom(
  href: string,
  as: string,
  link?: HTMLLinkElement
): Promise<any> {
  return new Promise<void>((resolve, reject) => {
    const selector = `
      link[rel="prefetch"][href^="${href}"],
      link[rel="preload"][href^="${href}"],
      script[src^="${href}"]`
    if (document.querySelector(selector)) {
      return resolve()
    }

    link = document.createElement('link')

    // The order of property assignment here is intentional:
    if (as) link!.as = as
    link!.rel = `prefetch`
    link!.crossOrigin = process.env.__NEXT_CROSS_ORIGIN!
    link!.onload = resolve as any
    link!.onerror = () =>
      reject(markAssetError(new Error(`Failed to prefetch: ${href}`)))

    // `href` should always be last:
    link!.href = href

    document.head.appendChild(link)
  })
}

이 함수는 미리 가져오는(prefetch) 역할을 하며 주요 특징은 다음과 같다.

  • 이미 prefetch 또는 preload된 리소스인지 확인.
  • 새로운 요소를 생성하여 리소스를 prefetch.
  • 로드 성공 또는 실패 시 적절한 처리.

Webpack의 Mini CSS Extract Plugin에서 CSS 청크 로드 실패 시 에러 처리 코드를 볼 수 있다.

 Template.indent([
  "var errorType = event && event.type;",
  "var realHref = event && event.target && event.target.href || fullhref;",
  'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + errorType + ": " + realHref + ")");',
  'err.name = "ChunkLoadError";',
  // TODO remove `code` in the future major release to align with webpack
  'err.code = "CSS_CHUNK_LOAD_FAILED";',
  "err.type = errorType;",
  "err.request = realHref;",
  "if (linkTag.parentNode) linkTag.parentNode.removeChild(linkTag)",
  "reject(err);",
]),

이 코드는 CSS 청크 로드 실패 시 발생하는 에러를 처리하며 주요 특징은 다음과 같다.

  1. 에러 타입과 실제 URL을 파악.
  2. 상세한 에러 메시지를 생성.
  3. 에러 객체에 추가 정보(name, code, type, request)를 설정.
  4. 실패한 <link> 태그를 DOM에서 제거.
  5. Promisereject하여 에러를 전파.

이 플러그인은 CSS를 별도의 파일로 추출하는 데 사용되며, 위 코드는 그 과정에서 발생할 수 있는 오류를 처리하는 중요한 부분.

#306

Google Sheets API를 활용하기 위해서는 Google Cloud Platform(GCP)에서 필요한 설정을 하고, google-spreadsheet 라이브러리를 통해 스프레드시트를 조작할 수 있습니다. 다음은 이를 위한 단계별 가이드입니다.

  1. 서비스 계정 설정
  2. Google Cloud 프로젝트 생성
  3. Google Sheets API 활성화
  4. API 자격 증명 생성
  5. 서비스 계정 생성
  6. 서비스 계정 키 생성
  7. 환경 변수 설정

#305

chrono는 다양한 형식의 날짜/시간을 처리하고 주어진 텍스트에서 정보를 추출할 수 있도록 설계된 자연어 날짜 파서.

  • “Today”, “Tomorrow”, “Yesterday”, “Last Friday” 등의 상대적 날짜 처리
  • “17 August 2013 - 19 August 2013”와 같은 날짜 범위 처리
  • “This Friday from 13:00 - 16.00”와 같은 시간 포함 날짜 처리
  • “5 days ago”, “2 weeks from now”와 같은 상대적 시간 표현 처리
  • “Sat Aug 17 2013 18:40:39 GMT+0900 (JST)“와 같은 표준 날짜 형식 처리
  • “2014-11-30T08:15:30-05:30”와 같은 ISO 8601 형식 처리

parse()123

parse(text: string, referenceDate?: ParsingReference | Date, option?: ParsingOption): ParsedResult[] {
  // 1. 파싱 컨텍스트 생성
  // 2. 모든 파서를 실행하고 결과 수집
  // 3. 결과를 인덱스 기준으로 정렬
  // 4. 모든 리파이너를 적용하여 결과 개선
  // 5. 최종 결과 반환
}

inclusive-dates는 자연어 입력을 지원하는 사용자 친화적이고 완전히 접근 가능한 데이트피커. 내부적으로 chrono를 사용하여 자연어 날짜 입력을 처리. 이는 두 라이브러리의 장점을 결합한 좋은 예시.

const parsedDate = await chronoParseDate(text, {
  locale: this.locale.slice(0, 2),
  minDate: this.minDate,
  maxDate: this.minDate,
  referenceDate: removeTimezoneOffset(new Date(this.referenceDate)),
  ...chronoOptions,
})
  1. chrono의 강력한 자연어 날짜 파싱 능력을 활용.
  2. inclusive-dates는 이를 사용자 친화적이고 접근성 높은 UI 컴포넌트로 구현.

이러한 조합을 통해, 개발자들은 사용자에게 직관적이고 유연한 날짜 입력 방식을 제공하면서도 접근성과 사용성을 높일 수 있음.


Footnotes

  1. executeParser

  2. sort

  3. refine

#304

grid view(또는 datagrid)는 데이터의 표 형식 보기를 제공하는 그래픽 제어 요소입니다.

일반적으로 다음 중 일부 또는 전부를 지원합니다.

  • 열 머리글을 클릭하여 그리드의 정렬 순서 변경
  • 열 머리글을 끌어서 크기 및 순서 변경
  • 보기 데이터의 제자리 편집
  • 행과 열 구분 기호 및 행 배경색 번갈아 지정하기

  • Cornerstone.js HTML5 canvas를 지원하는 웹 브라우저에서 가벼운 의료 이미지 표시에 사용되는 JavaScript 라이브러리
  • OpenSeadragon 데스크톱 및 모바일에서 사용 가능한 고해상도 줌 가능한 이미지를 위한 순수 JavaScript 뷰어
  • dicomParser DICOM 파일을 처리하여 의료 이미지 데이터를 JavaScript 객체로 변환하는 라이브러리
  • AMI Medical Imaging (AMI) 웹에서 의료 영상을 효과적으로 표시하고 주석을 추가하는 데 사용되는 JavaScript 라이브러리
  • OHIF Medical Imaging Viewer
  • itk-wasm 의료 영상 처리를 위한 JavaScript 라이브러리
  • Brainchop

예전에 관련 회사 기술 블로그 보다가 생각나서 찾아본 라이브러리 리스트. 대용량, 의학용 이미지 포멧을 다루기 위한 도구들.

Astro를 사용한 프로젝트에서 빌드를 하는데 JavaScript heap out of memory 에러가 발생했다. 쉽게 해결하자면 NODE_OPTIONS=--max_old_space_size(in megabytes) 설정해서 우회할수는 있겠지만 정리가 필요해서 메모를 남겨본다. 일단 원인은 파일사이즈가 크다는 점, 그리고 카테고리(국가)별 데이터가 많다는 점인데 개선할만한 부분은 두가지 정도인 듯.

  • 가능한 전처리해서 데이터를 다시 생성해서 참조
  • Astro.glob을 사용해서 조건부로 데이터를 가져오기

예상치 못한 에러였는데 역시 트레이드오프는 존재하기 마련이다.


#301

로컬에서만 실행 해야하는 프로젝트가 있길래 아무래도 사전설정 같은 귀찮은 문제가 있으니 pkg를 사용하면 좋을 것 같아서 들어가봤는데 개발이 중단 되었다.

노드 21버젼에서 해당 기능이 지원되는데 재미있는 시도들이 많이 나왔으면 좋겠다.


#300
15 중 2페이지