История о том, как я написал компилятор Svelte на Rust

от автора

Всем привет! Я хочу рассказать про свой путь написания компилятора Svelte на языке Rust, о своих мотивах и результатах.

Компилятор лежит тут: https://github.com/MrWaip/svelte-rs


Предыстория

Меня зовут Константин, я работаю в enterprise-компании на протяжении 5 лет фронтенд-разработчиком. Мы используем SvelteKit ещё с бета-версии.

У нас огромная кодовая база Svelte. В самом большом проекте 25 тысяч компонентов вместе с внутренними пакетами. И, по-моему, в 24 году мы упёрлись в то, что проекты долго собираются, LSP в IDE лагают, svelte-check работает долго. На 8-гиговых маках (людей с такими было немного) проекты вовсе не запускались. Dev-сервер стартовал долго, работал медленно. Ноуты грелись и гудели.

В это время TypeScript на Go ещё даже не анонсировали: Project Corsa объявили только в марте 2025 года, то есть уже под конец моей первой попытки. По-моему, уже void0 сказали, что разрабатывают Rolldown. А у нас был Vite 5, Svelte 4 в монолите, Svelte 5 в микрофронтах. И решение извне было ещё далеко: Vite 8 вышел стабильным 12 марта 2026 года, Rolldown 1.0 вышел 7 мая 2026 года, TypeScript 7 RC 18 июня 2026 года, а GA 8 июля 2026 года (LSP всё ещё в работе у TS 7, и поддержки программного API нет).

В это время в одном видео ThePrimeagen я увидел рекомендацию прочесть «Writing an Interpreter in Go». Я прочёл её, написал интерпретатор Monkey на Go, и меня это очень затянуло.

Следом я решил попробовать написать JS/TS-парсер на Go, прикола ради. И, читая спеку ECMAScript, пришёл в ужас, а у TS спеки вообще не было, у них есть только typescript.js на 9 мегабайт и 196 тысяч строк. И бросил эту затею, игра не стоит свеч.

Неделей спустя я решил сузить скоуп и выбрал Svelte, т. к. это же compiler.

4 ноября 2024 года я начал. Сначала я подумал: кода немного, и попробую именно портировать его line by line. Мне очень не понравилось, что то, как написан парсер Svelte, не было похоже на то, что я видел в книжке. Было много работы регулярок, лишних обходов, сканирований и так далее. Я решил написать парсер с нуля сам, сам его прототипируя, реверс-инжинирингом подглядывая на AST Svelte.

First try

Я потратил на эту работу пять с половиной месяцев: с 4 ноября 2024 года по 24 апреля 2025 года, 303 коммита, 108 дней с коммитами. В это время ИИ-агентов вроде ещё не было или я не знал об их существовании. Всё делалось руками, попутно изучая Rust, тильтуя от borrow checker’а и прочих его весёлых концепций.

Я брал какую-то простую единицу Svelte: отрендерить текст, отрендерить статичный HTML-элемент, отрендерить интерполяцию. По коммитам видно, как это шло. 6 ноября я начал сканировать интерполяцию. 8 декабря закоммитил finally interpolation. Месяц на Hello {name}!.

И писал сначала scanner, который разбирал в строке <div> text </div> токены типа StartTag {name: “div”}, Text {value: » text «}, EndTag {name: “div”}. Затем парсер, который эти токены превращал в AST-дерево, затем кодген-часть, которая превращала это в JS. На простых кейсах это было очень просто делать.

Первая сложность была с тем, как парсить JS. Svelte использовал для этого acorn. Уже существовал проект OXC, который является ядром Vite 8 / Rolldown, из-за которого я и выбрал Rust, потому что на Go не было поддерживаемых парсеров JS/TS.

