rakers — Rust로 만든 헤드리스 JS 렌더러
Source: Dev.to
개요
웹상의 많은 유용한 콘텐츠는 JavaScript가 실행된 뒤에야 존재합니다. 서버‑사이드 렌더링이 다시 주목받고 있지만, 여전히 많은 사이트가 거의 비어 있는 HTML 골격만을 제공하고 클라이언트‑사이드에서 전체를 채웁니다. 그 콘텐츠를 추출하려면(아카이빙, 테스트, 처리 등) 먼저 JavaScript를 실행해야 합니다.
표준적인 해결책은 헤드리스 브라우저(Playwright, Puppeteer, 혹은 자체 호스팅 Chrome)입니다. 이것들은 동작하지만 무겁습니다: Chrome의 메모리 사용량은 약 300 MB이고, 시작하는 데 1~2초가 걸리며 CI에서 실행하려면 주의가 필요합니다. 많은 사용 사례에서 전체 브라우저는 과도한 선택이며, CSS 레이아웃, GPU 합성, WebGL이 필요하지 않고 스크립트가 실행된 뒤의 DOM만 있으면 됩니다.
rakers는 이 문제에 대한 최소한의 해결책을 찾으려는 시도입니다. 약 10 MB 크기의 단일 바이너리로 HTML을 파싱하고, JavaScript를 실행하며, 실행 후의 HTML을 반환합니다.
파이프라인
- Parse –
html5ever(Servo의 HTML5 파서, 독립 크레이트로 배포) 가 입력을 DOM 트리로 변환합니다. - Execute –
<script>태그를 문서 순서대로 수집합니다(인라인·외부 모두). 외부 스크립트는 동기식으로 가져옵니다. 모든 스크립트는 샌드박스된 JS 컨텍스트에서 평가되며, 여기서는document,window,console,XMLHttpRequest,localStorage,setTimeout등 브라우저와 호환되는 전역 환경을 제공합니다. - Serialize – 실행 후의 DOM을 다시 HTML로 직렬화하고 stdout(또는 파일)으로 출력합니다.
JavaScript 엔진
JS 엔진은 rquickjs 크레이트를 통해 QuickJS 를 사용합니다. QuickJS는 ES2023을 지원하고, 작고, Rust에 깔끔히 임베드됩니다. C 컴파일러가 없는 환경을 위해서는 선택적인 boa_engine 백엔드가 제공되며, 이는 순수 Rust 구현으로 호환성 범위는 작지만 네이티브 의존성이 전혀 없습니다.
브라우저 환경 스텁
가장 까다로운 부분은 JS 엔진이 아니라 가짜 브라우저 환경입니다. React, Vue, Svelte와 같은 프레임워크는 비교적 완전한 DOM API를 기대합니다. rakers는 실제 레이아웃 엔진이 없기 때문에, 이러한 API들을 bootstrap.js 에 정의된 JavaScript 스텁으로 구현하고 페이지 스크립트가 실행되기 전에 주입합니다.
스텁은 가장 일반적인 패턴을 다룹니다:
- 요소 생성 및 변형
getElementById,querySelector,querySelectorAll- 이벤트 리스너 등록
classListlocalStoragehistory.pushState- XHR (동기식 Rust fetch인
ureq로 지원)
XHR가 동기식이기 때문에, XHR을 통해 런타임에 템플릿을 로드하는 프레임워크(예: RiotJS)도 정상적으로 템플릿을 가져올 수 있습니다.
알려진 차이점
- 레이아웃 의존 속성(
offsetWidth,getBoundingClientRect)은 0을 반환합니다. - 네이티브 ES 모듈은 건너뜁니다.
이러한 차이점에도 불구하고, 스텁은 23개의 TodoMVC 구현 중 21개를 실행할 수 있을 정도로 충분히 호환됩니다. React, Vue, Angular, Svelte, Preact, Mithril, Elm, Backbone, Ember, Knockout 등 다양한 프레임워크에서 합리적인 호환성 벤치마크를 제공합니다.
사용 예시
# Basic usage
rakers https://example.com
# Pipe input from curl
curl -s https://example.com | rakers
# Use a SOCKS5 proxy
rakers --proxy socks5://127.0.0.1:9050 https://example.com
# Extract a specific selector
rakers --selector "article.post" https://example.com
설치
설치 방법은 프로젝트의 README에 자세히 나와 있습니다. 일반적으로 cargo 로 설치할 수 있습니다:
cargo install rakers
제한 사항
- CSS 엔진, 레이아웃, WebGL, IndexedDB, 서비스 워커가 없습니다.
- 이러한 기능에 의존하는 모든 것은 동작하지 않습니다.
- JS 환경을 지문인식하거나 실제
navigator.plugins배열을 요구하는 사이트도 실패합니다. - 이러한 경우에는 실제 헤드리스 브라우저가 적절한 도구입니다.
가치 제안
제안은 좁지만 실질적입니다: 자체 포함된 JS 번들만으로 렌더링하고, 특수한 브라우저 의존성이 없는 사이트에 대해 rakers는 Chromium 복사본을 배포하는 어떤 솔루션보다 빠르고, 작으며, 배포가 간단합니다.