Легче и быстрее — руководство по Svelte Framework

Опубликовано: 2022-03-11

Веб-приложения с каждым днем ​​становятся все популярнее. Это растущий мир, который люди выбирают за его простоту, скорость и кросс-платформенную доступность. Одностраничные приложения (SPA) сыграли огромную роль в этом процессе. Такие фреймворки, как Angular, Vue.js и React, помогают разработчикам обеспечить наилучшее взаимодействие с пользователем за короткий период, оставляя код поддерживаемым и расширяемым. Эти инструменты долгое время оставались самыми популярными в этой области, имея множество преимуществ перед недавно созданными пакетами. Это похоже на олигополию в мире СПА. Однако группа дальновидных разработчиков, нацеленных на этот рынок, может выйти с серьезным конкурентом — Svelte.

Svelte — это новый подход к созданию пользовательских интерфейсов. Давайте погрузимся и узнаем, что делает его таким новым, создав общую форму входа.

Архитектура

Svelte спроектирован так, чтобы работать быстрее, чем любая другая библиотека. Это достигается изменением шага загрузки фреймворка для построения виртуального DOM. Вместо того, чтобы использовать инструмент во время рабочего процесса, он компилируется в vanilla JS на этапе сборки, поэтому для запуска приложения не требуется никаких зависимостей.

Стройный Другие библиотеки SPA (React, Vue.js, Angular и т. д.)

1. Откройте веб-сайт
2. Рендеринг страницы с использованием чистого JS

1. Откройте веб-сайт
2. Подождите, пока загрузится код для построения виртуального DOM.
3. Рендерим страницу с помощью библиотеки

В приведенной выше таблице показано, почему Svelte является абсолютным лидером по производительности при запуске. Это достигается не какой-либо оптимизацией, а использованием доступного браузерного компилятора JavaScript вместо стороннего компилятора.

Установка

Установка Svelte невероятно проста, что делает его использование очень приятным. Первым шагом является загрузка шаблона проекта:

 npx degit sveltejs/template svelte-login-form

Выполнение вышеуказанной команды означает, что у нас есть шаблон проекта Svelte. На данный момент он пуст, и необходимые пакеты NPM еще не установлены. Давайте исправим это.

 cd svelte-login-form npm install

Теперь приложение готово к запуску с помощью следующей команды:

 npm run dev

Структура

Любой компонент Svelte может содержать следующие разделы:

  • Скрипт
  • Стиль
  • Шаблон

Давайте посмотрим на пример в файле src/App.svelte .

 <script> export let name; </script> <style> h1 { color: purple; } </style> <h1>{name}</h1>

Приведенный выше код содержит ровно три раздела:

  1. script , который является необязательным блоком JavaScript с объявлениями переменных и функций, которые должны использоваться внутри компонента.

  2. тег style , который является еще одним необязательным блоком. Он очень похож на обычный тег стиля HTML, за исключением одного важного отличия. Правила, описанные в этом блоке, относятся только к этому компоненту. Применение стиля к элементу p не повлияет на все абзацы на странице. Это замечательно, так как вам не нужно придумывать имена классов, и вы никогда не переопределите случайно другое правило.

  3. Последний и единственный обязательный блок — это блок шаблона — в данном случае это тег h1 . Это презентация/представление вашего компонента. Он тесно связан со стилями и блоками сценариев, поскольку они определяют, как будет оформлено представление и как оно будет себя вести.

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

