Перейти к содержанию

Знакомство с популярными JS фреймворками - заключение

Составляем сводную таблицу особенностей рассмотренных фреймворков. Для сравнения также добавлю примеры кода на обычном JavaScript и Symbiote.js

В этой серии⚓︎

На основе всего (плюс добавлю несколько пунктов от себя), что мы прошли в этой серии статей, попробуем сделать такую таблицу:

Вывод значения переменной в разметке⚓︎

Пример кода
Обычный JavaScript element.innerText = variable
Alpine.js <span x-text="variable"></span>
Vue Options API <span v-text="variable"></span> или <span>{{ variable }}</span>
Vue Composition API ☝️
React/Preact <span>{variable}</span>
Svelte ☝️
Solid <span>{variable()}</span>
Symbiote.js <span>{{variable}}</span>

Вывод переменной с HTML в разметке⚓︎

Пример кода
Обычный JavaScript element.innerHTML = variable
Alpine.js <span x-html="variable"></span>
Vue Options API <span v-html="variable"></span>
Vue Composition API ☝️
React/Preact <span dangerouslySetInnerHTML={{ __html: variable }}/>
или с помощью сторонней библиотеки типа html-react-parser
Svelte <span>{@html variable}</span>
Solid <span innerHTML={variable}></span>
Symbiote.js <span ${{innerHTML: 'variable'}}></span>

Условия в разметке⚓︎

