Svelte — сравнительно новый UI фреймворк, разработанный Ричем Харрисом, который также является автором сборщика Rollup. Скорее всего Svelte покажется совершенно не похожим на то, с чем вы имели дело до этого, но, пожалуй, это даже хорошо. Две самые впечатляющие особенности этого фреймворка — скорость и простота. В этой статье мы сосредоточимся на второй.
Поскольку мой основной опыт разработки связан с Angular, вполне естественно, что я пытаюсь изучить Svelte, копируя уже привычные мне подходы. И именно об этом будет рассказано в этой статье: как в Svelte делать те же самые вещи, что и в Angular.
Примечание: Не смотря на то, что в ряде случаев я буду высказывать своё предпочтение, статья не является сравнением фреймворков. Это простое и быстрое введение в Svelte для людей, которые уже используют Angular в качестве своего основного фреймворка.
Внимание спойлер: Svelte — это весело.
Компоненты
В Svelte каждый компонент соотносится с файлом, где он написан. Например, компонент Button
будет создан путем присвоения имени файлу Button.svelte
. Конечно, мы обычно делаем то же самое в Angular, но у нас это просто соглашение. (В Svelte имя импортируемого компонента также может не совпадать с именем файла — примечание переводчика)
Компоненты Svelte однофайловые, и состоят из 3 разделов: script
, style
и шаблон, который не нужно оборачивать ни в какой специальный тег.
Давайте создадим очень простой компонент, который показывает "Hello World".
Импортирование компонентов
В целом это похоже на импортирование JS-файла, но с парой оговорок:
- необходимо явно указывать расширение файла компонента
.svelte
- компоненты импортируются внутри тега
<script>
<script>
import Todo from './Todo.svelte';
</script>
<Todo></Todo>
Из приведенных выше фрагментов очевидно, что количество строк для создания компонента в Svelte невероятно мало. Конечно, присутствуют некоторые неявности и ограничения, но при этом всё достаточно просто, чтобы быстро к этому привыкнуть.
Базовый синтаксис
Интерполяции
Интерполяции в Svelte больше схожи с таковыми в React, нежели в Vue или Angular:
<script>
let someFunction = () => {...}
</script>
<span>{ 3 + 5 }</span>
<span>{ someFunction() }</span>
<span>{ someFunction() ? 0 : 1 }</span>
Я привык использовать двойные фигурные скобки, так что иногда опечатываюсь, но, возможно, такая проблема только у меня.
Атрибуты
Передать атрибуты в компоненты также довольно просто. Кавычки не обязательны и можно использовать любые Javascript-выражения:
//Svelte
<script>
let isFormValid = true;
</script>
<button disabled={!isFormValid}>Отправить</button>
События
Синтаксис обработчиков событий выглядит так: on:событие={обработчик}
.
<script>
const onChange = (e) => console.log(e);
</script>
<input on:input={onChange} />
В отличие от Angular, нам не нужно использовать скобки после имени функции, чтобы вызывать её. Если нужно передать аргументы в обработчик, просто используем анонимную функцию:
<input on:input={(e) => onChange(e, ‘a’)} />
Мой взгляд на читабельность такого кода:
- Печатать приходится меньше, поскольку нам не нужны кавычки и скобки — это в любом случае хорошо.
- Читать сложнее. Мне всегда больше нравился подход Angular, а не React, поэтому для меня и Svelte здесь воспринимается тяжелее. Но это просто моя привычка и мое мнение несколько предвзято.
Структурные директивы
В отличие от структурных директив в Vue и Angular, Svelte предлагает специальный синтаксис для циклов и ветвлений внутри шаблонов:
{#if todos.length === 0}
Список дел пуст
{:else}
{#each todos as todo}
<Todo {todo} />
{/each}
{/if}
Мне очень нравится. Нет необходимости в дополнительных HTML элементах, и с точки зрения читаемости это выглядит потрясающе. К сожалению, символ #
в британской раскладке клавиатуры моего Macbook находится в труднодоступном месте, и это негативно сказывается на моем опыте работы с этими структурами.
Входные свойства
Обозначить свойства, которые можно передать компоненту (аналог @Input
в Angular) так же легко, как экспортировать переменную из JS модуля при помощи ключевого слова export
. Пожалуй, поначалу это может сбивать с толку — но давайте напишем пример и посмотрим, насколько это действительно просто:
<script>
export let todo = { name: '', done: false };
</script>
<p>
{ todo.name } { todo.done ? '?' : '?' }
</p>
- Как вы могли заметить, мы инициализировали свойство
todo
вместе со значением: оно будет являться значением свойства по умолчанию, в случае если оно не будет передано из родительского компонента
Теперь создадим контейнер для этого компонента, который будет передавать ему данные:
<script>
import Todo from './Todo.svelte';
const todos = [{
name: "Изучить Svelte",
done: false
},
{
name: "Изучить Vue",
done: false
}];
</script>
{#each todos as todo}
<Todo todo={todo}></Todo>
{/each}
Аналогично полям в обычном JS-объекте, todo={todo}
можно сократить и переписать код следующим образом:
<Todo {todo}></Todo>
Сначала мне казалось это странным, но теперь я думаю, что это гениально.
Выходные свойства
Для реализации поведения директивы @Output
, например, получения родительским компонентом каких-либо уведомлений от дочернего, мы будем использовать функцию createEventDispatcher
, которая имеется в Svelte.
- Импортируем функцию
createEventDispatcher
и присваиваем её возвращаемое значение переменнойdispatch
- Функция
dispatch
имеет два параметра: имя события и данные(которые попадут в полеdetail
объекта события) - Помещаем
dispatch
внутри функцииmarkDone
, которая вызывается по событию клика (on:click
)
<script>
import { createEventDispatcher } from 'svelte';
export let todo;
const dispatch = createEventDispatcher();
function markDone() {
dispatch('done', todo.name);
}
</script>
<p>
{ todo.name } { todo.done ? '?' : '?' }
<button on:click={markDone}>Выполнено</button>
</p>
В родительском компоненте нужно создать обработчик для события done
, чтобы можно было отметить нужные объекты в массиве todo
.
- Создаём функцию
onDone
- Присваиваем эту функцию обработчику события, которое вызывается в дочернем компоненте, таким образом:
on:done={onDone}
<script>
import Todo from './Todo.svelte';
let todos = [{
name: "Изучить Svelte",
done: false
},
{
name: "Изучить Vue",
done: false
}];
function onDone(event) {
const name = event.detail;
todos = todos.map((todo) => {
return todo.name === name ? {...todo, done: true} : todo;
});
}
</script>
{#each todos as todo}
<Todo {todo} on:done={onDone}></Todo>
{/each}
Примечание: для запуска обнаружения изменения объекта, мы не мутируем сам объект. Вместо этого мы присваиваем переменной todos
новый массив, где объект нужной задачи уже будет изменен на выполненный.
Поэтому Svelte и считается по-настоящему реактивным: при обычном присваивании значения переменной изменится и соответсвующая часть представления.
ngModel
В Svelte есть специальный синтаксис bind:<атрибут>={переменная}
для привязки определенных переменных к атрибутам компонента и их синхронизации между собой.
Иначе говоря, он позволяет организовать двухстороннюю привязку данных:
<script>
let name = "";
let description = "";
function submit(e) { // отправка данных формы }
</script>
<form on:submit={submit}>
<div>
<input placeholder="Название" bind:value={name} />
</div>
<div>
<input placeholder="Описание" bind:value={description} />
</div>
<button>Добавить задачу</button>
</form>
Реактивные выражения
Как мы уже видели ранее, Svelte реагирует на присваивание значений переменным и перерисовывает представление. Также можно использовать реактивные выражения, чтобы реагировать на изменение значения одной переменной и обновлять значение другой.
Например, давайте создадим переменную, которая должна показывать нам, что в массиве todos
все задачи отмечены как выполненные:
let allDone = todos.every(({ done }) => done);
Однако, представление не будет перерисовываться при обновлении массива, потому что значение переменной allDone
присваивается лишь единожды. Воспользуемся реактивным выражением, которое заодно напомнит нам о существовании "меток" в Javascript:
$: allDone = todos.every(({ done }) => done);
Выглядит весьма экзотично. Если вам покажется, что тут "слишком много магии", напомню, что метки — это валидный Javascript.
Небольшое демо, поясняющее вышесказанное:
Внедрение содержимого
Для внедрения содержимого тоже применяются слоты, которые помещаются в нужное место внутри компонента.
Для простого отображения контента, который был передан внутри элемента компонента, используется специальный элемент slot
:
// Button.svelte
<script>
export let type;
</script>
<button class.type={type}>
<slot></slot>
</button>
// App.svelte
<script>
import Button from './Button.svelte';
</script>
<Button>
Отправить
</Button>
В этом случае строка "Отправить"
займет место элемента <slot></slot>
.
Именованным слотам потребуется присвоить имена:
// Modal.svelte
<div class='modal'>
<div class="modal-header">
<slot name="header"></slot>
</div>
<div class="modal-body">
<slot name="body"></slot>
</div>
</div>
// App.svelte
<script>
import Modal from './Modal.svelte';
</script>
<Modal>
<div slot="header">
Заголовок
</div>
<div slot="body">
Сообщение
</div>
</Modal>
Хуки жизненного цикла
Svelte предлагает 4 хука жизненного цикла, которые импортируются из пакета svelte
.
- onMount — вызывается при монтировании компонента в DOM
- beforeUpdate — вызывается перед обновлением компонента
- afterUpdate — вызывается после обновления компонента
- onDestroy — вызывается при удалении компонента из DOM
Функция onMount
принимает в качестве параметра callback-функцию, которая будет вызвана, когда компонент будет помещен в DOM. Проще говоря, она аналогична действию хука ngOnInit
.
Если callback-функция возвращает другую функцию, то она будет вызвана при удалении компонента из DOM.
<script>
import {
onMount,
beforeUpdate,
afterUpdate,
onDestroy
} from 'svelte';
onMount(() => console.log('Смонтирован', todo));
afterUpdate(() => console.log('Обновлён', todo));
beforeUpdate(() => console.log('Сейчас будет обновлён', todo));
onDestroy(() => console.log('Уничтожен', todo));
</script>
Важно помнить, что при вызове onMount
все входящие в него свойства уже должны быть инициализированы. То есть в фрагменте выше todo
уже должно существовать.
Управление состоянием
Управлять состоянием в Svelte невероятно просто, и, пожалуй, эта часть фреймворка мне симпатизирует больше остальных. Про многословность кода при использовании Redux можно забыть. Для примера, создадим хранилище в нашем приложении для хранения и управления задачами.
Записываемые хранилища
Сначала нужно импортировать объект хранилища writable
из пакета svelte/store
и сообщить ему начальное значение initialState
import { writable } from 'svelte/store';
const initialState = [{
name: "Изучить Svelte",
done: false
},
{
name: "Изучить Vue",
done: false
}];
const todos = writable(initialState);
Обычно, я помещаю подобный код в отдельный файл вроде todos.store.js
и экспортирую из него переменную хранилища, чтобы компонент, куда я его импортирую мог работать с ним.
Очевидно, что теперь объект todos
стал хранилищем и более не является массивом. Для получения значения хранилища воспользуемся небольшой магией в Svelte:
- Добавлением символа
$
к имени переменной хранилища мы получаем прямой доступ к его значению!
Таким образом, просто заменим в коде все упоминания переменной todos
на $todos
:
{#each $todos as todo}
<Todo todo={todo} on:done={onDone}></Todo>
{/each}
Установка состояния
Новое значение записываемого хранилища может быть указано вызовом метода set
, которое императивно изменяет состояние согласно переданному значению:
const todos = writable(initialState);
function removeAll() {
todos.set([]);
}
Обновление состояния
Для обновления хранилища (в нашем случае todos
), основываясь на его текущем состоянии, нужно вызвать метод update
и передать ему callback-функцию, которая будет возвращать новое состояние для хранилища.
Перепишем функцию onDone
, которую мы создали ранее:
function onDone(event) {
const name = event.detail;
todos.update((state) => {
return state.map((todo) => {
return todo.name === name ? {...todo, done: true} : todo;
});
});
}
Здесь я использовал редьюсер прямо в компоненте, что является плохой практикой. Переместим его в файл с нашим хранилищем и экспортируем из него функцию, которая просто будет обновлять состояние.
// todos.store.js
export function markTodoAsDone(name) {
const updateFn = (state) => {
return state.map((todo) => {
return todo.name === name ? {...todo, done: true} : todo;
});
});
todos.update(updateFn);
}
// App.svelte
import { markTodoAsDone } from './todos.store';
function onDone(event) {
const name = event.detail;
markTodoAsDone(name);
}
Подписка на изменение состояния
Для того, чтобы узнать, что значение в хранилище изменилось, можно использовать метод subscribe
. Имейте ввиду, что хранилище не является объектом observable
, но предоставляет схожий интерфейс.
const subscription = todos.subscribe(console.log);
subscription(); // так можно отменить подписку
Observables
Если эта часть вызывала у вас наибольшие волнения, то спешу обрадовать, что не так давно в Svelte была добавлена поддержка RxJS и пропозала Observable для ECMAScript.
Как разработчик на Angular, я уже привык работать с реактивным программированием, и отсутствие аналога async pipe было бы крайне неудобным. Но Svelte удивил меня и тут.
Посмотрим на пример совместной работы этих инструментов: отобразим список репозиториев на Github, найденных по ключевому слову "Svelte"
.
Вы можете скопировать код ниже и запустить его прямо в REPL:
<script>
import rx from "https://unpkg.com/rxjs/bundles/rxjs.umd.min.js";
const { pluck, startWith } = rx.operators;
const ajax = rx.ajax.ajax;
const URL = `https://api.github.com/search/repositories?q=Svelte`;
const repos$ = ajax(URL).pipe(
pluck("response"),
pluck("items"),
startWith([])
);
</script>
{#each $repos$ as repo}
<div>
<a href="{repo.url}">{repo.name}</a>
</div>
{/each}
<!--
Имплементация в Angular:
<div *ngFor="let repo of (repos$ | async)>
<a [attr.href]="{{ repo.url }}">{{ repo.name }}</a>
</div>
-->
Просто добавляем символ $
к имени observable-переменной repos$
и Svelte автомагически отображает её содержимое.
Мой список пожеланий для Svelte
Поддержка Typescript
Как энтузиаст Typescript, я не могу не пожелать возможности использования типов в Svelte. Я так привык к этому, что порой увлекаюсь и расставляю типы в своём коде, которые потом приходится убирать. Я очень надеюсь, что в Svelte скоро добавят поддержку Typescript. Думаю этот пункт будет в списке пожеланий любого, кто соберётся использовать Svelte имея опыт работы с Angular.
Соглашения и гайдлайны
Отрисовка в представлении любой переменной из блока <script>
— очень мощная возможность фреймворка, но на мой взгляд, может привести к замусориванию кода. Я надеюсь, что сообщество Svelte проработает ряд соглашений и гайдлайнов, чтобы помочь разработчикам писать чистый и понятный код компонентов.
Поддержка сообществом
Svelte — грандиозный проект, который, при увеличении усилий со стороны сообщества в написании сторонних пакетов, руководств, статей в блогах и прочим, может взлететь и стать признанным инструментом в удивительном мире Frontend-разработки, который мы имеем сегодня.
В заключение
Несмотря на то, что я не был поклонником предыдущей версии фреймворка, Svelte 3 произвёл на меня хорошее впечатление. Он простой, небольшой, но умеет очень многое. Он настолько отличается от всего вокруг, что напомнил мне тот восторг, который я испытал, когда перешёл с jQuery на Angular.
Вне зависимости от того, какой фреймворк вы используете сейчас, изучение Svelte, скорее всего, отнимет лишь пару часов. Как только вы узнаете основы и поймёте различия с тем, что вы уже привыкли писать, работать со Svelte станет очень легко.
В русскоязычном Telegram-канале @sveltejs вы обязательно найдёте разработчиков, имеющих опыт работы с различными фреймворками и готовых поделится своими историями, мыслями и советами касательно Svelte.
Комментарии (49)
mamont80
12.09.2019 08:03Как раз нахожусь перед выбором шаблонизатора для небольшого проекта. Svelte интересная вещь для не очень навороченных интерфейсов, где Angular или React избыточны, но пока имеет 2 существенных для меня недостатка: он не typescript-френдли и сложность отладки из-за плохой поддержки со стороны IDE. И то и другое меня пугает, это шаг назад. Так что да, но наверное пока нет.
PaulMaly
12.09.2019 09:24Svelte намного мощнее React, поэтому довольно странно что вы ставите его в ряд с Angular, который мощнее Svelte. Поддержка TS базовая имеется (без шаблонов) с помощью препроцессоров. Ну и конечно же не понятно зачем TS если вы сами пишете не очень навороченных интерфейсов?
vintage
14.09.2019 09:22typescript-френдли
Боюсь нормально интергрируется с TS лишь один шаблонизатор — JSX. И то с ограничениями. Всё остальное нормально с тайпскриптом не интегрируется, пока MS не добавит в него хотя бы поддержку трансформаций до тайпчекинга.
JustDont
14.09.2019 09:31Да вы что. Всё, что основано на tagged template literals — внезапно, тоже нормально интегрируется и не жужжит.
vintage
14.09.2019 09:44Что, и подсказки в именах компонент и их свойств в строковых литералах работают?
JustDont
14.09.2019 09:51-1А должны?
Вы, фактически, тут просите TS поработать на разбор HTML. TS не умеет разбирать HTML.vintage
14.09.2019 13:27+3TS умеет в плагины, только сейчас они отрабатывают после тайпчека. Если бы их можно было применять к AST до тайпчека, то можно было бы расширять тайпскрипт любым синтаксисом.
JustDont
15.09.2019 10:09-1Конечно умеет. Дело в том, что TS в общем виде и не должен разбираться с HTML — зачем это ему? Это ж не проект универсального парсера и лексера всего на свете. Артефакты другого языка уместнее разбирать соответствующим инструментом.
JustDont
12.09.2019 08:17Смотрел сам примерно 8 месяцев назад, выводы точно такие же: стильно, модно, молодёжно, но в продакшн — извините. Только когда (если) будет TS и вменяемая поддержка через IDE. Хотя за пределами этого проблем вроде б нет, и даже транспилируется оно всё до веб-компонентов — а это значит, что в целом будет уживаться с остальным миром, хотя вот в сабже всё такая же убогая закрытость css от внешнего доступа, как и в css modules и shadow dom (пока что, пока :part и :theme не взлетят), и это тоже в серьезном коде будет страшно мешать.
PaulMaly
12.09.2019 09:19Смотрел сам примерно 8 месяцев назад, выводы точно такие же: стильно, модно, молодёжно, но в продакшн — извините.
NYT, GoDaddy, Яндекс.Деньги и Mail.Ru почему-то решили что норм. ;-) Но это ваше право конечно.JustDont
12.09.2019 09:42NYT, GoDaddy, Яндекс.Деньги и Mail.Ru почему-то решили что норм. ;-)
Argumentum ad verecundiam. Придумайте что-нибудь поинтереснее. Пока что вы слишком похожи на Wrike, которые со своим «нам не хочется признаваться, что dart был выбран по большей части от безысходности на тот момент, а поэтому будем топить за то, что это аж сам Хухл изобрел!».PaulMaly
12.09.2019 17:45Знаете, мне то пишут что мол никто не использует из известных компаний, значит не готово для прода. А когда пишу кто в итоге использует, ретируются с ответов вроде вашего. Всем не угодишь.
Вы, в целом тоже не блещите своей аргументацией ни в предыдущем комментарии, ни в других комментариях к другим статьям. Так что извините.JustDont
12.09.2019 21:46Вы, в целом тоже не блещите своей аргументацией ни в предыдущем комментарии, ни в других комментариях к другим статьям.
Я и не собирался блистать, всего лишь назвал критичные на мой взгляд недостатки. На что вы рассчитываете, когда на «нет TS и поддержки IDE» вы в ответ пишете «зато этим всякие условно-важные конторы пользуются»?
От того, что сабж где-то среди всего Mail.Ru применили — появилась поддержка TS, или что?
И эти люди будут мне за аргументацию чего-то объяснять, ага.PaulMaly
13.09.2019 11:38Учитывая что вы даже не в курсе про сорс-мапы, кажется глубина вашего погружения была недостаточная, чтобы оценить какая поддержка TS или IDE имеется на данный момент. 8 месяцев назад это очень давно, тогда еще и Svelte 3 то не было.
И опять же, причем тут TS если статья находится в хабе по JS и имеет тег JS. Можно с таким же успехом прийти и про CoffeScript затирать. Любите TS любите дальше, никто вас ни к чему не призывает, но не обязательно пытаться его присунуть везде где он не нужен.JustDont
13.09.2019 14:59была недостаточная, чтобы оценить какая поддержка TS или IDE имеется на данный момент
Так и какая?
И опять же, причем тут TS
При том, что лично я отношу отсутствие поддержки TS к существенным недостаткам. При чём тут хабы и теги?PaulMaly
13.09.2019 16:29Так и какая?
Нормальная поддержка IDE. TS поддерживается в скриптах, в шаблонах нет, но можно и минимизировать выражения в шаблонах и не использовать автоматические биндинги.
При том, что лично я отношу отсутствие поддержки TS к существенным недостаткам. При чём тут хабы и теги?
Потому что это 2 разных языка. Это как сейчас набегут адепты Elm в статью по React и начнут ныть, что React не поддерживает Elm.JustDont
13.09.2019 16:49Нормальная поддержка IDE.
Я вижу WIP Language Server с открытыми issues в духе «TS не поддерживается» и «Language server молча падает». На моем языке это называется «поддержка IDE начинает появляться».
TS поддерживается в скриптах, в шаблонах нет, но можно и минимизировать выражения в шаблонах и не использовать автоматические биндинги.
Вот это говорит мне о том, что таки «TS не поддерживается». То, что можно проявить некоторую ловкость рук, и намазать TS отдельным слоем сборки над всей конструкцией — это нельзя назвать поддержкой.
Потому что это 2 разных языка.
И?
На всякий случай, если вы с первого раза не прочитали: «назвал критичные на мой взгляд недостатки». По каким причинам лично вы считаете это не важным или недостаточно важным — мне совершенно неинтересно.PaulMaly
13.09.2019 20:14Я вижу WIP Language Server с открытыми issues в духе «TS не поддерживается» и «Language server молча падает». На моем языке это называется «поддержка IDE начинает появляться».
А причем тут TS? Я про поддержку синтаксиса Svelte. На TS всем плевать.
Вот это говорит мне о том, что таки «TS не поддерживается». То, что можно проявить некоторую ловкость рук, и намазать TS отдельным слоем сборки над всей конструкцией — это нельзя назвать поддержкой.
Это ишак про поддержку из коробки, которая нафиг не нужна. Для таких вещей придуманы препроцессоры. Собственно TS это и есть препроцессинг для JS, поэтому не вижу тут ничего из разряда «ловкость рук». Точно также нужно поставить препроцессоры для PostCSS или SCSS если они необходимы. Так как 100% разработчиков Svelte не нужен TS, значит его не должно быть в Svelte по-умолчанию.
На всякий случай, если вы с первого раза не прочитали: «назвал критичные на мой взгляд недостатки». По каким причинам лично вы считаете это не важным или недостаточно важным — мне совершенно неинтересно.
Кроме фейспалма, у меня ничего для вас нет в этом вопросе.JustDont
13.09.2019 20:22Для таких вещей придуманы препроцессоры.
Конечно. Транспилятор TS таковым и является, вам не надо писать собственный.
Собственно TS это и есть препроцессинг для JS
Даже странно, что вы так быстро это для себя открыли.
поэтому не вижу тут ничего из разряда «ловкость рук»
«Ловкость рук» — это вот это вот:
TS поддерживается в скриптах, в шаблонах нет, но можно и минимизировать выражения в шаблонах и не использовать автоматические биндинги.
В переводе с русского на русский это и означает «да, вы можете пользоваться TS, но требуется проявить некоторую ловкость рук». Когда не будет никакого «но» — это и будет означать поддержку TS.PaulMaly
13.09.2019 21:29Конечно. Транспилятор TS таковым и является, вам не надо писать собственный.
А мне и не надо. Надо писать препроцессор для компонентов Svelte (точнее он уже написан), потому что они не просто JS, а SFC.
Даже странно, что вы так быстро это для себя открыли.
Если вы согласны с тем, что TS это препроцессинг, тогда в чем проблема его использоваться как препроцессор? Зачем его по-умолчанию включать туда, где он не нужен всем, а только вам например?
В переводе с русского на русский это и означает «да, вы можете пользоваться TS, но требуется проявить некоторую ловкость рук». Когда не будет никакого «но» — это и будет означать поддержку TS.
Это означает только то, что TS штука ограниченная в возможностях. Это TS не поддерживает использование кастомных шаблонизаторов. Как только TS начнет поддерживать HTMLx, никаких проблем с ним в шаблонах не будет.
Опять же, для фанатов и сейчас не так много преград, вы лишь бездумно скачете по верхам.JustDont
13.09.2019 21:50Если вы согласны с тем, что TS это препроцессинг, тогда в чем проблема его использоваться как препроцессор?
Всё в том же:
TS поддерживается в скриптах, в шаблонах нет, но можно и минимизировать выражения в шаблонах и не использовать автоматические биндинги.
Зачем его по-умолчанию включать туда, где он не нужен всем, а только вам например?
А я вам где-то это предлагал? Или вы сами выдумали и сами же обиделись?
Это означает только то, что TS штука ограниченная в возможностях.
Это означает то, что ограниченная в возможностях штука по имени TS мне нужна для достижения других важных вещей (статической типизации), и серьезных конкурентов у неё нет. В то время как Svelte — это очень здоровская концепция, но ничего функционально уникального в ней нет: сочетание одного из нескольких десятков компонентных фреймворков с одним из дюжин инструментов для управления стейтом даст в итоге всё то же самое. Чуть менее изящно и с чуть большим количеством кода в рантайме, но нисколько не менее функционально (а то и более).
Поэтому в выборе «или-или» проиграет отнюдь не TS.
Опять же, для фанатов и сейчас не так много преград, вы лишь бездумно скачете по верхам.
Для фанатов никогда нет преград. Это JS, где всегда можно примерно всё, хоть Ангуляр вместе с реактом и Vue на одной странице. Вопрос не в «можно-нельзя», а в «а так уж ли это надо?».
zim32
12.09.2019 10:12У Vue лучше, меньше скобочек, которых я терпеть не могу
<input on:input={(e) => onChange(e, ‘a’)} /> — Svelte
<input input=«onChange($event, 'a')»> — VueAlexxNB Автор
12.09.2019 10:46Возможно. Просто поясню, что в Svelte в атрибутах внутри
{}
всегда используется javascript выражение, по аналогии с правой частью стрелочной функции. Поэтому, и в шаблонах Svelte можно написать такую же короткую запись как и в Vue(даже еще короче):
<input on:input={onChange(‘a’)} />
Просто надо понимать, что обработчиком события станет не сама функция с переданным ей параметром, а то, что она вернёт.
Поэтому, можно в компоненте объявить функцию для обработчика таким образом:
const onChange = (param)=>(e)=>console.log(e,param);
Kanut
12.09.2019 11:15Интересно, но явных преимуществ лично я пока не вижу. Ну или если точнее, то что-то сделано лучше чем в Angular, что-то [как минимум пока] хуже. Аналогично с React/Vue.
Но я не вижу ничего что было бы лучше чем во всех уже имеющихся альтернативах.
И в такой ситуации лично я не буду выбирать для рабочих решений "молодой" и необкатанный фреймворк без большого коммьюнити и всех вытекающих из этого последствий.
AlexxNB Автор
12.09.2019 11:29Главная особенность, отличающая Svelte от мейнстрима — он компилируется, а не тащит рантайм с собой. В статье про это ни слова, по-скольку у нее цель помочь ангулярщикам "въехать" в Svelte. А особенности уже не раз обсуждались в других статьях, в том числе и на Хабре.
Kanut
12.09.2019 11:37Вот об этом тогда пожалуйста поподробнее. Что значит "компилируется" и в чём отличие от того же Angular, который вроде бы тоже компилирует Typescript в Javascript?
И что имеется ввиду под "рантайм" и что конкретно Svelte меньше тащит по сравнению с Angular.
П.С. Я взял Angular для примера потому что в статье скорее сравнивают с ним, но если не сложно то было бы интересно прочитать и какие в этом плане есть отличия/преимущества по сравнению с React/Vue.
П.П.С. Если это слишком обширная тема для комментариев, то с удовольствием подожду отдельную статью или хотя бы ссылочку:)AlexxNB Автор
12.09.2019 11:40Можно почитать вводную статью по Svelte3 — https://habr.com/ru/post/449450/
Комментарии, как всегда, сильно интереснее самой статьи =)Kanut
12.09.2019 11:48YNile и AlexxNB спасибо, а то просто по слову svelte "нахабрилось" очень много статей :) Пошёл читать :)
П.С. И на работе конечно всё равно вряд ли буду использовать в ближайшие годы, но может хоть дома руки попробовать дойдут :)
Kanut
12.09.2019 14:34В общем почитал в обед поподробнее и наверное всё-таки останусь при своём мнении.
Особых плюсов я пока не вижу. То есть в теории может быть, но конкретно в наших проектах пожалуй нет.
А вот отсутствие typescript, относительно маленькое коммьюнити и слабая поддержка IDE это одгозначно большие минусы.
Гляну на это дело ещё раз годика через два-три:)
JustDont
12.09.2019 11:58Главная особенность, отличающая Svelte от мейнстрима — он компилируется, а не тащит рантайм с собой.
Это сложно записать в неоспоримое «лучше», ибо дебаг тут же машет ручкой из-за угла: если пишется одно, а выполняется уже другое, то для полноценного дебага нужен сопоставлятор выполняемого кода и исходников. А его нет.
Это «интересно», но не обязательно «лучше».AlexxNB Автор
12.09.2019 12:02Source maps же для этого и придуманы?
JustDont
12.09.2019 12:13Source maps откуда куда? ЧТО у вас будет исходником к написанному в ходе компиляции коду? Понятно, что замапить содержимое ваших <script> наверное можно (кстати, можно?), а как понять, откуда растут ноги у всего остального? У ошибок в svelte-коде, например? Как вы, например, будете выяснять, то ли баг порождается вашим кодом, то ли самим компилятором?
Yeah
12.09.2019 16:00В большом проекте, а не ToDoMVC, процент рантайма в общем объеме кода будет снижаться, а вот "вес" экосистемы, комьюнити и банально количества разработчиков, доступных для найма тут выйдет на первый план
PaulMaly
12.09.2019 18:00Так и в 2013 году рассуждали люди когда принимали решение попробовать React или остаться на jquery. Многие и до сих пор на нем сидят, но вряд ли это остановит прогресс.
xadd
12.09.2019 19:17+1В 2013 помню что VDOM стал революцией, а facebook корпорацией добра. JavaScript быстрее, чем вы думаете, говорили они… В итоге народ до сих пор и возится с атомарными компонентами, с разными memo, PureComponent и shouldComponentUpdate в борьбе с реконсиляцией.
vintage
14.09.2019 09:31import { SvelteComponent, append, detach, element, init, insert, listen, noop, safe_not_equal } from "svelte/internal"; import { createEventDispatcher } from "svelte";
Вот это вот тоже "компилируется, а не тащит в рантайм", да?
AlexxNB Автор
14.09.2019 10:43+1Конечно же, не без хелперов — атомарные операции над DOM и прочее, например:
// append export function append(target, node) { target.appendChild(node); }
Вся эта история с "исчезновением", конечно же, рекламный трюк, всего там насобирается аж 1043 байта загзипованного кода для пустого приложения.
Под отстутсвием рантайма можно понимать всю ту логику, которая происходит при вычислении изменений представления при изменении стейта. Это то всё как раз и происходит во время компиляции, а не во время выполнения.
feligz
12.09.2019 16:31+2Очень приятный фреймворк. Сделал 2 небольших проекта на нем, очень доволен. Реактивный, простой, понятный, мощный, легкий. Особых проблем не обнаружил, ни разу не ходил на стэк за подсказкой. Рич (создатель фреймворка) каждый день сидит в дискорде и отвечает на вопросы, да и коммьюнити уже довольно большое.
zoonman
Я наверно один такой сумасшедший, но мне совсем непонятно, зачем делать все эти решетки, звездочки и прочий кошмар в коде.
В чем проблема написать интерпретатор, способный нормально работать с такими шаблонами?
В данном случае транспайлер должен быть достаточно "умен", чтобы понять, что в bind передается итерируемое значение.
Передачу параметров внутрь можно реализовать через механизм, подобный React props.
Везде есть нормальный двухнаправленный биндинг для обычных компонентов ввода.
Могу привести альтернативный пример подобного подхода
А теперь просто покажу такую идею
Вместо bind можно использовать что-то другое, например делать так
С таким подходом можно писать простые приложения с точки зрения его интерпретации человеком. А машине все равно, что ей скормят, главное, чтобы она могла это быстро и без ошибок выполнить.
PaulMaly
Может быть потому что не всем нравятся управляющие конструкции в тегах? Этим страдают Vue и Angular и это является главным минусом их шаблонизаторов.
AlexxNB Автор
Мне кажется — это дело вкуса и привычек. Мне лично структуры в Svelte симпатизируют больше — легче писать и сильно легче читать и воспринимать. Особенно если структуры в несколько этапов или имеют вложенность.
Если подумать, написать для Svelte препроцессор, который развернет теги со структурными атрибутами в HTMLx, совсем не сложно. Но пока, видимо, без надобности.
Carduelis
А мне кажется — Svelte не взлетит именно из-за синтаксиса.
PaulMaly
Это все вкусовщина, но факт остается фактом — новый синтаксис Svelte 3 нравится значительно больше значительно большему кол-ву человек, иначе не было бы роста, который пришелся аккурат после выхода Svelte 3.