Возвращаясь к создаваемой нами форме входа, давайте создадим новый файл LoginForm.svelte внутри папки src со следующим содержимым:

 <style> form { background: #fff; padding: 50px; width: 250px; height: 400px; display: flex; flex-direction: column; justify-content: center; align-items: center; box-shadow: 0px 20px 14px 8px rgba(0, 0, 0, 0.58); } label { margin: 10px 0; align-self: flex-start; font-weight: 500; } input { border: none; border-bottom: 1px solid #ccc; margin-bottom: 20px; transition: all 300ms ease-in-out; width: 100%; } input:focus { outline: 0; border-bottom: 1px solid #666; } button { margin-top: 20px; background: black; color: white; padding: 10px 0; width: 200px; border-radius: 25px; text-transform: uppercase; font-weight: bold; cursor: pointer; transition: all 300ms ease-in-out; } button:hover { transform: translateY(-2.5px); box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.58); } h1 { margin: 10px 20px 30px 20px; font-size: 40px; } </style> <form> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" /> <label>Password</label> <input name="password" type="password" placeholder="password" /> <button type="submit">Log in </button> </form>

Это компонент с тупым стилем, который мы позже сделаем умнее. Чтобы увидеть этот компонент на нашем сайте, мы должны отрендерить его внутри корневого компонента — App. Давайте отредактируем src/App.svelte , чтобы он выглядел так:

 <script> import LoginForm from "./LoginForm.svelte"; </script> <style> section { height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; background: linear-gradient(to right, #cd76e2, #e358ab); } </style> <section> <LoginForm /> </section>

Если все сделано правильно и приложение все еще работает, наша форма появится по адресу localhost:5000 . Давайте повысим наши навыки Svelte, сделав форму умнее.

Статус

Любой компонент в Svelte может иметь свое состояние. Состояние — это специальная переменная или группа специальных переменных, которые можно использовать внутри шаблона. Почему я говорю «особенный»? Всякий раз, когда такая переменная изменяется, шаблон уведомляется об этом и отображает содержимое с новейшим состоянием. Это позволяет приложению очень быстро реагировать на действия пользователя.

Мы объявим переменные состояния email и password , в которых будут храниться значения формы для соответствующих полей. Это означает, что наши переменные email и password всегда будут синхронизированы со значениями формы, поэтому мы будем готовы отправить эти значения в любое время, не опасаясь каких-либо различий между значениями отправки и фактическими значениями в форме.

 <script> let email = ""; let password = ""; let isLoading = false; const handleSubmit = () => { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; // Authorize the user }, 1000); }; </script> <style> /* Style is unchanged */ </style> <form on:submit|preventDefault={handleSubmit}> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> {#if isLoading}Logging in...{:else}Log in {/if} </form>

Переменные состояния выглядят как обычные переменные JavaScript, но чтобы сделать их синхронизированными со значениями формы (привязать их к полям формы), необходимо использовать директиву bind:value . Есть еще пара незнакомых моментов:

  • on:submit|preventDefault — сокращение для предотвращения поведения событий по умолчанию. Так удобнее, чем каждый раз писать e.preventDefault() .

  • {#if isLoading}Logging in...{:else}Log in {/if} — это часть синтаксиса шаблона Svelte. Так как в блоке шаблона нет JS, есть специальный синтаксис для использования ifs, циклов и т.д.

Наконец, давайте воспользуемся доступными опциями, используя состояние, чтобы добавить проверку в нашу форму. Этого можно добиться, создав другую переменную состояния errors , которая будет заполняться ошибками при отправке формы с недопустимыми значениями.

 <script> let email = ""; let password = ""; let isLoading = false; let errors = {}; const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; // Authorize the user }, 1000); } }; </script> <style> // Previous styles unchanged .errors { list-style-type: none; padding: 10px; margin: 0; border: 2px solid #be6283; color: #be6283; background: rgba(190, 98, 131, 0.3); } </style> <form on:submit|preventDefault={handleSubmit}> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> <button type="submit"> {#if isLoading}Logging in...{:else}Log in {/if} </button> {#if Object.keys(errors).length > 0} <ul class="errors"> {#each Object.keys(errors) as field} <li>{field}: {errors[field]}</li> {/each} </ul> {/if} </form> 
Ошибка формы входа

Форма почти готова. Единственное, что остается, — это сообщение об успешном завершении аутентификации.

Давайте создадим переменную состояния для отслеживания успешных отправок, которая по умолчанию имеет значение false . После успешной отправки формы значение этой переменной должно быть установлено в true .

 let isSuccess = false;

Функция, обрабатывающая отправку формы, также должна быть изменена, чтобы следовать логике переключения isSuccess после успешной операции.

 const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; isSuccess = true; // Authorize the user }, 1000); } };

Эта модификация приводит к тому, что форма переходит в состояние успеха, как только отправка завершена.

Но если вы проверите свой сервер разработки, вы не найдете никаких изменений в поведении формы. Мы изменили код, но пока не трогали шаблон. Нам нужно добавить в шаблон инструкции, чтобы отображать сообщение об успешном завершении пользователем входа в систему. Синтаксис шаблона Svelte позволяет нам легко реализовать это:

 <form on:submit|preventDefault={handleSubmit}> {#if isSuccess} <div class="success"> <br /> You've been successfully logged in. </div> {:else} <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> <button type="submit"> {#if isLoading}Logging in...{:else}Log in {/if} </button> {#if Object.keys(errors).length > 0} <ul class="errors"> {#each Object.keys(errors) as field} <li>{field}: {errors[field]}</li> {/each} </ul> {/if} {/if} </form>

Аннотация со свойствами

Мы разобрались со всем, что касается состояния внутреннего компонента. Теперь пришло время пройтись по внешним зависимостям, называемым свойствами или «реквизитами». Реквизиты — это входные данные или аргументы, передаваемые компоненту для описания того, что должно отображаться или как должен вести себя компонент.

Объявление свойства похоже на состояние, за исключением ключевого слова export .

 <script> export let answer; </script> <p>The answer is {answer}</p>
 <script> import Nested from './Nested.svelte'; </script> <Nested answer={42}/>

Все дело в свойствах. Объявите и передайте — все, что вам нужно знать, чтобы использовать реквизит.

Но как эти свойства применяются к компоненту формы входа? Реквизиты могут сделать нашу форму входа более общей, извлекая функцию отправки в свойство. Это позволит вам использовать этот компонент с любым действием отправки, которое вам нужно (запрос на тестовый сервер, запрос на реальный сервер и т. д.). Это свойство будет называться submit и будет функцией, которая возвращает разрешенное обещание, если действие отправки прошло успешно, и отклоненное обещание, если есть ошибка. Давайте объявим свойство по примеру, приведенному выше:

 export let submit;

Обработчик отправки внутри формы входа также следует отредактировать, чтобы использовать новое свойство submit .

 const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; submit({ email, password }) .then(() => { isSuccess = true; isLoading = false; }) .catch(err => { errors.server = err; isLoading = false; }); } };

Компонент вроде бы готов. Однако, если вы вернетесь к форме и попытаетесь отправить ее, вы заметите, что состояние кнопки не изменилось после загрузки. Также в консоли есть исключение: Uncaught TypeError: submit is not a function . Конечно, мы объявили реквизит, но забыли его передать. Давайте объявим функцию в компоненте приложения и передадим ее в форму входа.

 const submit = ({ email, password }) => new Promise((resolve, reject) => setTimeout(resolve, 1000));
 <section> <LoginForm submit={submit} /> </section>

Теперь форма работает как надо. Он может как показывать ошибки, так и информировать пользователя об успешном входе в систему.

Успешная форма входа

Совместное использование контекста

Вроде бы все необходимое для сборки приложения перечислено. Со свойствами и внутренним состоянием мы готовы к работе. Однако это верно лишь отчасти. Эти два общих момента позволяют проектировать SPA высокой сложности. Однако, если вы попробуете разделить данные между множеством разных компонентов, вам будет очень сложно.

Самый простой пример — наличие глобально доступной user переменной. Многие компоненты должны изменить свое поведение, связанное с пользователем, в зависимости от роли пользователя, возраста, статуса и т. д. Однако не стоит повторяться, передавая пользователя каждому компоненту в приложении с помощью реквизита.

У Svelte есть решение для этого: контекстный API.

Контекстный API предоставляет механизм, с помощью которого компоненты могут «общаться» друг с другом, не передавая данные и функции в качестве свойств или отправляя множество событий. Это расширенная функция, но полезная.

Давайте добавим пользовательский контекст в форму входа, которую мы разрабатываем. Создайте файл userContext.js в папке src со следующим содержимым:

 export const key = "userContext"; export const initialValue = null;

key — это уникальный идентификатор контекста, поскольку приложение может иметь неограниченное количество различных контекстов, которые должны оставаться доступными. initialValue — это просто значение по умолчанию для контекста до его установки.

Следующим шагом будет добавление контекста в наше приложение. Перейдите к файлу App.svelte и добавьте 2 оператора импорта:

 import { onMount, setContext } from "svelte"; import { key as userContextKey, initialValue as userContextInitialValue } from "./userContext";

Глядя на код выше, вы можете задаться вопросом, что мы импортируем из пакета svelte . onMount — это вспомогательная функция, требующая в качестве аргумента функцию обратного вызова. Этот обратный вызов будет выполняться при монтировании текущего компонента (в самом начале загрузки компонента). setContext — это функция установки контекста. В качестве аргументов требуется ключ к контексту и новое значение.

Давайте используем функцию onMount , чтобы установить значение по умолчанию для контекста:

 onMount(() => { setContext(userContextKey, userContextInitialValue); });

И измените функцию submit , чтобы установить пользовательский контекст:

 const submit = ({ email, password }) => new Promise((resolve, reject) => { setTimeout(() => { setContext(userContextKey, { name: "Foo", lastName: "Bar", email: "[email protected]" }); resolve(); }, 1000); });

Вот и все. Успешная отправка изменит пользовательский контекст на поддельный пользовательский объект, к которому может получить доступ получатель контекста getContext :

 <script> import { getContext } from 'svelte'; import { key as userContextKey } from "./userContext"; const user = getContext(key); </script>

Резюме

Svelte — это мощный инструмент с высокой производительностью и гибким API. Помимо основ, описанных в этом посте, Svelte имеет следующие стандартные функции:

  • Реактивные декларации и заявления
  • Ожидайте блоков шаблонов
  • Привязка размеров
  • Глобальный магазин, такой как Redux
  • Помощники анимации и перехода
  • Помощник по отладке

Подводя итог, можно сказать, что Svelte — отличная библиотека, которая отвечает всем требованиям для создания SPA и многого другого. Он может конкурировать с крупнейшими игроками на рынке и даже побеждать. Однако прямо сейчас ему может пригодиться поддержка в сообществе разработчиков интерфейса.

Примечание. Весь код в этой статье можно найти в teimurjan/svelte-login-form GitHub. Демонстрация формы входа доступна здесь.