웹킷(WebKit)이 사파리(Safari) 웹 브라우저의 자바스크립트(JavaScript) 모듈 로더를 C++로 전면 재작성했습니다. 이는 ECMAScript 2022에 도입된 탑레벨 어웨이트(Top-Level Await, TLA) 기능과 관련된 고질적인 버그를 해결하기 위함입니다. 기존 모듈 로더는 특정 상황에서 모듈의 평가가 완료되기 전에 `import()` 호출이 먼저 끝나버려 'Cannot access '...' before initialization'과 같은 오류를 발생시켰습니다. 이번 재작업을 통해 사파리는 ECMAScript 표준에 완벽하게 부합하는 비동기 모듈 실행 환경을 갖추게 됩니다.
이번 재작업의 근본 원인은 사파리의 기존 모듈 로더가 2016년 이후 업데이트되지 않은 오래된 WHATWG Loader 제안을 기반으로 만들어졌기 때문입니다. 초기 ES 모듈(ES Module)은 동기적으로 실행되었기에 문제가 없었지만, 비동기 실행을 가능하게 하는 탑레벨 어웨이트(TLA)가 도입되면서 기존 설계의 한계가 드러났습니다. 웹킷은 수년간 여러 차례 수정 시도에도 불구하고 미묘한 버그를 완전히 제거하지 못했고, 결국 기반 자체를 ECMAScript 명세에 맞춰 새로 구축하기로 결정했습니다. 새로운 모듈 로더는 사파리 27(Safari 27)에 포함될 예정이며, 현재 사파리 27 베타와 사파리 테크놀로지 프리뷰(Safari Technology Preview) 251에서 테스트 중입니다.
탑레벨 어웨이트(TLA)는 모듈 실행 흐름을 복잡하게 만듭니다. 모듈이 TLA를 만나면 해당 모듈의 실행이 일시 중단되고, 이를 가져오는 상위 모듈 역시 평가를 기다려야 합니다. 반면, 의존성이 없는 다른 모듈들은 병렬로 계속 실행될 수 있습니다. 따라서 모듈 로더는 단순히 파일을 가져오는 것을 넘어 전체 의존성 그래프의 평가 순서와 비동기 상태를 정확하게 관리해야 합니다. 기존 사파리에서는 동일 모듈을 `import()`로 세 번 연속 동적 로딩할 때, 첫 번째 모듈 평가가 끝나기 전에 두 번째, 세 번째 `import()`의 프라미스(Promise)가 먼저 해결되어 초기화되지 않은 변수에 접근하는 오류가 발생했습니다. 새로운 C++ 기반 로더는 이러한 평가 순서 문제를 해결하여 각 `import()`가 올바른 시점에 완료되도록 보장합니다.
또한, 웹킷은 기존 모듈 로더가 자바스크립트코어(JavaScriptCore) 내부의 셀프-호스티드 자바스크립트(Self-Hosted JavaScript Builtin)로 구현되어 있던 방식을 폐기하고 네이티브 C++ 구현으로 전환했습니다. 셀프-호스티드 자바스크립트는 인라인(inline) 코드 실행 및 C++ 경계 호출 비용 절감 등의 장점이 있지만, 모듈 로더와 같이 사용 패턴이 다양하고 핫 패스(hot path)가 아닌 경우에는 런타임 컴파일 및 JIT(Just-In-Time) 최적화의 이점을 얻기 어려워 성능의 안정성과 예측 가능성이 떨어졌습니다. 새로운 C++ 구현은 ECMAScript 명세의 모듈 오퍼레이션(module operation)을 기준으로 바텀업(bottom-up) 방식으로 재구현되어, 더욱 안정적이고 예측 가능한 성능을 제공할 것으로 기대됩니다. 번(Bun) 개발팀이 제공한 테스트 케이스와 퍼징(fuzzing)을 통해 검증 과정을 거쳤습니다.
이번 웹킷의 대규모 재작업은 웹 표준 준수의 중요성을 다시 한번 강조합니다. 브라우저 엔진이 최신 ECMAScript 표준을 정확히 구현하는 것은 웹 개발자들이 더욱 복잡하고 강력한 비동기 애플리케이션을 안정적으로 구축할 수 있는 기반을 제공합니다. 특히 탑레벨 어웨이트(TLA)는 모듈 수준에서 비동기 작업을 처리할 수 있게 함으로써 코드 구조를 간소화하고 초기 로딩 로직을 개선하는 데 기여합니다. 웹 개발자들은 사파리 27 출시 이후 TLA를 활용한 모듈 로딩 시 발생하던 미묘한 버그들로부터 자유로워져, 더욱 예측 가능하고 안정적인 개발 환경을 경험할 수 있을 것입니다. 이는 장기적으로 웹 플랫폼 전반의 견고성과 개발자 생산성 향상으로 이어질 것입니다.