Pretext는 무엇이고, 어디에 사용할 수 있을까
프론트엔드에서 텍스트를 다룬다는 것은 생각보다 비용이 큰 작업이다. 브라우저는 단순히 글자를 그리는 것이 아니라, 줄바꿈을 계산하고, 레이아웃을 만들고, 높이를 결정한다. 이 과정에서 getBoundingClientRect, offsetHeight 같은 API를 사용하면 layout reflow가 발생하고, 이는 렌더링 성능에 큰 영향을 준다.
Pretext는 이 문제를 다른 방식으로 접근한다. DOM을 통해 측정하지 않고, 텍스트 레이아웃 자체를 JavaScript로 계산한다.
이전 방식: DOM에 물어본다
기존에는 텍스트의 크기나 높이를 알아내기 위해 DOM을 직접 사용했다.
cons tel = document.getElementById('text')
const height = el.offsetHeight
TypeScript
복사
이 방식은 간단하지만 치명적인 문제가 있다.
•
layout reflow가 발생한다
•
브라우저가 전체 레이아웃을 다시 계산한다
•
호출 타이밍에 따라 성능이 급격히 떨어진다
특히 스크롤, 리사이즈, virtualization 같은 상황에서는 이 비용이 누적된다.
개선된 방식: DOM 없이 계산한다
Pretext는 이 문제를 완전히 다른 방식으로 해결한다. 핵심은 간단하다.
“텍스트 레이아웃을 DOM이 아니라, 계산으로 처리한다.”
import { prepare, layout } from '@chenglou/pretext'
const prepared = prepare('AGI 春天到了. بدأت الرحلة 🚀', '16px Inter')
const { height, lineCount } = layout(prepared, textWidth, 20) // pure arithmetics. No DOM layout & reflow!
TypeScript
복사
여기서 중요한 포인트는 두 단계로 나뉜다는 점이다.
•
prepare()
→ 텍스트를 분석하고, segment를 나누고, width를 측정한다
•
layout()
→ 실제 줄바꿈과 높이를 계산한다 (순수 연산)
즉, 비싼 작업은 한 번만 하고, 이후에는 계산만 반복한다.
이 구조 덕분에 resize나 scroll 상황에서도 매우 빠르게 동작한다.
왜 빠른가
Pretext가 빠른 이유는 단순히 “최적화 잘했다” 수준이 아니다. 접근 자체가 다르다.
기존:
•
DOM 생성
•
layout 계산
•
paint
Pretext:
•
텍스트를 segment로 분해
•
canvas 기반으로 width 측정
•
이후는 순수 연산으로 처리
즉, layout reflow 자체를 피한다.
이 차이는 성능에서 크게 드러난다.
Pretext로 할 수 있는 것
이제 중요한 건 “그래서 어디에 쓰는가”다.
1. 정확한 텍스트 높이 계산
DOM 없이도 텍스트의 높이를 정확하게 알 수 있다.
const { height } = layout(prepared, width, lineHeight)
TypeScript
복사
이걸로 가능한 것들:
•
virtualization 정확도 개선
•
layout shift 방지
•
스크롤 위치 유지
특히 “대충 height 추정”하던 문제를 해결할 수 있다.
2. 직접 줄바꿈을 제어하는 레이아웃
Pretext는 단순 측정뿐 아니라, 라인 단위 레이아웃도 제공한다.
import { prepareWithSegments, layoutWithLines } from '@chenglou/pretext'
const prepared = prepareWithSegments(text, '18px Inter')
const { lines } = layoutWithLines(prepared, 320, 26)
lines.forEach((line,i) => {
ctx.fillText(line.text, 0, i*26)
})
TypeScript
복사
이걸 활용하면:
•
Canvas 렌더링
•
SVG 텍스트 배치
•
WebGL 기반 UI
같은 “DOM 없이 그리는 UI”를 만들 수 있다.
3. 동적인 레이아웃 (Flow Layout)
Pretext의 가장 흥미로운 기능 중 하나는 라인 단위로 텍스트를 흘려보낼 수 있다는 점이다.
while (true) {
const width = y < image.bottom ? columnWidth - image.width : columnWidth
const range = layoutNextLineRange(prepared, cursor, width)
if (range === null) break
constline = materializeLineRange(prepared, range)
ctx.fillText(line.text, 0, y)
cursor = range.end
y += 26
}
TypeScript
복사
이 코드는 무엇을 의미하냐면,
•
이미지 옆에서는 좁게
•
이미지 아래에서는 넓게
이렇게 텍스트를 동적으로 흐르게 만들 수 있다.
이건 CSS로는 꽤 까다로운 작업이다.
4. 서버 사이드 텍스트 레이아웃
Pretext는 DOM에 의존하지 않기 때문에, 이론적으로 서버에서도 동일하게 동작할 수 있다.
이게 의미하는 바는 크다.
•
서버에서 layout 계산
•
클라이언트에서 그대로 렌더링
•
layout shift 없음
virtualization과의 관계
Pretext는 virtualization을 대체하는 개념이라기보다는, 보완하는 역할에 가깝다.
기존 virtualization의 문제:
•
height를 추정해야 함
•
정확하지 않으면 스크롤 튐 발생
Pretext를 쓰면:
•
height를 정확하게 계산 가능
•
virtualization 정확도 상승
즉, “리스트를 줄인다”가 아니라
“계산 자체를 정확하게 만든다”는 접근이다.
언제 쓰는 게 좋은가
Pretext는 모든 상황에서 필요한 도구는 아니다.
다음과 같은 경우에 특히 유용하다.
•
긴 텍스트를 다루는 경우
•
정확한 layout이 필요한 경우
•
DOM 의존성을 줄이고 싶은 경우
•
Canvas / WebGL 기반 UI
반대로 일반적인 CRUD UI에서는 과한 선택일 수 있다.
_(1).jpeg&blockId=0e552736-74f0-4f5a-89e1-328d4931ca7c)