if if-else
Обычный JavaScript Любые условия JS только в скрипте 👈
Alpine.js <template x-if="condition">Видно?</template> <template x-if="condition">Видно?</template>
<template x-if="!condition">Не видно!</template>
Vue Options API <span v-if="condition">Видно?</span> <span v-if="condition">Видно?</span>
<span v-else>Не видно!</span>
Vue Composition API ☝️ ☝️
React/Preact {condition && (<span>Видно?</span>)} {condition ? (<span>Видно?</span>)
: (<span>Не видно!</span>)}
Svelte {#if condition}<span>Видно?</span>{/if} {#if condition}<span>Видно?</span>
{:else}<span>Не видно!</span>{/if}
Solid <Show when={condition}><span>Видно?</span></Show> <Switch><Match when={condition}>Видно?</Match><Match when={!condition}>Не видно!</Match></Switch>
Symbiote.js <span ${{'@hidden': '!condition'}}>Видно?</span> <span ${{'@hidden': '!condition'}}>Видно?</span><span ${{'@hidden': 'condition'}}>Не видно!</span>

Циклы в разметке⚓︎

Пример кода
Обычный JavaScript Любые циклы JS только в скрипте
Alpine.js <template x-for="(item, index) in items" :key="index"><li x-text="item.text"></li></template>
Vue Options API <li v-for="(item, index) in items" :key="index">{{ item.text }}</li>
Vue Composition API ☝️
React/Preact {items.map((item, index) => <li key={index}>{item.text}</li>))}
Svelte {#each items as item (item.id)}<li>{item.text}</li>{/each}
Solid <For each={items()}>{(item, index) => <li>{item.text}</li>}</For>
Symbiote.js <ul itemize="items"><li>{{text}}</li></ul>

Привязка событий⚓︎

Пример кода
Обычный JavaScript <button onclick="func()"/>
или element.addEventListener('click', func(event))
Alpine.js <button x-on:click="func"/> или <button @click="func"/>
Vue Options API <button v-on:click="func"/> или <button @click="func"/>
Vue Composition API ☝️
React/Preact <button onClick={func}/>
Svelte <button onclick={func}/>
Solid <button onClick={func}/>
Symbiote.js <button ${{onclick: 'func'}}/>

Привязка к HTML-элементу⚓︎

Пример кода
Обычный JavaScript Инициализация: const element = document.querySelector(selector), использование : element
Alpine.js HTML: <input x-ref="anyName"/>, использование: this.$refs.anyName
Vue Options API HTML: <input ref="anyName"/>, использование: ☝️
Vue Composition API HTML: ☝️, инициализация: const anyName = ref(null), использование: anyName.value
React/Preact HTML: <input ref={anyName}/>, инициализация: const anyName = useRef(), использование: anyName.current
Svelte HTML: <input bind:this={anyName}/>, инициализация: let anyName = $state(), использование: anyName
Solid HTML: <input ref={anyName}/>, инициализация: let anyName, использование: anyName
Symbiote.js HTML: <input ref="anyName"/>, использование: this.ref.anyName

Привязка к значению элемента⚓︎

Пример кода
Обычный JavaScript element.addEventListener('input', func(event) {}), использование: event.target.value
Alpine.js HTML: <input x-model="anyName"/>, использование: this.anyName
Vue Options API HTML: <input v-model="anyName"/>, использование: ☝️
Vue Composition API HTML: ☝️, использование: anyName.value
React/Preact HTML: <input ref={anyName}/>, использование: anyName.current.value
Svelte HTML: <input bind:value={anyName}/>, использование: anyName
Solid HTML: <input value={anyName()} onInput={(e) => setAnyName(e.target.value)} />, использование: anyName
Symbiote.js HTML: <input ${{value: 'anyName'}}>

Выполнение кода при загрузке страницы⚓︎

Пример кода
Обычный JavaScript window.onload = func
Alpine.js Через атрибут x-init="func()"
Vue Options API mounted() {func() {// тело функции}, func2() {// тело функции}, ...}
Vue Composition API onMounted(func)
React/Preact useEffect(() => func, []), useMount(() => func)
useSignalEffect(() => func)
Svelte onMount(func)
Solid onMount(() => func)
Symbiote.js initCallback() { func() }

Хранение и изменение состояния⚓︎

Пример кода
Обычный JavaScript let someVar = initialValue / someVar = newValue
Alpine.js HTML: x-data="{ someVar: initialValue }", использование: this.someVar = newValue
Vue Options API data() { return { someVar: initialValue } } / this.someVar = newValue
Vue Composition API const someVar = ref(initialValue) / someVar.value = newValue
React/Preact const [someVar, setSomeVar] = useState(initialValue) / setSomeVar(newValue)
const someVar = useSignal(initialValue) / someVar.value = newValue
Svelte let someVar = $state(initialValue) / someVar = newValue
Solid const [someVar, setSomeVar] = createSignal(initialValue) / setSomeVar(newValue)
const [someVar, setSomeVar] = createStore(initialValue) / setSomeVar(newValue)
Symbiote.js init$ = { someVar: initialValue } / this.$.someVar = newValue

Передача состояния между компонентами⚓︎

Как?
Обычный JavaScript Через объект window
Alpine.js Через события ($dispatch) или $store
Vue Options API provide / inject, Vuex, Pinia
Vue Composition API ☝️
React/Preact createContext / useContext, Redux Toolkit, MobX, Valtio, Zustand
Svelte svelte/store
Solid createContext / useContext
Symbiote.js Через пропсы, контексты данных и события

Асинхронные запросы⚓︎

Допустим, нам нужно подгружать данные с API при загрузке страницы. Как можно вызвать асинхронную функцию?

Как?
Обычный JavaScript window.onload = func
Alpine.js x-init="func()", $watch, x-effect
Vue Options API mounted() { func() }, defineAsyncComponent
Vue Composition API onMounted(async () => {}), defineAsyncComponent, useFetch, useAxios, useFetch / Composables
React/Preact useEffect, useRequest, useAsyncEffect,
useAsync, useQuery, use
Svelte onMount(async () => {}), $effect(() => {(async () => {})()})
Solid onMount(async () => {}), createResource
Symbiote.js initCallback() {async () => { await func() }}

Сравнение размеров билдов⚓︎

Кроме того, собрав билды всех вариаций нашего проекта TODO (npm run build), можно отсортировать участников сравнения по размерам полученных папок dist и сгенерированных файлов dist/assets/index-*.js:

Фреймворк/библиотека Размер папки dist Размер JS
Обычный JavaScript 20 КБ 2.77 КБ
Preact 32 КБ 15.77 КБ
Solid 36 КБ 18.94 КБ
Preact + Signals 40 КБ 21.97 КБ
Symbiote.js 40 КБ 23.59 КБ
Svelte 56 КБ 39.13 КБ
Alpine.js 68 КБ 46.64 КБ
Vue Composition API 80 КБ 63.69 КБ
Vue Options API 80 КБ 64.30 КБ
React 204 КБ 192.39 КБ

Разумеется, эти данные относятся всего лишь к нашему демонстрационному проекту, и ваше приложение может оказаться как меньшего, так и гораздо большего размера. С каждым обновлением того или иного фреймворка или библиотеки всё может меняться.

Для обучающихся⚓︎

Попробуйте заменить стили Tailwind в изученных проектах на Bootstrap или Material UI. Или реализуйте отправку POST/PATCH/DELETE запросов на сервер, в зависимости от действий с задачами. Или настройте хранение и обновление задач в localStorage. Это прокачает вас быстрее, чем простое копирование готовых решений.

Документация на русском языке⚓︎

Заключение⚓︎

Не забывайте, что в основе всех рассмотренных нами библиотек и фреймворков лежит обычный JavaScript. Поэтому, если вы этого не сделали ранее, смело открывайте и изучайте — главу за главой, абзац за абзацем. Пригодится.

Что вам больше нравится, с тем и работайте. Никто вам ничего не навязывает. Цель данного цикла статей лишь в структурировании информациии и сравнении реализаций одного и того же проекта с помощью разных инструментов. Ведь каждый фреймворк — всего лишь инструмент, а инструменты применяются в зависимости от конкретной задачи.

Комментарии