SvelteKit — это официально поддерживаемый фреймворк, построенный на основе Svelte. Он добавляет в приложение Svelte ключевые функции, такие как маршрутизация, макеты и рендеринг на стороне сервера, и делает разработку интерфейса чрезвычайно простой.
В этом руководстве мы для начинающих рассмотрим Svelte и SvelteKit и создадим простое веб-приложение, отображающее страницы профилей воображаемых пользователей. Попутно мы рассмотрим все основные функции, которые может предложить SvelteKit.
Давайте начнем с рассмотрения того, что предлагает Svelte.
Преимущества работы со Svelte
Популярность Svelte растет, и тому есть веская причина. Разработка приложений с помощью Svelte основана на написании многоразовых и автономных компонентов — аналогично другим популярным фреймворкам JavaScript, таким как React.
Большая разница поставляется с встроенным временем компиляции — в отличие от времени выполнения интерпретации коды. Другими словами, Svelte уже компилирует ваш код в процессе сборки, а окончательный пакет содержит только тот JavaScript, который действительно нужен вашему приложению. Это приводит к быстрым веб-приложениям с небольшими размерами пакетов.
Другие фреймворки только анализируют и объединяют написанный вами код, по сути принимая дерево компонентов как есть и отправляя его клиенту. Чтобы браузер мог интерпретировать его и обновлять пользовательский интерфейс, необходимо доставить гораздо больше кода и выполнить дополнительную работу на стороне клиента. (Вы можете прочитать здесь, как React обрабатывает этот процесс под капотом.)
В остальном Svelte — идеальный фреймворк для начинающих. Каждый, кто знает, как писать HTML и как включать <style>и <script>теги с базовым JavaScript и CSS, уже может начать писать компоненты Svelte.
Итак, зачем мне SvelteKit?
Хотя только Svelte дает вам очень хороший опыт разработки, вам все равно нужно решить, как вы хотите отправить свое приложение пользователю. Классический подход — взять ваш любимый пакет модулей, например webpack или Rollup, и объединить ваш код в один большой толстый файл JavaScript. Затем вы вызываете его из очень простого HTML-документа, например:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> ... </head> <body> <!-- the entry point of your application --> <div id="app" /> <!-- load the JavaScript that takes care of the rest --> <script src="dist/bundle.js"></script> </body> </html>
Хотя это абсолютно нормально, опыт пользователя может быть не идеальным. Есть много точек соприкосновения для улучшения, и именно здесь в игру вступает SvelteKit.
Во-первых, вместо того, чтобы предоставлять клиенту почти пустой HTML-файл, SvelteKit уже поставляется со всеми HTML-элементами, необходимыми для просмотра первой страницы. Преимущества — более быстрая загрузка страниц и повышение SEO. Есть два способа SvelteKit делает это: предварительной визуализации и на стороне сервера визуализации. Я объясню оба более подробно ниже. Что остается неизменным, так это то, что после загрузки JavaScript он берет на себя и включает типичные функции одностраничного приложения, такие как маршрутизация на стороне клиента.
Второе очевидное отличие SvelteKit от классического единого пакета JavaScript — это разделение кода. Вместо того, чтобы обслуживать все приложение в одном файле Javascript, SvelteKit разбивает код на отдельные более мелкие фрагменты. Каждый фрагмент представляет собой маршрут вашего приложения. Например, все, что нужно получить для маршрутов /homeи для /aboutмаршрутов, будет загружено, как только пользователю это действительно понадобится — или немного раньше, если вы воспользуетесь функцией предварительной выборки SvelteKit (как мы это сделаем ниже).
Еще одно выдающееся преимущество SvelteKit заключается в том, что вы можете решить, в какой среде развертывания будет запускаться ваше приложение. В настоящее время фронтенд-разработчики имеют множество различных платформ, на которых могут запускаться приложения. Существуют провайдеры хостинга для простых статических файлов, более продвинутые бессерверные варианты, такие как Netlify, или серверные среды, в которых могут выполняться серверы Node, и так далее. С помощью крошечных плагинов, называемых адаптерами, вы указываете SvelteKit оптимизировать ваш вывод для конкретной платформы. Это значительно облегчает развертывание приложения.
Однако самым большим преимуществом SvelteKit является простота использования. Конечно, вы можете вручную настроить процесс сборки с нуля со всеми этими функциями, но это может быть утомительно и утомительно. SvelteKit максимально упрощает вам задачу, и лучший способ испытать это — использовать его.
Вот почему мы создадим простое веб-приложение, показывающее страницы профилей выдуманных пользователей. Попутно мы рассмотрим все функции, о которых я упомянул выше, более подробно.
Предпосылки
Никаких предварительных знаний не требуется, хотя некоторый опыт работы со Svelte может быть полезен. Статья « Знакомство с Svelte 3, мощным и радикальным фреймворком JavaScript » дает хорошее введение.
Для работы со SvelteKit вам понадобится рабочая версия Node в вашей системе. Вы можете установить его с помощью диспетчера версий узлов (nvm). (Вы можете найти некоторые инструкции по установке здесь.)
Имейте в виду, что SvelteKit (на момент написания) все еще находится в стадии бета-тестирования, и некоторые функции могут быть изменены. Вы можете найти весь код этого руководства на GitHub.
Getting Started
Для начала инициируем новый проект SvelteKit. Выполните в своем терминале следующие команды:
npm init svelte@next svelteKit-example-app
Вам будет задано несколько вопросов, чтобы вы могли настроить свой проект. Для наших целей ответим следующее:
- Какой шаблон приложения Svelte? -> Демо-приложение SvelteKit
- Использовать компоненты TypeScript -> нет
- Добавить ESLint для линтинга кода? -> нет
- Добавить Prettier для форматирования кода? -> нет
Это загрузит среду разработки SvelteKit, включая функциональный пример приложения.
В маршруте вашего проекта теперь есть несколько файлов конфигурации: ваш package.json, staticпапка и srcпапка. В основном мы будем работать внутри srcпапки. Он имеет следующую структуру.
src ├── app.css ├── app.html ├── global.d.ts ├── hooks.js ├── lib │ ├── Counter │ │ └── index.svelte │ ├── form.js │ └── Header │ ├── index.svelte │ └── svelte-logo.svg └── routes ├── $layout.svelte ├── about.svelte ├── index.svelte └── todos ├── _api.js ├── index.json.js ├── index.svelte └── [uid].json.js
/src/app.htmlФайл представляет собой приложение-оболочка, минимальный HTML страница, где ваша визуализацию HTML будет вставлена и ваши файлы пучок связаны с. Обычно этот файл не нужно трогать. Вы можете вставить несколько мета- тегов для всего приложения, если хотите, но в этом нет необходимости — как вы вскоре увидите.
/src/routesПапка является сердцем вашего приложения. Файлы внутри этой папки определяют маршруты вашего приложения. Есть два типа маршрутов: pagesи endpoints. pagesявляются компонентами Svelte и обозначаются.svelteрасширением. Например, названный компонент /src/routes/test.svelteбудет обслуживаться по маршруту /test. endpointsявляются обычными файлами JavaScript (или TypeScript) и позволяют создавать конечные точки HTTP для получения данных.
Компоненты Svelte могут иметь дочерние компоненты. Например, компонент маршрута /src/routes/test.svelteможет импортировать компонент с именем Button.svelte. Место, где вы будете хранить все свои дочерние компоненты, — это /src/libпапка.
Посмотрим, как все это работает в действии. Перейдите во вновь созданный каталог, затем установите зависимости и запустите приложение в режиме разработки:
cd svelteKit-example-app npm install npm run dev -- --open
Это откроет уже существующий пример приложения на новой вкладке браузера. Щелкните приложение и убедитесь, что оно работает.
Some preparation
Как ни отточено демонстрационное приложение, оно содержит множество файлов, которые нам не понадобятся. Давайте избавимся от них.
Удаляем содержимое libпапки:
rm src/lib/*
Удалите routes/todosпапку:
rm -rf src/routes/todos
Мы можем обойтись без стилизации демонстрационного приложения. В корне проекта откройте app.cssи замените содержимое следующим:
:root { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;} body { margin: 0;}
Наконец, откройте src/index.svelteи замените содержимое следующим:
<main> <h1>HOME</h1> </main>
После этого приступим к созданию нашей демонстрации.
Макеты и маршрутизация на стороне клиента
Как я писал выше, каждый компонент Svelte в папке маршрутов определяет один маршрут. Однако есть одно исключение: компонент макета с именем $layout.svelte. Этот компонент содержит код, который применяется к каждой странице вашего приложения.
Откроем существующий /src/routes/$layout.svelteфайл. Все, что он сейчас делает, это импортирует некоторый CSS-код для всего приложения. <slot>Элемент заворачивает остальную часть приложения. Заменим контент следующим:
<script> import "../app.css"; </script> <svelte:head> <meta name="robots" content="noindex" /> </svelte:head> <nav> <a href=".">HOME</a> <a href="/about">ABOUT</a> </nav> <slot /> <style> nav { padding: 1rem; box-shadow: -1px 1px 11px 4px #898989; } a { text-decoration: none; color: gray; margin-right: 1rem; } </style>
Примечание: если вы хотите иметь подсветку синтаксиса для файлов Svelte, вы можете установить расширения. Это хорошо для VS Code.
В этом примере мы использовали элемент для определения метатегов, которые будут вставлены внаш документ. Поскольку мы сделали это в компоненте макета, он будет применен ко всему приложению. Робот тег просто пример.
Кроме того, мы создали панель навигации. Это типичный вариант использования компонента макета, поскольку он обычно предназначен для отображения на каждой странице вашего приложения.
Navbar имеет две ссылки: одна в корневой каталог приложения — который уже содержит служившую по /src/routes/index.svelteкомпоненте — и один к о странице. О странице также была создана с помощью демо — приложения. Откройте его и замените его содержимое следующим:
<main> <h1>ABOUT</h1> <hr /> <div>A website to find user profiles</div> </main> <style> main { font-size: 1.5rem; margin: 4rem; padding: 2rem; color: gray; justify-content: center; box-shadow: 4px 5px 11px 10px lightgray; } </style>
Эта страница довольно проста. Мы добавили немного HTML и применили стиль.
Вернемся в браузер и перейдем на новую страницу. Наши модификации уже должны быть видны, и вы должны увидеть что-то вроде этого:
Давай перемещаться между посадочной страницей и о странице. Вы можете понять, что изменение страницы не обновляет все приложение. Навигация кажется плавной и мгновенной. Это связано с тем, что SvelteKit «из коробки» применяет клиентскую маршрутизацию. Хотя мы использовали обычные теги в нашей навигационной панели, SvelteKit идентифицирует их как внутренние ссылки и перехватывает их с помощью своего встроенного клиентского маршрутизатора.
Статические страницы и предварительная отрисовка
Как я описал выше, SvelteKit использует концепцию адаптеров для создания приложений для различных сред. Адаптеры импортируются в svelte.config.cjsфайл.
Когда вы откроете этот файл конфигурации, вы увидите, что наше приложение в настоящее время использует адаптер узла. Это оптимизирует вывод сборки для среды Node, и по умолчанию каждая страница нашего приложения будет отображаться по запросу сервером Node. Однако это кажется слишком большим, учитывая текущее состояние нашего приложения. Кроме того, вы можете не захотеть запускать сервер для своего приложения.
Поскольку наше приложение в настоящее время не зависит от каких-либо динамических данных, оно может полностью состоять из статических файлов. И есть, adapter-staticчто вы можете установить, что превращает SvelteKit в генератор статического сайта. Он преобразует все ваше приложение в набор статических файлов в процессе сборки. Однако это помешало бы нам создавать дополнительные страницы, которые зависят от рендеринга на стороне сервера.
Поскольку мы не хотим превращать все наши страницы в статические файлы, мы воспользуемся другой функцией SvelteKit, которая позволяет нам предварительно визуализировать отдельные файлы нашего приложения. В нашем случае мы хотели бы, чтобы страница about была предварительно обработана, поскольку она состоит из статического содержимого и отображение страницы при каждом запросе не требуется. Мы можем добиться этого, добавив следующий фрагмент кода вверху нашей /src/routes/about.svelteстраницы:
<script context="module"> export const prerender = true; </script>
Мы можем проверить это, запустив npm run build. Это создаст работающий сервер Node внутри /buildпапки. Как видите, есть HTML-файл, /build/prerendered/about/index.htmlсодержащий предварительно отрисованный HTML-код для страницы about. Для нашей целевой страницы нет HTML-файла, поскольку он будет отображаться сервером Node по запросу.
Вы можете запустить сгенерированный сервер Node с помощью node build/index.js.
Конечные точки
Пришло время наполнить нашу страницу динамическим контентом. Мы настроим целевую страницу так, чтобы на ней отображался список аватарок пользователей. Для этого нам нужно получить список пользовательской информации из конечной точки API. У большинства команд разработчиков есть отдельная серверная часть. Это было бы то место, куда можно было бы пойти. Однако SvelteKit позволяет легко превратить ваше приложение в полный стек с помощью страниц конечных точек. Поскольку у нас нет бэкенда, мы создадим такую страницу.
Вместо того, чтобы использовать настоящую базу данных, мы создадим имитацию пользовательских данных. Для этого воспользуемся библиотекой faker. Давайте установим его с помощью npm install -D faker.
Теперь создайте файл /src/routes/api/index.jsв новой /apiпапке. Поскольку у файла нет.svelteрасширения, он будет рассматриваться как конечная точка. Синтаксис /api/index.jsтакой же, как у api.js. Конечная точка станет доступной под /api. Вставьте следующий код:
import faker from "faker"; const generateUsers = () => [...Array(50)].map(() => { const lastName = faker.name.lastName(); return { avatar: `https://avatars.dicebear.com/api/human/${lastName}.svg`, lastName, }; }); export async function get() { return { body: generateUsers(), }; }
Этот файл экспортирует функцию get. Как вы уже догадались, это соответствует методу HTTP GET. Все, что он делает, это возвращает объект со свойством body, содержащим массив пользовательских данных, созданных с помощью generateUsers.
Функция generateUsersвозвращает массив из 50 объектов со свойствами lastNameи avatar. lastNameсоздается с использованием faker. avatarхранит URL-адрес, который указывает на бесплатный DiceBear Avatar API. Он генерирует случайные аватары с использованием начального значения, как в нашем случае lastName.
Если бы у нас была настоящая база данных, мы могли бы заменить ее generateUsersчем-то вроде findUsersи получить доступ к базе данных внутри этой функции.
Это все, что ему нужно. Вернитесь в браузер (убедитесь, что ваше приложение все еще работает в режиме разработки npm run dev) и перейдите по адресу http: // localhost: 3000 / api. Это загрузит необработанные данные. Обратите внимание, что создание конечной точки, как мы, необходимо только в том случае, если у вас нет отдельного внутреннего API для получения данных.
Получение данных с помощью load функции
Затем мы будем использовать новую конечную точку для отображения пользовательских данных на нашей целевой странице. Откройте существующую /src/routes/index.svelteстраницу и замените ее содержимое следующим:
<script context="module"> export async function load({ fetch }) { const res = await fetch('/api'); if (res.ok) return { props: { users: await res.json() } }; return { status: res.status, error: new Error() }; } </script> <script> export let users; </script> <main> {#each users as { avatar, lastName }} <a href={`/${lastName}`} class="box"> <img src={avatar} alt={lastName} /> <h2>{lastName}</h2> </a> {/each} </main> <style> main { display: flex; flex-wrap: wrap; justify-content: center; } .box { padding: 0.25rem; margin: 1.5rem; color: salmon; box-shadow: 4px 5px 11px 2px lightgray; } .box:hover { box-shadow: 4px 5px 11px 10px lightgray; } img { width: 15rem; object-fit: contain; } </style>
Основная проблема при получении данных для динамического содержимого на странице заключается в том, что пользователь может перейти к нему двумя способами. Первый способ — из внешних источников или после обновления страницы. Это приведет к тому, что приложение будет загружено с нуля, а страница будет обслуживаться сервером. Второй способ — внутренняя навигация, и в этом случае страница будет обслуживаться пакетом JavaScript на стороне клиента. В первом случае данные выбираются сервером, а во втором — клиентом.
SvelteKit предлагает для этого очень элегантное решение — load
функцию. load
Функция может работать как на клиенте , так и на стороне сервера , и в обоих случаях будет выполняться до того , как компонент делает. Вот почему мы должны разместить его внутри <script>
элемента с context="module"
.
load
получает объект со свойством, fetch
которое мы можем использовать для выборки данных. Он ведет себя идентично собственному fetch
API. В этом примере мы используем нашу новую конечную точку /api
для получения массива пользовательских объектов. Чтобы передать эти данные нашему компоненту, мы возвращаем объект со props
свойством, в котором хранится наш пользовательский массив.
Если бы у вас был отдельный внутренний API, вместо получения данных из нашей /api
конечной точки вы бы получили их внутри load
функции из серверной части.
В случае load
запуска на сервере клиент поймет, что данные уже получены, и не будет делать дополнительный запрос.
Поскольку мы вернули props
объект, наш компонент может получить доступ к этим свойствам обычным способом Svelte — с export let
помощью <script>
тега. Это то, что мы делаем для доступа к нашим пользователям.
Затем мы визуализируем всех наших 50 пользователей, используя each
синтаксис, который мы знаем от Svelte. Внутри each
блока у нас есть доступ к пользователю avatar
и lastName
свойствам. Мы используем avatar
значение src
атрибута <img>
тега.
Теперь ваша целевая страница должна выглядеть так:
Динамические параметры
Каждый ящик пользователя на нашей целевой странице представляет собой внутреннюю ссылку с маршрутом /[lastName]
. Здесь в игру вступают динамические параметры . Под маршрутом /[lastName]
мы отобразим дополнительную информацию для соответствующего пользователя. Для этого нам сначала нужно расширить наш API с помощью дополнительной конечной точки для получения данных отдельных пользователей.
import faker from "faker"; export async function get({ params }) { const { lastName } = params; return { body: { lastName, firstName: faker.name.firstName(), avatar: `https://avatars.dicebear.com/api/human/${lastName}.svg`, title: faker.name.title(), phone: faker.phone.phoneNumber(), email: faker.internet.email(), }, }; }
Обратите внимание на динамический параметр [lastName]
в имени файла. Мы можем получить доступ к этому параметру из params
свойства get
функции. Мы используем его, чтобы вернуть правильные значения для объекта lastName
и avatar
внутри него body
. Затем мы генерируем некоторые дополнительные фиктивные данные для этого пользователя faker
, которые также возвращаем в body
объект.
Мы можем протестировать эту конечную точку с произвольным lastName
значением. Откройте браузер и перейдите по адресу http: // localhost: 3000 / api / Spiderman . Это позволит загрузить исходные данные для произвольного пользователя со значением Spiderman
из lastName
.
Затем мы создаем новую страницу — /src/routes/[lastName].svelte
— со следующим содержанием:
<script context="module"> export async function load({ fetch, page }) { const { lastName } = page.params; const res = await fetch(`/api/${lastName}`); if (res.ok) return { props: { user: await res.json() } }; return { status: res.status, error: new Error(), }; } </script> <script> export let user; </script> <main> <h1>{user.firstName} {user.lastName}</h1> <div class="box"> <img src="{user.avatar}" alt="{user.astName}" /> <ul> <li>Title: {user.title}</li> <li>Phone: {user.phone}</li> <li>Email: {user.email}</li> </ul> </div> </main> <style> main { margin: 4rem; padding: 2rem; color: gray; justify-content: center; box-shadow: 4px 5px 11px 10px lightgray; } h1 { color: salmon; } .box { display: flex; font-size: 1.5rem; } img { width: 15rem; object-fit: contain; margin-right: 2rem; } li { margin-bottom: 1rem; } </style>
Еще раз обратите внимание на динамический параметр [lastName]
в имени файла. Мы можем получить к нему доступ, используя page
свойство, которое load
получает функция.
Опять же, мы используем его fetch
для доступа к нашей новой конечной точке /api/[lastName]
и передачи пользовательских данных в качестве свойства user
компоненту Svelte. Мы получаем доступ к этому свойству export let user
и визуализируем данные с помощью базового синтаксиса Svelte.
Теперь у вас должна быть возможность вернуться на целевую страницу и щелкнуть любое поле пользователя. Это откроет соответствующую страницу пользователя. Вы должны увидеть что-то вроде этого:
Предварительная загрузка
Есть еще одна особенность, которую я хотел бы показать, и я очень взволнован по этому поводу. SvelteKit предлагает возможность предварительной выборки данных для отдельных страниц.
Вернемся на нашу /src/routes/index.svelteстраницу и добавим атрибут sveltekit:prefetchк тегу. Вот так:
<a sveltekit:prefetch href={`/${lastName}`} class="box">
Это указывает SvelteKit на выполнение loadфункции соответствующей страницы при наведении курсора на элемент.
Попробуйте, открыв вкладку сети в вашем браузере (см. Ниже). Каждый раз, когда вы наводите указатель мыши на один из ящиков пользователя, выполняется запрос /api/[lastName]и извлекаются данные для соответствующей страницы пользователя. Это экономит дополнительные миллисекунды и обеспечивает лучший пользовательский опыт.
Кстати, это также отличный способ увидеть, как SvelteKit применяет разделение кода из коробки. Перезагрузите страницу и очистите сетевой журнал. Обратите внимание, что в самый первый раз, когда вы наводите курсор на аватар, загружаются один файл JavaScript и один файл CSS. Это фрагмент кода, соответствующий нашей /src/routes/[lastName].svelteстранице. Он загружается только один раз за сеанс страницы. Если вы наводите курсор на другой аватар, загружаются только соответствующие данные, но не JavaScript и CSS.
Вам не обязательно применять к тегу атрибут предварительной выборки. При желании вы можете выполнить предварительную prefetchвыборку программно, используя функцию модуля $ app / navigation SvelteKit.
Заключение
Работа со SvelteKit очень интуитивна. В общем, мне потребовалось всего около часа, чтобы изучить все основные функции, и результаты просто поразительны. Вы получаете невероятно быстрые, оптимизированные для SEO веб-приложения, которые обеспечивают лучший пользовательский интерфейс, который могут предоставить современные инструменты сборки.
По умолчанию SvelteKit отображает вашу страницу на сервере. На клиенте он постепенно расширяется за счет оптимизированного пакета JavaScript для обеспечения маршрутизации на стороне клиента. С помощью нескольких строк кода вы можете предварительно визуализировать отдельные страницы или предварительно выбрать данные, чтобы обеспечить мгновенную загрузку страницы и навигацию. Такие функции, как разделение кода, гарантируют, что преимущество Svelte, заключающееся в небольшом объеме выходных данных компиляции, не будет сведено на нет большими пакетами для всего приложения.
И последнее, но не менее важное: SvelteKit дает вам полную свободу в отношении всех своих функций. Всегда есть способ исключить функцию, если хотите.
SvelteKit вместе с самим Svelte меняют правила игры. И я верю, что так могло быть и со многими другими.
Добрый день, может знаете как решить…
Правильно ли я понимаю, что у svelte есть два варианта менять стиль css по нажатию кнопки. Это через объявление одноименной переменной в script и в style правило,
и через class:имя переменной, через on:click менять стиль
например
script
let show = false
style
.show {display: none}
<button on:click={show = !show} class:show
или второй вариант через if
{#if show}
style=”display: none”
{:else}
style=”display: block”
{/if}
Они все прекрасно работают
Вопрос:
А что делать когда <button мы получаем после итерации, и их стало например 3 шт
Когда я нажимаю на кнопку, открывают все кнопки, а хочется что открывалась только та на которую кликаю . Это как то можно решить движком svelte ?
Интересный вопрос.
Пример Вашего решения: https://svelte.dev/repl/cd10e875398643a0b99d144bb4b6d78a?version=3.53.1
«Движок» Svelte может предложить следующее решение:
https://svelte.dev/repl/74c4172a64dd40138c5a4baf15681dac?version=3.53.1
«`
let doHide = false;
function handleClick(event) {
event.target.classList.toggle(‘hide’);
}
{#each Array(3) as _, index}
Show/Hide Me #{index}
{/each}
button {
margin: 0.5rem;
}
.hide {
display: none;
}
«`