Вместо предисловия
Статья будет полезна тем, кто так-же как и Мы решил попробовать Svelte в живом проекте. В нашу небольшую компанию пришёл заказ на разработку веб-админки для сервиса с бекэндом на Mongodb Stitch. В последние пару лет frontend Мы пишем на React или Vue (в зависимости от размера проекта и нужен ли ReactNative), но наслышав о красотах Svelte мы решили попробовать его, чтобы понять для себя так ли он хорош. И может нам тоже стоит дальше использовать его вместо Vue или React?..
Кто такой Svelte ?
Если в двух словах — это новый js фреймворк (но он таким себя не считает), который убийца React и Vue, и бла, бла, бла… В своей статье я хочу рассмотреть Svelte не какой он классный «под капотом», а с точки зрения удобства его использования в реальном проекте.
Мы не делаем машины, мы на них ездим и у нас есть злые заказчики с еще не менее злыми сроками.
Tutorial
Первое с чего Вы начинаете знакомство с новым языком или фреймворков — это туториал на сайте. У Svelte это Svelte.dev/Tutorial.
К сожаление часть туториалов просто не работает на сайте в превью, при этом не совсем понятно работает ли оно в реальности или нет. Приходится тратить время и проверять самому вручную, так как не понятно устарел ли туториал или что-то пошло не так на сайте Svelte. И на это реально тратится очень много времени.
UI Kit и Стили
Поиски UI Kit для Svelte были отдельной болью для всех нас. Хотелось воскликнуть: «Хоть Material, Bootstrap… хоть что нибудь...».
Были найдены только sveltematerialui.com и svelteui.js.org, которые в данный момент выглядели очень сыро.
При простом импорте <Button/>
из него, при сборке вывалилась ошибка из самого пакета, решать ошибки ui kit времени не было.
Пробежав быстро по документации я решил от него отказаться в пользу «Ванилла» импорта из CDN.
В проекте хотелось использовать Material UI, так как возможно админка будет использоваться и с мобильного устройства, а Material очень хорошо для этого подходит (на мой взгляд он даже хуже смотрится на десктопе).
Использование JS без UI Kit вернуло меня мысленно на 10 лет назад ) Паровозы классов и добрая ностальгия ).
Из-за того, что Svelte работает с DOM «по другому» в MaterialUI начали вылазить всякие гадости, связанные с тем как отображаются UI компоненты которые добавляются через js в dom. Например простой спиннер отображается через раз:
После долгих поисков что же пошло не так, выяснилось что спиннер в Material UI, добавляется через JS после того, как документ готов (onLoad) но после этого события Svelte запускает своё добавление в DOM и JS скрипт Material просто его не видит так как событие было раньше.
Лечить это пришлось добавлением в родительский компонент Svelte:
afterUpdate(() => {
componentHandler.upgradeDom();
});
Стилизация
Со стилями все предельно ясно, мы запихиваем все стили в как в Vue. Вы пишите стиль и все в порядке, и потом пишите компонент UI (так как у Вас нет UIKit) который должен принимать параметры props, например width и height, и логично делаете это так:
<script>
export let width = '20px';
export let height = '20px';
</script>
<style>
.loader {
width: { width },
height: { height },
}
</style>
А… нет, в стиле у Вас не получится вставлять переменные. Из этой ситуации Вы можете выкрутится через «ReactWay» и делать динамические стили в как переменные или функции с возвратом стиля.
В итоге у нас опять каша, часть стиля в style часть в script. Чистый код получится только в том случае если у Вас нет параметров в стилях или у Вас только динамические параметры и они только в script.
Routing и ротуеры
Без нормального роутера Вы не сможете сделать даже one page app.
React, Vue при скалфолдинге 'Hello World' проекта уже идут с роутером в коробке (или можно его выбрать). Но как и всё в Svelte — это дается не просто.
Нужно выбрать роутер самому, да и еще между очень похожими решениями. По правде говоря пока есть всего два роутера github.com/EmilTholin/svelte-routing и github.com/kazzkiq/svero
Оба очень похожи но я выбрал первый, выбирал по количеству звезд (да я знаю, я ужасный человек ).
Итак начнем его встраивать в наш MDL.
Обернем всё в <Router url="{url}"> и Добавим <Link/> для ссылок из навигации.
Переходим в превью и смотрим, что получилось.
А получилось то, что детские болезни Svelte продолжаются и в <Link/> нельзя передавать классы. Возник резонный вопрос а как Вы его будете стилизировать?
Видимо это все еще в issues для роутера.
К счастью Мы можем привязать к роутеру наш обычный a href=‘’ указав use:link за что отдельная благодарность.
Ошибки
В отличии от React который просто не даст Вам создать bundle и будет сильно «кричать» об ошибке, Svelte отлично соберёт всё с ошибкой. При этом если Вы забыли что-то npm install'нуть или export'ануть, все отлично соберется и просто покажет белый экран (Кстати говоря так было в первых версиях React).
В React и Vue, Мы привыкли видеть такие ошибки еще на этапе билда или линта.
В тоге Вам придется отлавливать ошибки в двух местах. Справедливости ради — это есть в React и Vue, но гораздо реже и такие явные ошибки ловятся еще на стадии линта.
Svelte просто необходим naming convention
C этой проблемой Вы будете сталкиваться довольно часто — с отсутствием конвенции по наименованию.
Например, вернемся к роутеру.
Есть вот такой импорт:
import { Router, link, Link ,Route } from "svelte-routing";
Что из этого Link и link? Даже в таком маленьком проекте как у меня, уже возникла путаница с отсутствием конвенций имен в проектах используемых в Svelte.
Конечно это должно было выглядеть в глазах ReactМэна вот так:
import { Router, useLink, LinkComponent ,RouteComponent } from "svelte-routing";
В Svelte есть подобие ref как в react’е, это ссылка на элемент dom или компонент.
Официальный туториал гласит нам сделать это так:
<script>
let dialog;
</script>
<dialog bind:this={dialog} class="mdl-dialog» />
А если у Вас будет 15 переменных в компоненте?
<script>
let loading;
let pins;
let dialog;
let stitch;
</script>
<dialog bind:this={dialog} class="mdl-dialog» />
Где и что из этого действительно переменные, а где ссылки на компоненты или элементы?
Я бы изменил туториал и сделал примеры более правильными с точки зрения новичков и их конвенции переменных (см Туториал React для хорошего примера). Если Вы даёте делать винегрет переменных, было бы неплохо чтобы linter или bundler ругался на такой винегрет, как например, это сделано у golang.
<script>
let dialogElement;
</script>
<dialog bind:this={dialogElement} class="mdl-dialog» />
Еще один пример «из жизни», когда Вы получаете какие-то данные в функции компонента и эти данные нужно отправить в Ваш View, где к части елемента UI у Вас прикручена какая-то переменная. И выглядит это у нас (вернее у нашего программиста) вот так:
async function ReloadPins() {
loading = true;
pins = await getAllPins();
status = 0;
}
Когда я открыл его код, мне сразу «стало понятно», что здесь переменная которая state и какая из них привязана к нашему UI.
Шучу, конечно же ничего не ясно. Причем даже не понятно меняется состояние или это просто вспомогательная переменная. В React это решается state, который хоть как-то вносит ясности.
Что где изменилось и кто это сделал ?
Переменные внутри Svelte компонента — глобальные и меняются они везде (привет Angular).
Но есть и хорошая новость, они глобальны внутри одного компонента (пока Angular), поэтому это изменение всех и всеми не так уж и страшно внутри одного компонента.
При этом Вы экономите время на «красоте» кода и не размышляете, что Вам сделать state переменной, а что оставить внутри функции (привет React) — у Вас все и везде.
В итоге Вы быстро пишете компоненты но понять, что написал джуниор в этом «венегрете» через несколько дней когда он сам уже забыл (иногда даже как его зовут) бывает очень сложно. Из-за этого будет невозможно понять что внутри без четкой организации кода внутри проекта или команды.
Привязываем Stitch
Stitch — отличная штука и я обязательно расскажу о ней подробнее, и сравню с аналогами, померяем тесты в продакшене в своей следующей статье, а сейчас все таки больше про Svelte.
Чтобы использовать Stitch Вам прийдется пойти по «Ванильному» пути и вставить:
<script src="https://s3.amazonaws.com/stitch-sdks/js/bundles/4.4.0/stitch.js"></script>
Так как при использовании npm и нормального import пакета, начинается проблема с ошибкой buffer.
Не знаю связанно ли это со сборщиком Svelte или самим Stitch, или еще c чем-то, но времени ковырять у меня не было и пришлось просто добавить script с импортом, после чего всё успешно заработало.
Это основные проблемы с которыми мы столкнулись при работе со Svelte. И сказать честно — в общем нам не понравилось, причём никому…
Что в итоге:
Для чего Вам пригодится Svelte ?
- Если Вы работаете один и Вам срочно нужно сделать MVP или не больше админку. С большой админкой будут проблемы так как при написании нового кода Вы забудете старый или нужно обязательно писать само-документированный код, так как Svelte не «заставляет» Вас это делать.
- Если размер bundle Вам очень важен. Например, Вы делаете веб-app для страны в которой всё еще нет 3G или интернет очень медленный и очень дорогой. В большей части мира дорогие программисты, а не интернет, поэтому размер bundle в разумных пределах не будет актуальной проблемой в 99% случаев.
- Если Вы только начинаете учиться писать на JS и делать фронтенд Svelte даст Вам всю свободу «выстрелить в ногу», в соседа по парте или устроить массовую стрельбу по ногам. На самом деле Вам не нужно будет учить JSX или долго разбираться в конвенциях кода, Вы сразу можете сделать Ваш первый фронтенд проект и увидеть, что у Вас уже что-то получилось и что-то даже работает.
Исходя из последнего я совсем не понимаю зачем мэйнтэйнеры Svelte собираются делать поддержку TypeScript? Мы же любим Svelte как раз за «стрельбу по ногам» и TypeScript на мой взгляд это как вседорожные гусеницы для спорткара Svelte. И знаете, поработав со Svelte, я понял на сколько сильно за последние годы изменился JS, и что он совсем уже не JS.
Svelte даёт возможность поработать в еще том, старом и ламповом JS, без PropTypes, Flow и TypeScript.
Что мне понравилось ?
- Хорошо читаемые if/else, чего нет в Vue. Я бы очень хотел увидеть что-то похожее в Vue.
- Можно создавать свои event в компонентах и избавится от передачи в child коллбэков функции, для коммуникации между child > parent.
Почему не стоит использовать Svelte ?
- Нет ни одного полностью рабочего UI Kit. Трудно представить себе web app без UIKit, написать самим UI Kit могут позволить себе только крупные проекты, для которых как раз Svelte мало подходит. Прикручивание чего-то ванильного переходит в создание своих UI компонентов (своего UI Kit) или в борьбу с ошибками и «паровозами» классов.
- Не явность части простых ошибок, и отлова их только на этапе тестирования.
- Если Вы собрались делать мульти-платформенное приложение (а сейчас везде mobile first), Вам прийдется все переписывать на ReactNative или допиливать руками сгенерированный NativeScript (есть генератор NS из Svelte). Справедливости ради у Vue с мобильной разработкой тоже всё не очень хорошо, но она есть и кое-как рабочая.
- Вам прийдется позаботится о написании очень четкой конвенции кода для своих разработчиков в проекте, так как туториал и примеры не сделаны для командной разработки.
Автор: Maksym Geek