Turborepo миграция с Go на Rust: как Vercel использует Zig для совместимости
Компания Vercel продолжает масштабный проект по переносу Turborepo — высокопроизводительной системы сборки для JavaScript и TypeScript — с Go на Rust. Ранее компания рассказала, как начала этот процесс, а теперь поделилась подробностями о портировании двух основных команд: run и prune. Но самым неож

Компания Vercel продолжает масштабный проект по переносу Turborepo — высокопроизводительной системы сборки для JavaScript и TypeScript — с Go на Rust. Ранее компания рассказала, как начала этот процесс, а теперь поделилась подробностями о портировании двух основных команд: run и prune. Но самым неожиданным открытием стало использование языка Zig для решения проблемы совместимости между Go и Rust. Это решение позволило сохранить точное поведение оригинального кода, не переписывая всю файловую подсистему с нуля.
Почему Zig оказался в центре миграции Turborepo
Основная сложность заключалась в том, что Turborepo активно использует специфичные для Go возможности работы с файловой системой. В частности, команда run должна отслеживать изменения файлов и перезапускать задачи при их модификации — это требует точного соответствия поведению Go. В Rust же реализация файловых операций отличается, и переписывание всей логики с нуля было бы слишком трудоёмким и рискованным.
Вместо этого инженеры Vercel решили использовать Zig — низкоуровневый язык, который может компилироваться в библиотеки, совместимые с C. Они переписали критический участок кода на Zig, а затем скомпилировали его в статическую библиотеку, которую можно вызывать из Rust через FFI (Foreign Function Interface). Это позволило сохранить точное поведение Go, но при этом интегрировать его в Rust-версию Turborepo.
Как Vercel пришла к идее использовать Zig для миграции?
Идея использовать Zig возникла не сразу. Первоначально команда рассматривала возможность полной перезаписи файловых операций на Rust, но быстро поняла, что это потребует огромных усилий и может привести к несовместимости с существующим кэшем. Zig, с его возможностью компиляции в C-совместимые библиотеки, оказался идеальным промежуточным звеном. Он позволил изолировать сложный код и повторно использовать его без изменений.
Предыстория и контекст: почему Vercel меняет Go на Rust
Turborepo изначально был написан на Go и быстро завоевал популярность благодаря скорости работы с монорепозиториями. Однако со временем команда столкнулась с ограничениями Go: отсутствие полноценного управления памятью и менее выразительная система типов усложняли поддержку и развитие проекта. Rust, напротив, предлагает безопасную работу с памятью, нулевые абстракции и отличную производительность.
Vercel начала миграцию в 2023 году, но процесс оказался сложнее, чем ожидалось. Вместо полной перезаписи компания выбрала инкрементальный подход, перенося компоненты по одному. Однако команда run и prune оказались особенно сложными из-за их тесной связи с файловой системой и кэшированием.
Как работает решение на Zig
Zig выступил в роли «прокладки» между Go и Rust. Инженеры выделили из Go-версии Turborepo функции, отвечающие за хэширование файлов и обнаружение изменений — эти функции были критичны для корректной работы кэша. Затем они переписали их на Zig, сохранив ту же логику, но с учётом особенностей компиляции. Полученная библиотека подключается к Rust-коду через C ABI, что делает вызовы практически без накладных расходов.
Такой подход позволил избежать полного переписывания всей файловой подсистемы. Более того, Zig обеспечивает полный контроль над памятью и не имеет сборщика мусора, что критично для производительности в сценариях с интенсивным вводом-выводом. В результате команды run и prune в Rust-версии работают так же, как в Go, но с потенциально более высокой производительностью за счёт оптимизаций Rust.
Технические подробности: что изменилось под капотом
Основная часть работы пришлась на систему хэширования. В Go-версии Turborepo использовался собственный алгоритм для вычисления контрольных сумм файлов, который учитывал метаданные и содержимое. При переносе на Rust инженеры столкнулись с тем, что стандартные библиотеки Rust дают другие результаты для некоторых краевых случаев. Zig позволил сохранить точное поведение: код на Zig компилируется в нативный машинный код, который вызывается из Rust без какой-либо обёртки.
Кроме того, команда prune, отвечающая за удаление неиспользуемых файлов из кэша, также требовала точного соответствия Go. Используя Zig, разработчики смогли повторно использовать те же алгоритмы, что и в оригинале, но в контексте Rust-приложения. Это значительно сократило время тестирования и снизило риск регрессий.
Кого затронет и как
Нововведение в первую очередь повлияет на разработчиков, использующих Turborepo в своих проектах. Для них миграция пройдёт незаметно: API останется прежним, но производительность может улучшиться. В долгосрочной перспективе Rust-версия позволит быстрее добавлять новые функции и исправлять ошибки, так как код станет более безопасным и поддерживаемым.
Для сообщества Rust и Zig это интересный пример практического использования Zig в качестве связующего звена между двумя языками. Подход Vercel может вдохновить другие компании, сталкивающиеся с подобными проблемами при миграции.
Пользователи из России и СНГ, активно применяющие Turborepo в DevOps-практиках, также выиграют от ускорения сборок и уменьшения потребления ресурсов, хотя прямых ограничений на использование нет.
Что будет дальше
Vercel планирует завершить портирование всех команд Turborepo на Rust в течение 2025 года. Пока что run и prune — лишь первые шаги. В дальнейшем компания намерена переписать и другие компоненты, возможно, снова используя Zig для сложных участков. Кроме того, Vercel рассматривает возможность открытия исходного кода Zig-прокладки, чтобы другие разработчики могли перенимать этот опыт.
Ожидается, что финальная Rust-версия Turborepo будет выпущена в стабильном релизе в конце 2025 года. Параллельно команда работает над улучшением документации и инструментов миграции для существующих пользователей.
Итог
Использование Zig в миграции Turborepo с Go на Rust — это изящное инженерное решение, которое позволяет Vercel сохранить совместимость, не жертвуя производительностью. Этот подход демонстрирует, что даже в эпоху Rust иногда требуется третий язык для решения специфических задач. Следите за обновлениями Turborepo: в ближайшие годы система станет ещё быстрее и надёжнее.