Если тег script довольно легко распарсить, то вот выражение { 1 + 1 } мне было неочевидно. От скобки до скобки просто не просканировать, т. к. внутри могут быть вложенные скобки в JS Expression. Могут быть строковые литералы "${name}". Оригинальный компилятор просто отдаёт acorn’у кусок начиная с { и позволяет ему самому найти конец выражения.

Ничего лучше придумать, чем считать баланс скобок и не парсить JS на этапе лексера, я не смог, тем более что OXC не умел вести себя как acorn и падал. Таким образом, лексинг оставался без бэктрекинга за O(n).

Тогда же я решил делать парсер с восстановлением. Разбор в Svelte построен на исключениях: первая ошибка его прекращает, и в IDE ты видишь одну проблему за раз. У меня ошибка пишется в список, разбор идёт дальше. Задел был под встреивание в LSP.

Дальше возникло много непонимания устройства Svelte-компилятора, я расскажу про два.

Внутри есть различные оптимизации, пример: оригинал выкидывает лишние \n, \t, \s символы из начала строк. А в <h1>Hello {name}!</h1> три токена (текст, выражение, текст) склеиваются в один шаблонный литерал:

var root = $.from_html(`<h1></h1>`);export default function App($$anchor) {var h1 = root();h1.textContent = `Hello ${name ?? ''}!`;$.append($$anchor, h1);}

Ни трёх текстовых нод, ни трёх присваиваний. Такие штуки не выводятся из грамматики, их надо находить в оригинале по одной.

А как спроектировать AST в Rust? Я решил следовать JS версии AST и хранить строки. Но не String, str', эффективно же, без аллокаций, одна и та же строка, думал я. Следующая ошибка была, хранить в AST мета информацию, по подобию оригинала, которая наполняется анализ фазой. Оба этих решения приводили к тому что через все AST прорастал lifetime, а мутировать такое дерево в AST без Cell, RefCell, .borrow было невозможно. Все вместе превращалось в код который долго, скучно писать и поддерживать.

Отдельная головная боль: куда девать все эти оптимизации и факты о коде. В AST их пихать не хотелось, оно и так распухло от мета-полей. Тут я прочитал, как устроен HIR в rustc, и мне показалось логичным: вот же оно, второе дерево, туда всё и сложим.

25 февраля завёл два крейта, hir и ast_to_hir. Второе дерево, в которое лоуэрится AST, с идентификаторами NodeId, OwnerId, AttributeId вместо ссылок. За неделю сделал лоуэринг, компиляцию, заготовку под анализ и трансформ, к началу марта через него проходили текст и элементы.

А смысла в нём не было. Отдельное дерево оказалось не нужно: то, ради чего я его заводил, во второй попытке стало анализом и семантиками, без всякого второго дерева. Тогда я этого не понимал и просто получил два AST вместо одного, лоуэринг между ними и вдвое больше бойлерплейта на каждый чих.

Вот это и был последний гвоздь в крышку гроба моей мотивации.

Пять с половиной месяцев, 303 коммита, и продвинулся я никуда. Отставал от оригинала всё сильнее, они выпускали новые фичи, OXC обновлялся, а я тонул в lifetime’ах и бойлерплейте. Писать код на Rust’е было очень утомительно и тратило больше времени на проброс типов, чем реальной полезной работы. Я понял, что не сделаю это и за год, а вдобавок выгорю и буду отставать от оригинала навечно. Бросил 24 апреля 2025 года на коммите each block, посреди {#each}. И забыл про эту историю на десять с половиной месяцев.

Second try AI generation

9 марта 2026 года я вернулся. За это время ИИ бурно вырос, я для себя открыл Cursor, Claude Code, Codex и наделал с ними всякого, от плагина для Steam Deck до расширения для VS Code.

Короче, я открыл для себя ИИ, и это был очень интересный опыт. Он помог мне сделать то, чем я бы никогда не захотел сам заниматься в свободное от работы время и потратил бы сильно больше времени, а проблему бы ещё и не решил.

Ко мне в голову закралась идея, что ещё можно сделать с ИИ одному человеку, и я вспомнил про компилятор на Rust’е, и понеслось.

Работы велись или после 8-часового рабочего дня, вечером или на выходных: 42% коммитов между 19:00 и 01:00, 43% в выходные.

Для работ был выбран Claude за 20 бачей. Очень быстро я начал сжигать всю подписку и уходить в лимиты. Тут я перешёл на 100-бачевую подписку, её хватало до середины весны, когда начались проблемы с кэшами антропиков, и до переезда антропиков на грок инфру.

За месяц это 100 864 сообщения, 100 миллионов токенов на выход и 24 миллиарда на чтение кэша. По прайс-листу API это около $17 000. За пять месяцев набежало бы тысяч на восемьдесят. Заплатил я $700.

Актуализация

Первое, с чего я начал: поресёрчил, как избавиться от прорастания lifetime’ов строк повсюду. Ровно то, на чём я утонул в первый заход. Решение такое: мы храним span в AST, start + end, вместо str. Таким образом работа с AST становится сильно проще. Где-то смухлевал и положил String. Доп. аллокация, но не критично. Это сильно упростило написание кода. Пять месяцев боли, и один вечер, чтобы её снять.

Затем я обновил svelte до актуальной на тот момент версии. Положил в корень проекта исходники компилятора, документацию из svelte.dev, чтобы модели было просто смотреть на реализацию оригинала. Следом я выровнял версию OXC до актуальной. Также поизбавлялся от HIR-версии AST, промежуточных версий парсера и кодгена, которые появились в связи с HIR. Таким образом мы получили проект, с которым можно работать.

Весь старый код я снёс на второй день, 10 марта, коммитом Drop legacy version: 82 файла, +10 / −12 296.

На протяжении всего пути меня мучали несколько вопросов:

  • А с чего начать-то? Как построить процесс? Что делать с фичами, которые связаны между собой?

  • Как это тестировать?

  • Как ревьювить такое количество кода?

  • Как организовать работу между множеством сессий?

  • Как сделать навигацию ИИ эффективней?

  • Как писать скиллы и зачем?

  • Что делать, когда ИИ делает не то, что нужно?

Первый вид работ

Выглядел ок как-то так: «просканируй весь оригинал и составь список чекбоксов фичей, которые есть в ./original/compiler». И получил список: 128 строк, 76 галочек, отмечено ноль.

Затем я писал большой промпт, по сути: «Возьми галочку из todo.md, посмотри в оригинал и реализуй по нашей архитектуре».

На этом этапе я отдался Vibe’у… ревьювил плохо, да и понимания у меня тогда было мало, как я хочу видеть компилятор, я мог пристально отсмотреть только parser-часть. Прогресс шёл семимильными шагами, много кода, много фичей быстро реализовывались. За три недели марта 631 коммит, в пике 85 за сутки, пятнадцать дней подряд без выходных.

Где-то в это время и появились первые гига-скиллы /port + /audit. Появились пять конкурирующих трекеров: plan.md, PROGRESS.md, ROADMAP.md, TODO.md, PLAN.md. Как трекать прогресс эффективно, было непонятно.

Также глаз радовался, что всё в коде покрыто комментариями… (к ним вернёмся).

Тогда же появился способ тестирования. Есть команда just generate, которая берёт из папки cases/*/case.svelte файлы и генерит рядышком файлик case.svelte.js вроде от оригинального компилятора.

И на эти же кейсы натравлен наш компилятор, и получалось сравнение. Мы брали case.svelte.js и сравнивали его со своим output’ом. Тесты заводились абы как, ИИ без какой-то системы, по её настроению.

Пока тесты пополнялись, выяснилось несколько фактов: оригинал TS стрипает, но не весь. Например, на enum кидаются диагностики, т. е. ожидается, что такое будет обрабатывать препроцессор. Комментарии оригинал и OXC пишут по-разному, поэтому они удалялись из сравнения в тестах. CSS-парсер у оригинала неполноценный: вместо вырезания неиспользуемых AST-нод они оборачиваются в комментарии /* (unused) */ через magic string, а удаляет он их только когда включена минификация. Поэтому пришлось нормализовать CSS через сторонние тулы перед сравнением. Также в случае с customElement или dev-режимом CSS с комментами инлайнится в JS, что пришлось тоже нормализовывать.

Также тогда стартанул «туалетный кодинг» (в шутку). Это когда можно с claude.ai в облаке запускать агентов в чатике и делать то же самое, что с компа, но с телефона, в туалете, в кровати, в дороге и т. д. С телефона вызвались скиллы /audit -> /port -> merge.

Затем добавилось несколько скиллов по ревью кода агентами: /review, потом четыре отдельные команды по крейтам, которые через три дня схлопнулись обратно в одну, потом /fix-review, потом три агента: codebase-analyzer, quality-reviewer, reference-tracer. Они работали медленно, часто false positive, жрали токены, а толку давали мало. Собирали огромные md-файлы, чеклисты проблем, оценивали их по важности, и всё херня была. Поправил 1 раз, ИИ в другой сессии повторит. Позже я снёс их все разом вместе с ещё пятнадцатью командами.

Лимиты

В середине весны у антропиков возникли проблемы и им не хватало ресурсов и железа. Они вводили часы пик / урезали лимиты, было много бомбежа. Я это тоже заметил, что вынудило меня уйти в Codex за 200 бачей. Но Codex оказался залупой, имхо. Кода он писал много, быстро, красиво. Но не тот. Он всегда был сырой, неполноценный, костыльный, ad hoc. Его планы были такими же поверхностными. С этим я ничего сделать не смог, оформил refund и ушёл на 200 баксов Claude и просидел с ними 2 месяца, потом перешёл на 100-бачевую подписку. Лимиты, кстати, удвоили 6 мая, я к тому моменту уже вернулся.

Второй вид работ

Начался с того, что прогресс замедлился, писалось очень много кода, но долго и без прогресса, тесты зелёные, а расхождений много.

У меня стала вырабатываться насмотренность и понимание того, как я это вижу. Я обнаружил, что ИИ болт клал на разделение слоёв scanner -> parser -> analyze -> transform -> codegen. Он позволял себе parseJs вызывать и в сканере, и в трансформе, и в анализе. Почему? Да потому что у оригинала нет середины: он переоткрывает доменные факты прямо в кодгене, и агент это исправно копировал. Он всё больше портировал, чем следовал нашей архитектуре. Архитектура была такая: «сканнер = сканнит. парсер = парсит и никакого анализа. анализ обходит аст и собирает факты о коде. трансформ только обходит аст и мутирует какие-то его узлы. руны переписывает, ссылки на переменные разворачивает и т. д. кодген генерит итоговый код, без вычисления смыслов, и остаётся тупым». Это было нарушено с нулевой, то, что я не ревьювил.

Также я стал замечать, что ИИ подгоняет результат нашего парсера под ответ. Не код, который генерит, а генерируемый output под наш ответ, со словами «это оригинал багованный». В это я выпал, когда руками прогнал just generate и затем тесты, и было много падений. Пришлось в каждый скилл, claude.md писать сноску, что руками трогать можно, а что нет. Появилась она 23 апреля, дословно: «Never edit by hand case-.json, case-.js files. Only generated by just generate».

Тут начался большой рефакторинг, глазками отсматривал всё. Были выявлены дубли кодгена, парсинг в анализе, анализ в кодгене, размытый трансформ. Странные энамы расползлись по кодовой базе, нарушение ответственности слоёв. Всё это я фиксил ближайший месяц без новых фич, эти проблемы всё ещё есть в виде issue на gh, но их почти не стало.

Обошлось это дорого. 23 апреля один коммит снёс 10 894 строки в крейтах, убил каталог template/, который трогали 767 раз, урезал CLAUDE.md со 165 строк до 47. К 30 апреля из 86 мартовских файлов .rs дожили 48: две трети мартовского кода я стёр.

Также я обратил внимание, что комменты в коде это мусор. Они есть на всё, на каждый чих. Я пытался запретить модели их писать в клод.md, ругался с ним, в скиллах. Это не помогало. Первый takeaway отсюда: существующий код будет повторён моделью, все ваши ограничения для модели это советы, и она ими подотрётся. Поэтому с нулевой позаботьтесь о строгих рамках, чтобы не оставалось техдолга, всего того, что модель будет повторять и тратить ваше время. Комменты я вычистил регуляркой, все. И написал хук, который препятствует написанию их, и это сработало. За всю историю проекта комментариев в crates/**/*.rs было добавлено 10 374 строки и удалено ровно столько же.

Параллельно я пытался найти способ, как следить за прогрессом, что сейчас делать, что не сделано и т. д. Потому что фичей очень много, много опций компилятора, всё пересекается. Я отслеживал всё в ./specs/feature_name.md на тот момент.

Я плохо следил за ними, чек-лист расширялся ИИ от одного из моих скиллов и превратился в мусорку. Вместо чек-листа фич и описания того, что делает эта фича, файлы превратились в реестр тестов и комментариев к ним. Токены тратило, пользы не приносило ни мне, ни модели. Лучше всего это видно на одном файле: 28 марта в нём 141 строка и ноль галочек, 14 мая 138 строк и 99 галочек. Объём тот же.

Третий вид работ. We grinding again boy

Итак, спустя чистку 27 мая, на дворе начало июня, рефакторинг на руках у нас компилятор, только клиентского кода, всё ещё сыроватая анализ-фаза, подчищенный кодген/трансформ от анализа, но всё ещё не полностью. Тестов на тот момент было 1113.

Я решаю написать sweep-утилиту, которая принимает путь до директории и сравнивает все svelte-компоненты с тем как мы его компилируем. Сначала на энтерпрайз базе. Из 7к компонентов успешно скомпилировались ~40. Это была модерн-кодовая база на svelte 5 с вкраплениями legacy-синтаксиса.

Начался гринд, длиною в месяцы. (Тут постфактум я бы отметил, что нужно было гонять sweep на тест кейсах оригинала, позже я так и поступил). Я брал компонент из sweep с расхождениями и кидал его в новый скилл /dig. Суть которого: завести минимальное репро на находку. 1 тест! (к этому вернёмся). И дать результат что не совпало. Под капотом он использовал другой скилл /quick-check, который давал инструкцию агенту как быстро прогнать сравнение с нашим компилятором. Затем следовал оч умный скилл-комбайн, который пытался понять, в чём проблема расхождения, прикинуть реализацию, проверить себя субагентом. И так я двигался к закрытию 7к провалов к 0. На это ушло два месяца, с 9 мая до начала июля. Только клиентский прод-бандл, без dev’а, без ssr.

Тут пришло осознание, сколько всего было упущено в первом виде работ, сколько эдж-кейсов и так далее. Этот процесс мне не удалось автоматизировать, хоть он и был репетативным по большей части, но вылазила куча архитектурных вопросов, которые приходилось решать.

Тогда же мне пришла идея про ReactivitySemantics. Всякие реактивные примитивы были реализованы по куче сырых индексов (хеш таблиц), содержали мириад boolean флагов. А я хотел прийти к схеме, когда кодген/трансформ делает один query по id сущности и получает готовый ответ со всей доменной информацией, чтобы принять все решения. Вместо того чтобы кодген делал так:

if attr_name == "defaultChecked" && has_static_true_boolean_attribute(el, "checked") {    return RegularAttrUpdate::Call { setter_fn: "$.set_default_checked", attr_name: None };}fn has_static_true_boolean_attribute(el: &Element, name: &str) -> bool {    el.attributes        .iter()        .any(|attr| matches!(attr, Attribute::BooleanAttribute(ba) if ba.name == name))}

И из этой мысли вырос потом принцип /verdict-directed: анализ рождает вердикт, а трансформ и кодген по нему выбирают форму и никогда не восстанавливают доменный факт сами, ни по имени узла, ни повторным обходом AST. Появились AttributeSemantics, ReferenceSemantics, BindingSemantics, ElementSemantics, FragmentSemantics, RuntimeSemantics, всё это доменные факты. Чтобы код стремился к такому виду:

query semantic by id -> match exhaustive Semantic -> emit/rewrite

Этот рефакторинг занял тоже много времени, но теперь я стал понимать и замечать полноценно, когда что-то идёт не так. Стало проще следить за ИИ: если он адхоком делает что-то в кодгене, что можно унести в семантику. И агент-ревью /verdict-directed тоже стал заметно лучше и приносил пользу. Также появилась чёткая зависимость между пассами анализа, вместо спагетти кода.

./specs был очищен, на его смену пришёл ./docs/, в котором лежали настоящие specs/prds. Они описывали, как тот или иной кусок системы работает. Например, ReactivitySemantics. За что отвечает, какие основные публичные методы, где находится. Инварианты того что можно и нет. Эти файлы строго ревьювятся по /writing-docs, на предмет воды и мусора, только та инфа, которую тяжело / дорого вывести из кода, т.к. она пронизывает множество систем. Под нее был написан /required. Скилл который грепает теги из ./docs и читает попавшие под греп файлы. Целиком это нововведение дало буст в качестве написания и скорости. Меньше правок были адхок, и чаще они были в нужных местах. Модель есть модель, и порой говнокодила жёстко, с этим можно только смириться.

Sweep закрывал расхождения, долго. А потом я стал прогонять его на тестах оригинального компилятора, и их было всё ещё > 50%. Я решил пересобрать рабочий workflow еще раз.

Был разработан скилл /dig. Его задача была принять файл / директорию, найти расхождение или самое массовое расхождение в инпуте. По этой ниточке выйти в оригинал. Посмотреть на все if/switch/лямбды, которые там есть и написать на них e2e тесты. И выдать резюме о чем была проблема. А затем я в чате давал команду сделать так то или использовал /grill-me чтобы придти к реализации, особенно там где нужно было шатать много кода. Если задача была масштабная, использовал /to-spec -> /to-tickets скиллы, после этого у меня были issue на gh, каждый из которых я реализовывал в отдельной сессии. Всё вместе дало сильную прибавку к паритету и удобству его написания. /grill-me и ещё пару штук я взял готовыми из набора скиллов Matt Pocock, не всё изобретал сам.

Четвёртый вид работ

Первое июля. Читатель, мы уже близко к развязке. Клиентский прод-кодген и трансформ были закончены, тесты оригинала пройдены все. На энтерпрайз-проектах сошлись все 144 тысячи свелт-компонентов.

Пора реализовывать SSR, но с чего начать? Хорошо, что оригинальный SSR использует всё тот же анализ, что и CSR. Было принято решение все существующие тест кейсы e2e превратить и в ssr. А также добавить и dev мод. Общее кол-во тестов было равно кол-ву файлов * 4 (client dev, client prod, ssr dev, ssr prod). По умолчанию ssr были выключены.

С помощью ИИ работа была разбита на кластера, по принципу, что даёт больше всего зелёных тестов. И примерно 2-3 недели заняла реализация SSR. Всё за счёт работ из этапа 3. Первого июля серверных эталонов в репозитории было ноль, шестого 2219 из 2219. Sweep прогнал все 144 тысячи компонентов и тесты оригинала по всем 4м режимам, и все было пройдено.

Где-то тут я заметил, что sweep не учитывал experimental async фичу, и пришлось ещё неделю погриндить и порефачить, реализовав AwaitSemantics.

Профилировал я постоянно компилятор и что-то оптимизировал, но сейчас фокус стал именно на это. Появились опции nativePreprocess, которые позволяют препроцессить TypeScript и SCSS на своей стороне, чтобы меньше делать на JS-стороне. Был собран fork vite plugin и подключен в него компилятор.

@mrwaip/svelte-rs оказался быстрее оригинала в 9-15 раз. И в 3.7–4.9 раза быстрее нативного rsvelte. Blazingly fast, как положено. Это успех!

Пора было тестировать на реальной кодовой базе перфоманс!

Финал

Сейчас 31 июля, vite 8 уже релизнулся, typescript 7 уже релизнулся. В спину дышит rsvelte. Что мы получили после этой огромной работы?

А итог неоднозначный.

Во-первых, на кодовой базе, где vite < 8 и svelte-check без TypeScript 7, это даёт значительный буст. Самый большой проект, 23 тысячи компонентов на vite 7: было 3:37, стало 2:09. Минус 40% с каждой сборки. На маке, на котором 8 гигов, npm run build проходит, когда с оригинальным компилятором он OOM killed. В dev-моде vite стартует быстрее, быстрее пребандлит, быстрее HMR. Это все круто.

Во-вторых, на проектах с vite 8 и svelte-check с —tsgo разница не такая яркая, 8-10 секунд, около 9% сборки, т. к. Rolldown использует параллельность, а всю структуру держит в rust коде, то и памяти ест автоматически меньше и медленный svelte-компилятор не последовательный теперь, а параллелится. И с rust компилятором времени занимает ничтожно мало, 0.2 секунды на все компоненты проекта.

Но секунды тут вообще не главное, и это я понял только в конце.

Главное это память. JS-компилятор аллоцирует AST в той же куче V8, где уже лежит граф модулей. На Rollup это не «медленнее на N секунд», а «собирается или нет».

Второе: компилятор свой, и поэтому в него можно затаскивать что угодно. Препроцессинг SCSS и TypeScript уехал в Rust, sass-embedded выкинут: grass компилирует блок стилей за 2.6 мс против 30. С чужим JS-компилятором такой ход невозможен в принципе.

Третье: там, где бандлера нет, скорость снова начинает значить. Это IDE и svelte-check: 2785 компонентов в цикле, без rolldown, который спрячет разницу.

И четвёртое, самое скучное: это drop-in replacement. Побайтовое совпадение с оригиналом на 144 тысячах компонентов значит, что его можно поставить одной строчкой и снять одной строчкой. Не понравилось, откатился, ничего не сломав.

В первой попытке 108 дней с коммитами и брошенный {#each}. Во второй 106 дней и рабочий компилятор.

Для проекта итог неоднозначный. Для меня однозначный. Я освоил ИИ-агентов как инструмент и прокачался в rust как никогда. Компиляторный мир перестал быть для меня тёмным лесом. И один человек на досуге действительно переписал компилятор svelte.

Да, на старте я не знал про rsvelte. И не знал, что с приходом vite 8 выигрыш станет не таким заметным. Но это всё ещё ускорение проекта в одну строчку.

Код тут: https://github.com/MrWaip/svelte-rs. Это canary, баги есть, мы уже используем его на наших проектах.

Если такой опыт вам интересен, могу потом рассказать конкретнее: про скиллы и хуки, про устройство самого компилятора, про то, как сделан парити-харнесс. Пишите, что было бы полезнее.

А я если честно беру таймаут от этого проекта, я порядком устал. на время, всем Happy Hacking!

ссылка на оригинал статьи https://habr.com/ru/articles/1065708/