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

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

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


#301

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

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


#300
[data-scope='slider'][data-part='thumb']

[data-scope='slider'][data-part='track']

[data-scope='slider'][data-part='control']

Ark UI의 각 컴포넌트 파트는 data-scopedata-part 속성으로 지정됩니다. data-scope 속성은 컴포넌트를 식별하고, data-part 속성은 컴포넌트의 개별 부분을 지정합니다.

ark-ui에서 사용하는 방식인데 적용해볼만한 컨셉이라고 생각한다.


#297

Bottom Sheet 라이브러리 비교

react-modal-sheet 추천:

  • 활발한 유지보수 (v5 최근 릴리즈)
  • Framer Motion 기반, Compound component 패턴
  • avoidKeyboard, disableDismiss 등 유용한 옵션
import { Sheet } from 'react-modal-sheet'

<Sheet isOpen={isOpen} onClose={() => setOpen(false)}>
  <Sheet.Container>
    <Sheet.Header />
    <Sheet.Content>콘텐츠</Sheet.Content>
  </Sheet.Container>
  <Sheet.Backdrop />
</Sheet>

WARNING

react-spring-bottom-sheet는 3년간 업데이트 없음. 신규 프로젝트에선 피할 것.


#289
class CustomError extends Error {
  name = 'CustomError'

  constructor(message?: string) {
    super(message)

    Object.setPrototypeOf(this, CustomError.prototype)
  }
}

try {
  throw new CustomError('This is a custom error message.')
} catch (error) {
  if (error instanceof CustomError) {
    console.log('CustomError occurred:', error.message)
    console.log('Error name:', error.name)
  } else {
    console.log('An error occurred:', error)
  }
}
#287
enum LogLevel {
  DEBUG = 'debug',
  INFO = 'info',
  WARN = 'warn',
  ERROR = 'error',
}

type Message = string

class Logger {
  private level: LogLevel

  constructor(level: LogLevel = LogLevel.DEBUG) {
    this.level = level
  }

  private log(level: LogLevel, message: Message) {
    if (this.level === LogLevel.DEBUG || level !== LogLevel.DEBUG) {
      const label = level.toUpperCase()

      console.log(`[${label}] ${message}`)
    }
  }

  /**
   * - 개발 혹은 테스트 단계
   * - 운영 환경에서는 남기고 싶지 않은 로그 메세지
   */
  public debug(message: Message) {
    this.log(LogLevel.DEBUG, message)
  }

  /**
   * - 정상 작동에 대한 정보
   * - 시스템을 파악하는데 유익한 정보
   */
  public info(message: Message) {
    this.log(LogLevel.INFO, message)
  }

  /**
   * - 잠재적으로 문제가 될 수 있는 상황
   * - 언제든 발생할 수 있는 일반적인 문제 상황
   * - 사용자에게 노출되는 메세지에 상세한 가이드가 필요
   */
  public warn(message: Message) {
    this.log(LogLevel.WARN, message)
  }

  /**
   * - 심각한 오류나 예외 상황
   * - 즉시 조치가 필요할때
   */
  public error(message: Message) {
    this.log(LogLevel.ERROR, message)
  }
}

1. 효율적으로 로그 모니터링하기 - 로그 레벨 구분하기

#281
import z from 'zod'

const envSchema = z.object({
  REACT_APP_FEATURE_VAC_ASK: z.string(),
  REACT_APP_FEATURE_RECORDS: z.string(),
  NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
})

const windowSchema = z.object({
   SOMETHING_COOL: z.string()
})

export const ENV = envSchema.parse(process.env)
export const WINDOW = windowSchema.parse(window)

#280
type Props = {
  popover: 'auto' | 'manual'
  popovertarget: string
  popovertargetaction: 'hide' | 'show' | 'toggle'
}

type State = {
  hasBackdrop: boolean
  isPopoverOpen: boolean
}

type Methods = {
  hidePopover: () => void
  showPopover: () => void
  togglePopover: () => void
}

type Events = {
  beforetoggle: () => void
  toggle: () => void
}

#279
import { match } from 'ts-pattern'

type Format = 'webp' | 'jpg'

type Params = {
  id: string
  quality: keyof typeof QUALITY_MAP
  format: Format
}

const QUALITY_MAP = {
  player_background: '0',
  video_frames_start: '1',
  video_frames_middle: '2',
  video_frames_end: '3',
  lowest_quality: 'default',
  medium_quality: 'mqdefault',
  high_quality: 'hqdefault',
  standard_quality: 'sddefault',
  unscaled_resolution: 'maxresdefault',
}

const BASE_URL = 'https://i.ytimg.com'

const VI = (format: Format) =>
  match(format)
    .with('jpg', () => 'vi')
    .otherwise(() => ['vi', format].join('_'))

export function getThumbnail({ id, quality, format }: Params) {
  return [BASE_URL, VI(format), id, QUALITY_MAP[quality]]
    .join('/')
    .concat(`.${format}`)
}

#275

한 마을에 개발자들이 모여 프로젝트를 진행하고 있었습니다. 그 중 한 명의 개발자인 에릭은 팀에서 핵심적인 역할을 맡고 있었고, 그의 전문적인 지식과 능력은 프로젝트의 성공에 큰 영향을 미칠 정도였습니다. 그러나 에릭은 여행을 갈 계획을 세우고 모두에게 알리지 않았습니다.

어느 날, 프로젝트 팀은 예기치 않은 문제에 직면했습니다. 시스템의 일부가 오작동을 일으켜 복구해야 할 상황이었는데, 당연히 에릭이 이를 해결할 수 있었습니다. 그러나 에릭은 이미 여행을 떠나버렸고, 팀은 그를 찾을 수 없었습니다. 에릭이 없는 상태에서는 아무도 그의 전문적인 지식을 대체할 수 없었기 때문에 팀은 큰 혼란에 빠지게 되었습니다.

프로젝트 팀은 에릭의 결석으로 인한 위기를 극복하기 위해 긴급 회의를 열었습니다. 모두가 버스 팩터에 대해 이야기하며, 이 사태로부터 배운 교훈에 대해 논의했습니다. 팀은 이제부터 지식을 공유하고 업무를 분산시키기로 결정했습니다. 각 개발자는 다른 팀원의 역할을 이해하고, 중요한 결정과 지식을 모두가 공유하도록 노력하기로 했습니다.

이제 마을의 개발자들은 에릭 없이도 프로젝트를 진행할 수 있었습니다. 에릭은 멋진 여행을 즐겼지만, 팀은 그의 결석으로 인한 위기를 극복하고 지속 가능한 개발 환경을 조성하는 데 성공했습니다. 그들은 버스 팩터를 기억하며, 이 작은 이야기는 그들에게 프로젝트 관리의 중요성을 상기시켜주었습니다.


https://www.google.com/search?q=%EB%B2%84%EC%8A%A4%ED%8C%A9%ED%84%B0

#274
26 중 13페이지