Пост о том, как я переписал сайт с Tilda на Rust и что из этого вышло.
Как всё начиналось
Год назад мы с друзьями запустили небольшой проект CyberBusinessLeague - платформу для организации киберспортивных турниров между юридическими лицами.
На старте было много организационных задач, поэтому решили не распыляться и сделать лендинг на Tilda. Он решал свои задачи: простые страницы, анонсы, формы - и в целом прожил с нами год.
Но этим летом нас пригласили провести кибертурнир по Dota 2 на форуме «Мой бизнес 2025», и старый, угловатый сайт на Tilda перестал отвечать нашим требованиям и просто стал бить по репутации.
Решили, что пора что-то менять.
Почему вообще Rust?
Так как в команде был человек с технической экспертизой - то есть я :-)
Хотелосьпереписать сайт на чём‑то «своём»: лёгком, кастомизируемом и без зависимости от платформ. Мы рассматривали разные связки:
фронт - SvelteKit, Solid.js, etc
бэк - Go, Python и т. д.
По правде надо сказать, что я довольно давно работаю в разработке, но к фронтеду у меня было очень опосредованное отношение, верстать что-то очень простое я когда-то учился, но на этом мои полномочия все, и JS я тоже плохо знал.
Но у меня уже был опыт с Rust, и я подумал что "риск дело благородное".
Так и родилась идея сделать всё на Rust + Leptos.
Почему именно Leptos?
До этого момента у меня был опыт с Dioxus, но после небольшого ресерча стало понятно, что у Leptos лучше поддержка SSR(server side rendering), а значит меньше время до первого отображения контента и компактнее wasm-бандл. Для наших задач - идеально.
Процесс
Следующие несколько вечеров были потрачены на написание сайта.
Всего сайт содержит около 10–12 страниц, поэтому я сделал его полностью статическим.
Бэк ничего не хранит, сборка - это просто один Dockerfile с бинарником и статикой.
Leptos отлично дружит с Axum, и получается аккуратная интеграция SSR + роутинга.
Вот пример кода, который инициализирует маршрутизацию и добавляет GZIP-компрессию:
let app = Router::new()
.leptos_routes(&leptos_options, routes, {
let leptos_options = leptos_options.clone();
move || shell(leptos_options.clone())
})
.fallback(leptos_axum::file_and_error_handler(shell))
.with_state(leptos_options)
.layer(CompressionLayer::new().gzip(true));
На всё ушло около 20–30 часов, из которых две трети я провёл в диалоге с Claude Code, который помогал с версткой.
Что получилось
Сайт крутится на самой слабенькой виртуалке, которую я смог найти:
512 MB RAM, 1 shared vCPU, 400 ₽/мес
(для сравнения: Tilda - ~1200 ₽/мес)
CPU загрузка не превышает 3%, даже с SSR
RAM - до 10%
wasm-бандл - около 350 KB
Сравнение
С одной стороны это не то место где стоит оценивать какой-то перформанс, не те масштабы, но было интересно как поведет себя сайт полностью написанный на rust.

Скорость загрузки осталась примерно на том же уровне, но я неожиданно понял,что сайт на Rust получился дружелюбнее к SEO, чем версия на Tilda. И это стало для меня главным откровением - видимо, конструкторы далеко не всегда оптимизируют страницы идеально.

Стереотипы и реальные проблемы
Один из самых живучих стереотипов про Rust — это «медленная компиляция». От части так и есть, но почти всегда можно решить этот вопрос или сократить его влияние на твою работу.
В моем случае всё было гораздо проще: у Leptos есть livereload режим.
Он пересобирает проект на лету, и результат виден практически сразу.
cargo leptos watch
А вот релизная сборка действительно доставила проблем, на моем стареньком MacBook Air M1 я получал ошибку линковки:
ld: Assertion failed: (name.size() <= maxLength), function makeSymbolStringInPlace, file SymbolString.cpp, line 74.
Это означает, что линковщик ld пытается создать объект с именем, которое превышает максимально допустимую длину. Leptos в процессе сборки генерирует довольно длинные имена на которые ругается линкер и это довольно известная проблема в сообществе.
Попытка заменить его на clang ничего не дала.
[target.aarch64-apple-darwin]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
В прочем у меня еще были идеи попробовать альтернативные линкеры mold или lld, или уменьшить оптимизации, но в угоду скорости я не стал разбираться с этой проблемой, а просто собирал релиз в Docker - там всё проходило без проблем.
Итог
Спустя некоторое количество вечером мы получили вполне работоспособный сайт, который отвечает нашим требованиям в данный момент.
Конечно, Rust не предлагает того же уровня инфраструктуры и готовых компонентов, как мир JS, но писать на нём в разы интереснее. Ну и в целом проект был сделан больше как баловство, но для меня было интересно увидеть некоторое «сравнение» и ответить себе на вопрос «А можно ли?».
Не смотря на то что сама по себе целесообразность всего мероприятия довольно сомнительная.
После этого опыта я понял, что, пожалуй, не стал бы учить React/Vue/etc только ради фронта, потому что rust так же может решать часть этих задач. К слову у меня ни разу за пару лет использования rust не возникало ситуации, чтобы я не понимал что делает мой код, а вот с python, go — у меня такие эпизоды были.
Жизнь слишком коротка, чтобы тратить ее исключительно рационально, иногда нужно что‑то сделать потому что просто хочется.
Закончить хочется словами классика:
Никогда не забывайте заниматься фигнёй. Потому, что фигня — это оценочное суждение людей, которые не видят в вашей деятельности выгоды.
Но, занимаясь фигнёй, вы исследуете мир, открываете новые пространства и способны найти ту форму взаимодействия с миром, которая сделает вас счастливым.
Всем спасибо!
Комментарии (5)

Hovs Автор
21.11.2025 10:25Вы правы! Ну вот мне интуитивно казалось, что они должны были эту проблему решать лучше, чем я ожидал, поэтому и удивился.

cupraer
21.11.2025 10:25Вы не создали сайт на расте. Вы создали генератор статического сайта на расте. Которых, наверное, и так — вагон и маленькая тележка, в принципе, но я лично уважаю велосипедостроение.
не стал бы учить React/Vue/etc только ради фронта, потому что rust так же может решать часть этих задач
Не может. То, что некоторые альтернативно одаренные товарищи считают, что статику тоже лучше делать реактивной, — ничего не означает.

DanriWeb
21.11.2025 10:25Статья классная — в целом всё верно, а нюансы вроде SEO/SSR и экосистемы Rust vs JS тут и так думаю знающим понятны. Важнее, что это честный опыт «сделал потому что хотел», а такие истории всегда приятно читать :)
Ydav359
Конструкторы вообще очень сильно ограничивают то, что можно было бы прописать руками в meta и т.д.
Hovs Автор
Вы правы! Ну вот мне интуитивно казалось, что они должны были эту проблему решать лучше, чем я ожидал, поэтому и удивился.