SvelteKit является последним из того, что я бы назвал платформами приложений следующего поколения. Он, конечно же, формирует приложение для вас с маршрутизацией на основе файлов, развертыванием и рендерингом на стороне сервера, которые Next делал всегда. Но SvelteKit также поддерживает вложенные макеты, мутации сервера, которые синхронизируют данные на вашей странице, и некоторые другие тонкости, о которых мы поговорим.
Этот пост предназначен для введения на высоком уровне, чтобы, надеюсь, заинтересовать тех, кто никогда не использовал SvelteKit. Это будет спокойный тур. Если вам нравится то, что вы видите, полные документы здесь.
В некотором смысле это сложный пост для написания. SvelteKit — это рамки приложения. Он существует, чтобы помочь вам создавать… ну, приложения. Это затрудняет демонстрацию. Невозможно построить все приложение в сообщении блога. Поэтому вместо этого мы немного воспользуемся нашим воображением. Мы создадим скелет приложения, создадим несколько пустых заполнителей пользовательского интерфейса и жестко закодированные статические данные. Цель состоит не в том, чтобы создать реальное приложение, а в том, чтобы показать вам, как работают движущиеся части SvelteKit, чтобы вы могли создать собственное приложение.
С этой целью мы создадим проверенное и настоящее приложение To-Do в качестве примера. Но не волнуйтесь, это будет гораздо больше связано с тем, чтобы увидеть, как работает SvelteKit, чем с созданием еще одного приложения To-Do.
Код для всего в этом посте доступно на GitHub. Этот проект также развернуто на Верселе для живой демонстрации.
Создание вашего проекта
Запустить новый проект SvelteKit достаточно просто. Бег npm create your-app-name
в терминале и ответьте на вопросы. Обязательно выберите «Skeleton Project», но в противном случае сделайте любой выбор для TypeScript, ESLint и т. д.
После создания проекта запустите npm i
и npm run dev
и сервер разработки должен начать работать. Зажечь localhost:5173
в браузере, и вы получите страницу-заполнитель для каркасного приложения.
Базовая маршрутизация
Обратите внимание, что routes
папку под src
. Он содержит код для всех наших маршрутов. уже есть +page.svelte
файл там с содержимым для корня /
маршрут. Независимо от того, где вы находитесь в иерархии файлов, фактическая страница для этого пути всегда имеет имя +page.svelte
. Имея это в виду, давайте создадим страницы для /list
, /details
, /admin/user-settings
и admin/paid-status
, а также добавьте текстовые заполнители для каждой страницы.
Ваш макет файла должен выглядеть примерно так:
Вы должны иметь возможность перемещаться, изменяя URL-адреса в адресной строке браузера.
Планировка палуб
Нам нужны навигационные ссылки в нашем приложении, но мы, конечно же, не хотим копировать разметку для них на каждой создаваемой странице. Итак, давайте создадим +layout.svelte
файл в корне нашего routes
папку, которую SvelteKit будет рассматривать как глобальный шаблон для всех страниц. Давайте добавим к нему некоторый контент:
<nav> <ul> <li> <a href="/ru/">Home</a> </li> <li> <a href="/ru/list">To-Do list</a> </li> <li> <a href="/ru/admin/paid-status">Account status</a> </li> <li> <a href="/ru/admin/user-settings">User settings</a> </li> </ul>
</nav> <slot /> <style> nav { background-color: beige; } nav ul { display: flex; } li { list-style: none; margin: 15px; } a { text-decoration: none; color: black; }
</style>
Некоторая элементарная навигация с некоторыми основными стилями. Особое значение имеет <slot />
ярлык. Это не слот, который вы используете с веб-компонентами и теневым DOM, а скорее функция Svelte, указывающая, куда поместить наш контент. Когда страница отображается, содержимое страницы будет скользить туда, где находится слот.
Теперь у нас есть навигация! Мы не выиграем никаких дизайнерских конкурсов, но мы и не пытаемся.
Вложенные макеты
Что, если бы мы захотели, чтобы все наши страницы администрирования наследовали обычный макет, который мы только что создали, но также делили некоторые элементы, общие для всех страниц администрирования (но только для страниц администрирования)? Нет проблем, мы добавим еще +layout.svelte
файл в нашем корне admin
каталог, который будет унаследован всем, что находится под ним. Давайте сделаем это и добавим этот контент:
<div>This is an admin page</div> <slot /> <style> div { padding: 15px; margin: 10px 0; background-color: red; color: white; }
</style>
Мы добавляем красный баннер, указывающий, что это страница администратора, а затем, как и раньше, <slot />
обозначая, куда мы хотим, чтобы содержимое нашей страницы шло.
Наш корневой макет до рендеринга. Внутри корневого макета находится <slot />
ярлык. Содержимое вложенного макета переходит в корневой макет. <slot />
. И, наконец, вложенный макет определяет свой собственный <slot />
, в который отображается содержимое страницы.
Если вы перейдете на страницы администратора, вы должны увидеть новый красный баннер:
Определение наших данных
Хорошо, давайте визуализируем некоторые фактические данные — или, по крайней мере, посмотрим, как мы можем визуализировать некоторые фактические данные. Есть сотни способов создать базу данных и подключиться к ней. Этот пост посвящен SvelteKit, а не управлению DynamoDB, поэтому вместо этого мы «загрузим» некоторые статические данные. Но мы будем использовать все те же механизмы для чтения и обновления, которые вы использовали бы для реальных данных. Для настоящего веб-приложения замените функции, возвращающие статические данные, на функции, подключающиеся и запрашивающие любую базу данных, которую вы используете.
Давайте создадим простейший модуль в lib/data/todoData.ts
который возвращает некоторые статические данные вместе с искусственными задержками для имитации реальных запросов. ты увидишь это lib
папка, импортированная в другое место через $lib
. Это функция SvelteKit для конкретной папки, и вы даже можете добавить свои собственные псевдонимы.
let todos = [ { id: 1, title: "Write SvelteKit intro blog post", assigned: "Adam", tags: [1] }, { id: 2, title: "Write SvelteKit advanced data loading blog post", assigned: "Adam", tags: [1] }, { id: 3, title: "Prepare RenderATL talk", assigned: "Adam", tags: [2] }, { id: 4, title: "Fix all SvelteKit bugs", assigned: "Rich", tags: [3] }, { id: 5, title: "Edit Adam's blog posts", assigned: "Geoff", tags: [4] },
]; let tags = [ { id: 1, name: "SvelteKit Content", color: "ded" }, { id: 2, name: "Conferences", color: "purple" }, { id: 3, name: "SvelteKit Development", color: "pink" }, { id: 4, name: "CSS-Tricks Admin", color: "blue" },
]; export const wait = async amount => new Promise(res => setTimeout(res, amount ?? 100)); export async function getTodos() { await wait(); return todos;
} export async function getTags() { await wait(); return tags.reduce((lookup, tag) => { lookup[tag.id] = tag; return lookup; }, {});
} export async function getTodo(id) { return todos.find(t => t.id == id);
}
Функция для возврата плоского массива наших элементов списка дел, поиск наших тегов и функция для извлечения одного дела (мы будем использовать последний на нашей странице сведений).
Загрузка наших данных
Как мы можем получить эти данные на наших страницах Svelte? Есть несколько способов, но сейчас давайте создадим +page.server.js
файл в нашем list
папку и поместите в нее это содержимое:
import { getTodos, getTags } from "$lib/data/todoData"; export function load() { const todos = getTodos(); const tags = getTags(); return { todos, tags, };
}
Мы определили load()
функция, которая извлекает данные, необходимые для страницы. Заметьте, что мы не await
-ing звонки в наш getTodos
и getTags
асинхронные функции. Это создаст водопад загрузки данных, поскольку мы ждем поступления наших задач перед загрузкой наших тегов. Вместо этого мы возвращаем необработанные обещания из load
, а SvelteKit выполняет необходимую работу для await
их.
Итак, как нам получить доступ к этим данным из нашего компонента страницы? SvelteKit предоставляет data
prop для нашего компонента с данными о нем. Мы будем получать доступ к нашим задачам и тегам из него, используя реактивное присвоение.
Наш компонент страницы списка теперь выглядит так.
<script> export let data; $: ({ todo, tags } = data);
</script> <table cellspacing="10" cellpadding="10"> <thead> <tr> <th>Task</th> <th>Tags</th> <th>Assigned</th> </tr> </thead> <tbody> {#each todos as t} <tr> <td>{t.title}</td> <td>{t.tags.map((id) => tags[id].name).join(', ')}</td> <td>{t.assigned}</td> </tr> {/each} </tbody>
</table> <style> th { text-align: left; }
</style>
И это должно отображать наши задачи!
Группы макетов
Прежде чем мы перейдем к странице сведений и изменим данные, давайте взглянем на действительно удобную функцию SvelteKit: группы макетов. Мы уже видели вложенные макеты для всех страниц администрирования, но что, если мы хотим разделить макет между произвольными страницами на одном уровне нашей файловой системы? В частности, что, если бы мы хотели использовать макет только для нашей страницы списка и нашей страницы сведений? У нас уже есть глобальный макет на этом уровне. Вместо этого мы можем создать новый каталог, но с именем в скобках, например:
Теперь у нас есть группа макетов, которая охватывает наши страницы List и Details. я назвал это (todo-management)
но вы можете назвать его как угодно. Чтобы было ясно, это имя будет не влияют на URL-адреса страниц внутри группы макетов. URL-адреса останутся прежними; Группы макетов позволяют вам добавлять общие макеты на страницы, при этом они не составляют весь каталог в routes
.
We может добавить +layout.svelte
файл и некоторые глупости <div>
баннер с надписью «Эй, мы управляем задачами». Но давайте сделаем что-нибудь более интересное. Макеты могут определять load()
функции для предоставления данных для всех маршрутов под ними. Давайте воспользуемся этой функциональностью для загрузки наших тегов — так как мы будем использовать наши теги в нашем details
страница — в дополнение к list
страница у нас уже есть.
На самом деле заставлять группу компоновки просто предоставлять один фрагмент данных почти наверняка не стоит; лучше продублировать эти данные в load()
функция для каждой страницы. Но для этого поста это послужит поводом для того, чтобы увидеть новую функцию SvelteKit!
Во-первых, давайте зайдем в нашу list
страницы +page.server.js
файл и удалите из него теги.
import { getTodos, getTags } from "$lib/data/todoData"; export function load() { const todos = getTodos(); return { todos, };
}
Наша страница со списком теперь должна выдавать ошибку, поскольку нет tags
объект. Давайте исправим это, добавив +layout.server.js
файл в нашей группе макетов, затем определите load()
функция, которая загружает наши теги.
import { getTags } from "$lib/data/todoData"; export function load() { const tags = getTags(); return { tags, };
}
И точно так же наша страница со списком снова отображается!
Мы загружаем данные из разных мест
Давайте уточним, что здесь происходит:
- Мы определили
load()
функция для нашей группы макетов, которую мы поместили в+layout.server.js
. - Это обеспечивает данные для Найти страниц, которые обслуживает макет — что в данном случае означает наши страницы списка и сведений.
- Наша страница списка также определяет
load()
функция, которая идет в своем+page.server.js
. - SvelteKit выполняет тяжелую работу по получению результатов из этих источников данных, объединяет их вместе и делает доступными в
data
.
Наша страница с подробностями
Мы будем использовать нашу страницу сведений для редактирования элемента списка дел. Во-первых, давайте добавим столбец в таблицу на нашей странице списка, которая ссылается на страницу сведений с идентификатором элемента списка дел в строке запроса.
<td><a href="/ru/details?id={t.id}">Edit</a></td>
Теперь давайте создадим нашу страницу Details. Во-первых, мы добавим загрузчик для захвата элемента списка дел, который мы редактируем. Создать +page.server.js
in /details
, с этим содержанием:
import { getTodo, updateTodo, wait } from "$lib/data/todoData"; export function load({ url }) { const id = url.searchParams.get("id"); console.log(id); const todo = getTodo(id); return { todo, };
}
Наш погрузчик поставляется с url
свойство, из которого мы можем извлечь значения строки запроса. Это упрощает поиск элемента списка дел, который мы редактируем. Давайте визуализируем эту задачу вместе с функциональностью для ее редактирования.
SvelteKit имеет замечательные встроенные возможности мутации, если вы используете формы. Помните формы? Вот наша страница сведений. Я опустил стили для краткости.
<script> import { enhance } from "$app/forms"; export let data; $: ({ todo, tags } = data); $: currentTags = todo.tags.map(id => tags[id]);
</script> <form use:enhance method="post" action="?/editTodo"> <input name="id" type="hidden" value="{todo.id}" /> <input name="title" value="{todo.title}" /> <div> {#each currentTags as tag} <span style="{`color:" ${tag.color};`}>{tag.name}</span> {/each} </div> <button>Save</button>
</form>
Мы берем теги, как и раньше, из загрузчика нашей группы макетов, а элемент списка дел — из загрузчика нашей страницы. Мы хватаем фактическое tag
объекты из списка дел с идентификаторами тегов, а затем визуализировать все. Создаем форму со скрытым вводом для ID и реальным вводом для заголовка. Мы отображаем теги, а затем предоставляем кнопку для отправки формы.
Если вы заметили use:enhance
, который просто указывает SvelteKit использовать прогрессивное улучшение и Ajax для отправки нашей формы. Вы, вероятно, всегда будете использовать это.
Как сохранить наши правки?
Обратите внимание, что action="?/editTodo"
атрибут на самой форме? Это говорит нам, куда мы хотим отправить наши отредактированные данные. Для нашего случая мы хотим представить editTodo
"действие."
Давайте создадим его, добавив следующее в +page.server.js
файл, который у нас уже есть для деталей (который в настоящее время имеет load()
функция, чтобы захватить нашу задачу):
import { redirect } from "@sveltejs/kit"; // ... export const actions = { async editTodo({ request }) { const formData = await request.formData(); const id = formData.get("id"); const newTitle = formData.get("title"); await wait(250); updateTodo(id, newTitle); throw redirect(303, "/list"); },
};
Действия формы дают нам request
объект, который обеспечивает доступ к нашему formData
, который имеет get
метод для наших различных полей формы. Мы добавили этот скрытый ввод для значения идентификатора, чтобы мы могли получить его здесь, чтобы найти элемент списка дел, который мы редактируем. Имитируем задержку, вызываем новую updateTodo()
метод, а затем перенаправить пользователя обратно на /list
страницы. updateTodo()
метод просто обновляет наши статические данные; в реальной жизни вы бы запустили какое-то обновление в любом хранилище данных, которое вы используете.
export async function updateTodo(id, newTitle) { const todo = todos.find(t => t.id == id); Object.assign(todo, { title: newTitle });
}
Давайте попробуем. Сначала мы перейдем на страницу списка:
Теперь давайте нажмем кнопку «Редактировать» для одного из элементов списка дел, чтобы открыть страницу редактирования в /details
.
Мы собираемся добавить новый заголовок:
Теперь нажмите Сохранить. Это должно вернуть нас к нашему /list
страницу с новым названием задачи.
Как появилось новое название? Это было автоматически. Как только мы перенаправились на /list
page, SvelteKit автоматически перезапустил все наши загрузчики, как это было бы в любом случае. Это ключевое преимущество фреймворков приложений следующего поколения, таких как SvelteKit. Ремикси Следующий 13 предоставлять. Вместо того, чтобы предоставить вам удобный способ рендеринга страниц, а затем пожелать вам удачи в получении любых конечных точек, которые могут вам понадобиться для обновления данных, они интегрируют изменение данных вместе с загрузкой данных, позволяя им работать в тандеме.
Несколько вещей, которые вам могут быть интересны…
Это обновление мутации не кажется слишком впечатляющим. Загрузчики будут повторно запускаться всякий раз, когда вы перемещаетесь. Что, если бы мы не добавили редирект в действие формы, а остались на текущей странице? SvelteKit будет выполнять обновление в действии формы, как и раньше, но все еще повторно запустить все загрузчики для текущей страницы, включая загрузчики в макете(ах) страницы.
Можем ли мы иметь более целенаправленные средства аннулирования наших данных? Например, наши теги не редактировались, поэтому в реальной жизни нам не хотелось бы повторно запрашивать их. Да, то, что я показал вам, — это просто поведение форм по умолчанию в SvelteKit. Вы можете отключить поведение по умолчанию, обеспечение обратного звонка use:enhance
. Затем SvelteKit предоставляет руководство функции аннулирования.
Загрузка данных при каждой навигации потенциально затратна и не нужна. Могу ли я кэшировать эти данные, как я это делаю с такими инструментами, как react-query
? Да просто по другому. SvelteKit позволяет вам установить (а затем соблюдать) заголовки управления кешем, которые уже предоставляет Интернет. И я расскажу о механизмах инвалидации кеша в следующем посте.
Все, что мы делали в этой статье, использует статические данные и изменяет значения в памяти. Если вам нужно вернуть все назад и начать заново, остановите и перезапустите npm run dev
Процесс узла.
Подведение итогов
Мы едва коснулись SvelteKit, но, надеюсь, вы увидели достаточно, чтобы заинтересоваться им. Я не могу вспомнить, когда в последний раз я находил веб-разработку такой увлекательной. Благодаря тому, что такие вещи, как объединение, маршрутизация, SSR и развертывание, выполняются из коробки, я трачу больше времени на кодирование, чем на настройку.
Вот еще несколько ресурсов, которые вы можете использовать в качестве следующих шагов в изучении SvelteKit:
- SEO-контент и PR-распределение. Получите усиление сегодня.
- Платоблокчейн. Интеллект метавселенной Web3. Расширение знаний. Доступ здесь.
- Источник: https://css-tricks.com/getting-started-with-sveltekit/
- 1
- 10
- 100
- 11
- 7
- 9
- 98
- a
- в состоянии
- О нас
- об этом
- доступ
- Учетная запись
- Действие
- действия
- Адам
- добавленный
- дополнение
- адрес
- Администратор
- продвинутый
- влиять на
- Все
- Позволяющий
- рядом
- уже
- всегда
- количество
- и
- Другой
- ответ
- кто угодно
- приложение
- Применение
- Приложения
- прикладной
- около
- массив
- гайд
- искусственный
- назначенный
- Автоматический
- автоматически
- доступен
- Ждите
- назад
- фон
- баннер
- бар
- основной
- до
- ЛУЧШЕЕ
- Лучшая
- между
- Немного
- Черный
- Блог
- Сообщения в блоге
- Синии
- Коробка
- приносить
- браузер
- ошибки
- строить
- построенный
- встроенный
- кнопка
- Кэш
- призывают
- Объявления
- возможности
- случаев
- конечно
- сложные
- изменения
- Очистить
- код
- Кодирование
- цвет
- Column
- как
- Общий
- Соревнования
- компонент
- компоненты
- конференции
- Свяжитесь
- Соединительный
- Консоли
- содержание
- Удобно
- может
- "Курс"
- покрытие
- Обложки
- Создайте
- создали
- Создающий
- Текущий
- В настоящее время
- данным
- База данных
- По умолчанию
- Определяет
- задерживать
- задержки
- развертывание
- Проект
- подробнее
- Дев
- Развитие
- DID
- Дисплей
- не
- дело
- Dont
- каждый
- в другом месте
- достаточно
- Весь
- цельность
- ошибка
- и т.д
- Даже
- Каждая
- многое
- пример
- возбужденный
- Возбуждение
- существует
- дорогим
- экспорт
- выполнимый
- Особенность
- несколько
- Поля
- Файл
- Файлы
- в заключение
- конец
- Для пожарных
- First
- фиксированный
- плоский
- после
- навсегда
- форма
- формат
- формы
- найденный
- каркасы
- от
- полный
- fun
- функция
- функциональность
- Функции
- получить
- получающий
- Дайте
- Отдаете
- Глобальный
- Go
- цель
- идет
- будет
- захват
- группы
- Группы
- происходить
- Жесткий
- Заголовки
- помощь
- здесь
- Скрытый
- иерархия
- на высшем уровне
- имеет
- С надеждой
- горизонтальный
- Как
- HTML
- HTTPS
- БОЛЬНОЙ
- воображение
- Импортировать
- значение
- впечатляющий
- in
- В том числе
- начальный
- вход
- вместо
- интегрировать
- интересный
- Введение
- IT
- пункты
- саму трезвость
- JavaScript
- Основные
- Фамилия
- последний
- Планировка
- изучение
- Lets
- уровень
- Li
- ЖИЗНЬЮ
- легкий
- Вероятно
- связи
- Список
- жить
- загрузка
- загрузчик
- погрузка
- грузы
- Длинное
- посмотреть
- ВЗГЛЯДЫ
- поиск
- удачи
- машины
- сделать
- ДЕЛАЕТ
- Создание
- управления
- руководство
- Маржа
- Вопрос
- означает
- Память
- просто
- объединение
- метод
- может быть
- против
- Модули
- БОЛЕЕ
- двигаться
- перемещение
- с разными
- имя
- Названный
- навигационный
- Откройте
- Навигация
- необходимо
- Необходимость
- Новые
- следующий
- узел
- "обычные"
- номер
- объект
- объекты
- ONE
- заказ
- Другое
- в противном случае
- собственный
- особый
- путь
- Выполнять
- выбирать
- кусок
- штук
- заполнитель
- Платон
- Платон Интеллектуальные данные
- ПлатонДанные
- Точка
- После
- Блог
- потенциально
- Подготовить
- Проблема
- процесс
- производит
- приложение
- Проект
- Обещает
- собственность
- защищенный
- обеспечивать
- приводит
- Тянет
- положил
- вопрос
- Сырье
- Читать
- реальные
- реальная жизнь
- Реальность
- Red
- переориентировать
- Несмотря на
- оставаться
- помнить
- удаление
- оказание
- оказывает
- запросить
- Полезные ресурсы
- Итоги
- возвращают
- возвращение
- Возвращает
- возвращаться
- Богатые
- корень
- дорога
- маршруты
- Run
- Бег
- то же
- Сохранить
- видя
- служит
- набор
- Shadow
- Поделиться
- общие
- должен
- показывать
- просто
- просто
- с
- одинарной
- Слайд-шоу
- So
- некоторые
- удалось
- Источники
- тратить
- Начало
- и политические лидеры
- остались
- Шаги
- Stop
- отправить
- Поддержка
- Поверхность
- система
- ТАБЛИЦЫ
- TAG
- взять
- с
- Говорить
- Тандем
- целевое
- говорит
- шаблон
- Терминал
- Ассоциация
- вещи
- по всему
- время
- Название
- в
- вместе
- слишком
- инструменты
- Тур
- лечить
- правда
- ОЧЕРЕДЬ
- Машинопись
- ui
- под
- Обновление ПО
- Updates
- URL
- us
- использование
- Информация о пользователе
- ценностное
- Наши ценности
- различный
- с помощью
- Вид
- ждать
- стремятся
- способы
- Web
- веб-компоненты
- Веб-разработка
- Что
- который
- белый
- будете
- выиграть
- без
- замечательный
- Работа
- работает
- стоимость
- бы
- записывать
- Ты
- ВАШЕ
- зефирнет