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

В этой серии⚓︎
- Часть 1: создание компонента на Alpine.js
- Часть 2: почему Vue?
- Часть 3: знакомство с React
- Часть 4: а может Preact?
- Часть 5: Svelte тоже неплох
- Часть 6: но и Solid красавчик
- Заключение: подводим итоги ⬅️ вы здесь
На основе всего (плюс добавлю несколько пунктов от себя), что мы прошли в этой серии статей, попробуем сделать такую таблицу:
Вывод значения переменной в разметке⚓︎
| Пример кода | |
|---|---|
| Обычный JavaScript | element.innerText = variable |
| Alpine.js | <span x-text="variable"></span> |
| Vue Options API | <span v-text="variable"></span> или <span>{{ variable }}</span> |
Vue <script setup> | ☝️ |
| React/Preact | <span>{variable}</span> |
| Svelte | ☝️ |
| Solid | <span>{variable()}</span> |
Вывод переменной с HTML в разметке⚓︎
| Пример кода | |
|---|---|
| Обычный JavaScript | element.innerHTML = variable |
| Alpine.js | <span x-html="variable"></span> |
| Vue Options API | <span v-html="variable"></span> |
Vue <script setup> | ☝️ |
| React/Preact | <span dangerouslySetInnerHTML={{ __html: variable }}/>или с помощью сторонней библиотеки типа html-react-parser |
| Svelte | <span>{@html variable}</span> |
| Solid | <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 <script setup> | ☝️ | ☝️ |
| 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> |
Циклы в разметке⚓︎
| Пример кода | |
|---|---|
| Обычный 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 <script setup> | ☝️ |
| 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> |
Привязка событий⚓︎
| Пример кода | |
|---|---|
| Обычный 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 <script setup> | ☝️ |
| React/Preact | <button onClick={func}/> |
| Svelte | <button onclick={func}/> |
| Solid | <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 <script setup> | 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 |
Привязка к значению элемента⚓︎
| Пример кода | |
|---|---|
| Обычный 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 <script setup> | 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 |
Выполнение кода при загрузке страницы⚓︎
| Пример кода | |
|---|---|
| Обычный JavaScript | window.onload = func |
| Alpine.js | Через атрибут x-init="func()" |
| Vue Options API | mounted() {func() {// тело функции}, func2() {// тело функции}, ...} |
Vue <script setup> | onMounted(func) |
| React/Preact | useEffect(() => func, []), useMount(() => func)useSignalEffect(() => func) |
| Svelte | onMount(func) |
| Solid | onMount(() => 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 <script setup> | 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) |
Передача состояния между компонентами⚓︎
| Как? | |
|---|---|
| Обычный JavaScript | Через объект window |
| Alpine.js | Через события ($dispatch) или $store |
| Vue Options API | provide / inject, Pinia |
Vue <script setup> | ☝️ |
| React/Preact | createContext / useContext, Redux Toolkit, MobX, Valtio, Zustand |
| Svelte | svelte/store |
| Solid | createContext / useContext |
Асинхронные запросы⚓︎
Допустим, нам нужно подгружать данные с API при загрузке страницы. Как можно вызвать асинхронную функцию?
| Как? | |
|---|---|
| Обычный JavaScript | window.onload = func |
| Alpine.js | x-init="func()", $watch, x-effect |
| Vue Options API | mounted() { func() }, defineAsyncComponent |
Vue <script setup> | onMounted(async () => {}), defineAsyncComponent, useFetch, useAxios, useFetch / Composables |
| React/Preact | useEffectuseRequest, useAsyncEffect,useAsync, useQuery, use |
| Svelte | onMount(async () => {}), $effect(() => {(async () => {})()}) |
| Solid | onMount(async () => {}), createResource |
Сравнение размеров билдов⚓︎
Кроме того, собрав билды всех вариаций нашего проекта TODO (npm run build), можно отсортировать наших героев по размерам полученных папок dist и сгенерированных файлов index.js:
| Фреймворк/библиотека | Размер папки dist | Размер js |
|---|---|---|
| Обычный JavaScript | 32 КБ | 3.41 КБ |
| Solid | 44 КБ | 15.65 КБ |
| Preact | 48 КБ | 16.37 КБ |
| Preact + Signals | 52 КБ | 21.86 КБ |
| Svelte | 52 КБ | 22.28 КБ |
| Alpine.js | 80 КБ | 45.64 КБ |
| Vue | 92 КБ | 63.88 КБ |
| React | 212 КБ | 188.30 КБ |
Разумеется, эти данные относятся всего лишь к демонстрационному проекту, и ваше приложение может оказаться как меньшего, так и гораздо большего размера. С каждым обновлением того или иного фреймворка или библиотеки всё может меняться.
Для обучающихся⚓︎
Попробуйте заменить Tailwind в изученных проектах на Bootstrap или Material UI. Или реализуйте отправку POST/PATCH/DELETE запросов на сервер, в зависимости от действий с задачами. Или настройте хранение и обновление задач в localStorage. Это прокачает вас быстрее, чем простое копирование готовых решений.
Документация на русском языке⚓︎
- Обычный JavaScript: https://learn.javascript.ru
- Alpine.js: https://alpinejs.dragomano.ru
- Vue: https://vuejs.dragomano.ru
- React: https://reactdev.ru
- Preact: https://preactjs.com/guide
- Svelte: https://svelte.dev/docs/svelte
- Solid: https://www.solidjs.com/
Заключение⚓︎
Не забывайте, что в основе всех рассмотренных нами библиотек и фреймворков лежит обычный JavaScript. Поэтому, если вы этого не сделали ранее, смело открывайте и изучайте — главу за главой, абзац за абзацем. Пригодится.
Создание аналогичного проекта на чистом JS мы рассматривать не будем, но если кому интересно, есть готовая реализация.
Что вам больше нравится, с тем и работайте. Никто вам ничего не навязывает. Цель данного цикла лишь в структурировании информациии и сравнении реализаций одного и того же проекта с помощью разных инструментов. Каждый фреймворк всего лишь инструмент, а инструменты применяются в зависимости от конкретной задачи.