Cloudflare와 VoidZero는 Owner.com의 Max Schwenk과 협력하여 TypeScript 컴파일러의 Rust 포트인 tsrs를 개발하고 있습니다. 저희는 TypeScript 팀과의 긴밀한 협력을 통해 이 작업을 진행하고 있으며, tsrs를 Oxc JavaScript 컴파일러 툴체인의 일부로 육성하고 있습니다.
저희의 목표는 개발자들이 코드를 확인하기 위해 기다리는 시간을 줄이고, 더 많은 시간을 구축하는 데 할애할 수 있도록 돕는 것입니다. TypeScript를 더 빠르고 메모리 효율적으로 만드는 것은 브라우저 내에서도 완전한 개발 환경을 구현하는 데 도움이 됩니다.
명확히 하자면, 저희는 TypeScript를 포크(fork)하는 것이 아닙니다. 저희는 TypeScript 팀이 언어의 설계와 방향에 대한 완전한 통제권을 유지해야 한다고 믿습니다. 그들은 JavaScript 커뮤니티 전반에 걸쳐 TypeScript 채택을 안내하면서 장기적인 비전을 유지해 왔습니다. 저희는 그것을 바꾸고 싶지 않습니다.
TypeScript 팀은 많은 부분에서 상당히 빠르게 움직일 수 있지만, 일부 기능의 경우 올바른 구현을 선택하기 위해 의도적으로 옵션을 탐색하고 프로토타입을 만드는 데 몇 년이 걸릴 수도 있습니다. Rust 포트는 이러한 결정들을 면밀히 따라야 하며, 그렇지 않으면 결국 무너지고 호환되지 않게 될 것입니다. 저희는 TypeScript 언어를 원래의 구현에 기반하여 엄격하게 보존해야 하며, 이 모습이 무엇인지 결정하는 책임은 전적으로 TypeScript 팀에게 남아 있어야 합니다.
성능 및 메모리 개선
저희 Rust 포트인 TypeScript의 초기 벤치마크 결과는 유망합니다: tsrs는 동일한 수의 타입 검사 워커를 사용할 때, TypeScript 7.0에 비해 최대 8배 빠르며 약 70% 적은 메모리를 사용합니다:
보시다시피, TypeScript의 다음 버전은 이미 많은 성능 개선을 가져와서, TypeScript 7.1 베타는 TypeScript 7.0보다 최대 2.5배 빠릅니다. 이러한 최적화 중 일부는 tsrs에서 상위 스트림(upstreamed)되었으며, 저희는 더 많은 것을 찾기를 희망합니다.
최근 다양한 성능 주장을 하는 여러 TypeScript 포트의 벤치마크를 보셨을 수 있습니다. 이러한 차이는 종종 TypeScript의 기본 설정과 비교하여 더 큰 머신 타입이나 다른 옵션을 사용했기 때문입니다. 저희는 TypeScript 팀과 협력하여 위 벤치마크가 동일한 구성을 비교하도록 했습니다.
기본적으로, tsrs는 메모리를 더 많이 사용하지만 훨씬 빠른 적응형(adaptive) 설정을 갖추고 있습니다:
tsrs 사용해 보기
TypeScript in Rust는 TypeScript의 충실한 포트를 목표로 합니다. npm에서 tsrs 패키지를 설치하여 실험적인 릴리스를 시도해 볼 수 있습니다:
npm install tsrs
npx tsrs
왜 지금인가?
저희는 지난 몇 년 동안 TypeScript를 다른 언어로 포팅하려는 많은 시도를 목격했습니다. 관련된 복잡성 때문에, 성공한 포트는 오직 하나뿐이었습니다: TypeScript 팀이 JavaScript에서 Go로 구현한 TypeScript 포트입니다.
하지만 이제 최첨단 AI 모델들은 거의 독립적으로 며칠 만에 대규모 포트를 수행할 수 있게 되었습니다. 저희는 이미 Rust나 C++로 작성된 TypeScript의 슬롭포크(slopforks), 충실한 포트, 그리고 완전히 재설계된 버전을 보았습니다. 더 빠른 TypeScript에 대한 수요가 분명히 존재합니다.
왜 Rust인가?
'TypeScript의 Go 포트만으로도 이전 버전보다 10배 빠르고 메모리 효율적이지 않던가? 이것만으로는 충분하지 않은가?'라고 생각하실 수도 있습니다.
하지만 문제는 속도에만 국한되지 않습니다. Rust는 몇 가지 독특한 장점을 제공합니다: WebAssembly에서 실행된다는 점입니다. Rust + Wasm 이야기는 항상 강력했으며, 그 이유 중 하나는 Rust의 언어 설계 기본 원칙과 관련이 있습니다. Go 프로그램을 Wasm으로 컴파일할 때, Go의 가비지 컬렉터(garbage collector)를 함께 컴파일해야 합니다. 하지만 Rust의 메모리 관리 모델은 WebAssembly 게스트와 호스트 간에 간단한 메모리 상호 작용을 가능하게 합니다. 이것이 Rust가 WebAssembly 사용 사례에 훨씬 더 적합한 이유 중 하나입니다: 메모리 효율성 때문입니다.
Cloudflare Workers는 오랫동안 Wasm을 지원해 왔습니다. 불과 몇 주 전, 저희는 wasm-bindgen의 새로운 Emscripten 타겟으로 Worker에서 네이티브 Rust를 지원한다고 발표했습니다. Worker에서 전체 소프트웨어 빌드 및 배포 시스템을 촘촘한 루프(tight loops)로 실행할 때, 작은 메모리 발자국(memory footprint)의 이점은 빠르게 체감됩니다. 이는 이러한 워크로드들을 매우 효율적으로 실행할 수 있게 하여, 이전에는 실행될 수 없었던 장소에서도 완전히 격리된 개발 시스템을 운영하는 것이 가능해졌다는 것을 의미합니다.
이는 에이전트와 결합했을 때 새로운 가능성을 열어줍니다. 이제 Cloudflare에서 완전히 샌드박스화된 환경 내에서 개발 도구 체인 전체를 실행할 수 있게 되었습니다. 하지만 Wasm을 사용하면 이러한 환경들을 브라우저 클라이언트 측, 또는 임베디드 장치, 혹은 IoT 애플리케이션에서도 안전하게 운영할 수 있습니다.
tsrs 포트는 어떻게 유지될까요?
먼저, 저희는 Theo Browne와 협력하여 tsc-rs와 tsrs를 단일 패키지로 병합하고 있으며, 이 패키지는 Language Server Protocol (LSP) 및 콘텐츠 매퍼(content mappers)를 포함한 TypeScript의 모든 기능을 지원할 것입니다. 둘째, 저희는 Vinext를 상위 버전인 Next.js와 동기화하는 방식에서 많은 성공을 거두었습니다. 저희는 [최근 블로그 게시물]에서 이 과정을 설명했습니다:
매일 아침, 에이전트가 변경 사항을 검토하고, 차이점(diffs)을 가져오며, Vinext에 영향을 줄 수 있는 모든 것에 대해 추적 이슈를 생성합니다. 매일 밤에는 Next.js 테스트 스위트를 Vinext에 실행하면서 호환성 행렬(compatibility matrix)이 재생성됩니다. 이러한 테스트나 이슈 중 하나가 격차(gap)를 발견하면, 에이전트들은 이제 두 코드베이스 전반에 걸쳐 변경 사항을 식별하고, 재현 환경을 구축하며, 관련 테스트를 포팅하고, 수정 방안을 제안할 수 있는 위치에 있습니다.
저희는 TypeScript에도 동일한 프로세스를 적용하여, 상위 버전 TypeScript와 다른 동작(diverging behaviors)을 도입하지 않도록 극도로 주의를 기울일 것입니다. 성능 개선 사항을 발견하면, 모두가 이익을 얻을 수 있도록 TypeScript Go 코드베이스에 기여할 수 있도록 시도할 것입니다.
마지막으로, 현재 업스트림(upstream) 버전의 TypeScript와는 진단 메시지(diagnostics)가 출력되는 순서 같은 몇 가지 차이점이 있다는 것을 인식했습니다. 저희는 안정화된 릴리스를 발표할 때까지 이러한 차이를 최소화하는 것을 목표로 합니다.
향후 계획?
Cloudflare는 이미 Vite, Rolldown, Oxlint, Oxfmt와 같이 JavaScript 생태계를 구동하는 많은 무료 오픈 소스 Rust 도구들의 본거지입니다. 1,000만 명 이상의 개발자가 Cloudflare를 기반으로 구축하고 있기 때문에, 저희는 근본적인 개발자 툴체인(developer toolchain)을 더 빠르고, 더 이식성이 높으며, 더 많은 곳에서 쉽게 실행할 수 있도록 하는 것에 큰 관심을 기울이고 있습니다. 예를 들어 Oxlint의 타입 인식(type-aware) 린트 규칙에 깊이 있는 tsrs 통합을 실험하는 것에 기대가 큽니다.
Vinext와 마찬가지로, 저희의 목표는 TypeScript 자체를 방해하지 않으면서도 잘 관리되는 건강한 오픈 소스 프로젝트로서 tsrs를 운영하는 것입니다. Oxc 팀은 이미 코드베이스를 리팩토링하여 속도를 높이고, 메모리 사용량을 줄이며, 유지보수하기 쉽게 만드는 작업을 시작했습니다. 저희는 TypeScript 팀이 이 문제를 심각하게 받아들이고 있다는 것을 알고 있습니다. 그들은 tsc의 메모리 및 성능 개선을 실험하고 있습니다. 저희는 최고의 빠르고 효율적인 TypeScript 구현을 함께 구축하기 위해 TypeScript 팀 및 JavaScript 커뮤니티와 협력하는 것에 기대가 큽니다.