The Chrome DevTools Protocol (CDP) is a JSON-based protocol that connects debug and automation targets (such as browsing contexts and workers) with trusted debug and automation clients. It allows tools to instrument, inspect, debug, and profile Chromium, Chrome, and other Blink-based browsers.
- ChromeDevTools/devtools-frontend1
- cyrus-and/chrome-remote-interface2
- paulirish/awesome-chrome-devtools3
- Tencent/vConsole4
- liriliri/chii5
- devtools-frontend — get the code
- https://www.youtube.com/watch?v=RDi2snh8bpA
Footnotes
-
DevTools 화면 자체(TypeScript·CSS 웹앱). 이 프런트엔드가 CDP 로 대상과 대화하므로, 떼어다 다른 곳에 붙이면 자기만의 디버거가 된다 — 아래 chii 가 그렇게 쓴다. ↩
-
Node 에서 CDP 를 부르는 클라이언트. 명령·이벤트를 JS API 로 감싸서, 예컨대 페이지를 열고 나가는 요청을 전부 덤프하는 걸 몇 줄로 짠다. ↩
-
DevTools·CDP 생태계 링크 모음 — 학습 자료, 프로토콜 클라이언트, DevTools 프런트엔드를 다른 플랫폼에 쓰는 법, 확장. 마지막 커밋이 2021-01 이라 최신 도구는 빠져 있다. ↩
-
모바일 웹 페이지 안에 띄우는 가벼운 콘솔 패널(로그·네트워크·요소·스토리지). CDP 없이 페이지 안에서 돈다 — WeChat 미니프로그램의 공식 디버깅 도구. ↩
-
weinre 같은 원격 디버거인데 화면을 최신 devtools-frontend 로 바꿨다. 디버깅할 페이지에 스크립트를 넣고, 다른 기기의 브라우저에서 DevTools 로 붙는다. ↩
The
Generatorobject is returned by a generator function and it conforms to both the iterable protocol and the iterator protocol.
useGenerator— 핸들러를 async generator 로 받아 yield 마다 상태를 바꾼다- Iterator Helpers — async generator 페이지네이션을
take로 조기 종료 - Maybe Monad — generator 로 early return
- MobX
flow—await대신yield
- Async iterators and generators - JakeArchibald.com1
- How to consume a paginated API using JavaScript async generators
- Why would anyone need JavaScript generator functions?
Footnotes
-
Streaming 작업 시 비동기처리 방법을 알려주고 있는데…경험이 없어서 일단 메모. ↩
브라우저에서 PDF 및 이미지 파일에 대한 OCR 실행
- PDF.js를 사용하여 PDF에서 이미지를 추출
- Tesseract OCR로 추출된 이미지에서 텍스트를 인식
- 직접 브라우저 상에서 OCR 작업을 실행
getServerSideProps
|> getServerSideSitemapLegacy
|> withXMLResponseLegacy
|>
res.setHeader('Content-Type', 'text/xml')
res.write(content)
res.end()
SSR에서 XML 형식의 사이트맵을 생성하기.
import * as React from 'react'
type ContainerProps = {
children: typeof Body
}
type BodyProps = {
id: string
}
function Container({ children }: ContainerProps) {
const id = '1234'
return <>{children({ id })}</>
}
export function Body({ id }: BodyProps) {
return <>{id}</>
}
export function Page() {
return <Container>{Body}</Container>
}
컨테이너/프레젠테이션 패턴을 활용한 React 컴포넌트 구조.
- 컨테이너 컴포넌트(
Container)는 상태를 관리하고 데이터를 하위 컴포넌트에 전달함. - 프레젠테이션 컴포넌트(
Body)는 데이터를 받아서 UI를 렌더링함. - 이 구조는 테스트를 쉽게 하고, 컴포넌트의 역할을 명확하게 분리함.
/**
* - 인자 수 확인: `curry` 함수는 전달된 함수 `fn`의 인자 수를 확인
* - 인자 수가 충분한 경우: 만약 `args`의 길이가 `fn`의 인자 수 이상이면, `fn`을 호출하고 결과를 반환
* - 인자 수가 부족한 경우: 그렇지 않으면 추가 인자(`moreArgs`)를 받을 수 있는 새 함수를 반환. 이 함수는 기존 인자(`args`)와 새로운 인자(`moreArgs`)를 합쳐 다시 `curry(fn)`을 호출하여 최종적으로 인자가 충분할 때까지 이 과정을 반복
*/
const curry =
(fn: Function) =>
(...args: any[]) =>
args.length >= fn.length
? fn(...args)
: (...moreArgs: any[]) => curry(fn)(...args, ...moreArgs)
/**
* - `...fns: Function[]` 여러 개의 함수를 인자로 받는다
* - 내부에서 `reduce` 메서드를 사용하여 함수 배열을 순회 초기값으로 `x`를 사용하며, 각 함수 `fn`을 차례로 호출하여 결과를 다음 함수로 전달
*/
const pipe =
(...fns: Function[]) =>
(x: any) =>
fns.reduce((acc, fn) => fn(acc), x)
/**
* - `...fns`: 여러 개의 함수를 매개변수로 받음
* - `(x)`: 초기값 `x`를 인자로 받아 결과를 리턴
* - `fns.reduceRight(...)`: 배열의 오른쪽부터 왼쪽으로 각 함수를 적용합니다. `y`는 이전 함수의 결과이며, `f`는 현재 함수
* - `f(y)`: 현재 함수 `f`를 이전 함수의 결과 `y`에 적용
*/
const compose =
(...fns) =>
(x) =>
fns.reduceRight((y, f) => f(y), x)
- 함수 조합(Composition): 작은 함수들을 조합하여 새로운 함수를 만들며, 예를 들어
compose(f, g, h)는f(g(h(x)))로 실행 compose: 오른쪽에서 왼쪽으로 함수를 실행하며,compose(square, double)(3)은 36을 반환pipe: 왼쪽에서 오른쪽으로 함수를 실행하여,pipe(double, square)(3)의 결과는 36- 커링(Currying):
f(a, b, c)를f(a)(b)(c)형태로 변환하고, 예를 들어add(1)(2)(3)의 결과는 6 - 부분 적용(Partial Application): 일부 인자만 미리 적용하여 새로운 함수를 만들 수 있으며,
const double = multiply(2, _)로 정의 - 포인트-프리 스타일: 변수를 사용하지 않고 함수를 조합하여 작성하며, 예를 들면
compose(square, double)와 같은 형태 - 데이터 마지막 원칙(Data Last): 데이터를 마지막 인자로 배치하여 조합성을 높이는데, 예를 들어
const halve = divideDataLast(2)와 같이 사용
- 프런트엔드(클라이언트)에서 MP4 파일의 오디오 존재 여부를 확인하기
- 브라우저 API 사용 시 호환성 문제 발생 (Chrome, Safari, Firefox 각각 다른 API 사용)
- FileReader API를 사용하여 서버에서 응답받은 바이너리 데이터를 읽고, 이를 분석해 오디오 여부 확인.
- 오디오 정보가 발견되지 않으면 추가 데이터 요청하여 확인 범위를 증가시켜 반복.
await ffmpeg.writeFile('input.mp4', await fetchFile(file))
await ffmpeg.ffprobe(['-i', 'input.mp4', '-show_streams', '-o', 'output.txt'])
const data = await ffmpeg.readFile('output.txt')
…하지만 ffmpeg의 중요성을 깨달았다.
Figma의 권한 관리 DSL - JSON 직렬화 가능한 DSL로 정책 표현, TypeScript 기반 평가 엔진 구현.
기존 문제: 불필요한 복잡성, 계층적 권한 비효율, DB 부하, 여러 진실 소스
type ExpressionDef = BinaryExpressionDef | OrExpressionDef | AndExpressionDef
// 바이너리 표현식: [필드, 연산자, 값]
const binaryExpression = ['file.id', '<>', null] satisfies ExpressionDef
// AND/OR 조합
const andExpression = {
and: [
['file.id', '<>', null],
['team.permission', '=', 'open'],
],
} satisfies ExpressionDef