Мы с друзьями любим играть в настольные игры, но не всегда под рукой оказываются громоздкие коробки с играми. Тут на помощь приходит смартфон. Раньше я написал игру Ну, этот, аналог коробочной игры Бум. Затем родилась идея игры с похожей механикой, но вместо слов - случайные фильмы с кинопоиска. В качестве основы проекта я взял SvelteKit. В статье расскажу об интересном функционале SvelteKit и быстром деплое на площадке Vercel.
Встречайте, О, кинчик!
Немного о проекте
О, кинчик - это игра, по механике похожая на Алиас или Активити. Только вместо скучных слов - фильмы из базы кинопоиска. Как показала практика, отгадывать Человек на проволоке или Реквием по мечте куда интересней, чем банальные слова типа "рыбак" и "охотник".
Игроки разбиваются на две команды, затем игрок за отведенное время пытается объяснить своей команде как можно больше фильмов. Когда фильмы закончатся, команда с большим количеством отгаданных фильмов побеждает.
Исходный код проекта доступен в Gitlab, сыграть можно здесь.
Я не буду углубляться в особенности Svelte (об этом можно прочитать в моих предыдущих статьях: раз, два, три, четыре), а больше уделю внимания функциям, которые мне понравились в SvelteKit.
Что такое SvelteKit
SvelteKit это метафреймворк, построенный на базе svelte с файл роутером (похожим на Next), поддержкой SSR, статической генерацией, serveless и невероятным dev experience, который дает Svelte.
Запуск проекта
Чтобы запустить проект достаточно выполнить команду:
npm init svelte@next my-app
Мастер создания проекта спросит, хотите ли вы использовать демо данные, нужна ли вам поддержка TypeScript, EsLint и Prettier. И подскажет, как установить зависимости и запустить дев сервер.
Api
Для получения данных о фильмах из кинопоиска, мы будем использовать api "Случайный фильм!". Напрямую запросить данные из фронтенда у нас не получится, мы столкнемся с CORS ограничениями. Поэтому воспользуемся функционалом Endpoints, который позволяет создавать серверные функции.
Для этого достаточно создать файл .js
или .ts
, который будет экспортировать функцию get
, post
, put
, patch
или del
, для соответвующего HTTP метода.
api/index.js
import parse from 'node-html-parser';
export async function get({ url }) {
const min_years = url.searchParams.get('min_years') || 1920;
const max_years = url.searchParams.get('max_years') || new Date().getFullYear();
const response = await fetch(
`https://www.kinopoisk.ru/chance/?item=true¬_show_rated=false&count=5&max_years=${max_years}&min_years=${min_years}&rnd=${Math.random()}`
);
const json = await response.json();
const data = json.map((item) => {
const root = parse(item);
const id = root.querySelector('.movieBlock').getAttribute('data-id-film');
const source = root.querySelector('img').getAttribute('src');
const rating =
Math.round(Number(root.querySelector('.WidgetStars').getAttribute('value')) * 10) / 10;
const src = `https://kinopoisk.ru/${source.slice(3)}`;
const nameRaw = root.querySelector('.filmName a').textContent;
const name = nameRaw.replace(/ /g, ' ');
const yearRaw = root.querySelector('.filmName span').textContent;
const year = yearRaw.match(/\(\d{4}\)/)[0].slice(1, -1);
return { id, src, name, rating, year };
});
return {
body: data
};
}
Теперь при заходе на страницу http://localhost:3000/api
будет отдаваться набор из случайных фильмов. Поскольку фронтенд и /api
теперь находятся на одном домене, можно спокойно получать данные.
Роутинг
Игровой процесс разделен по экранам. Я использовал встроенный файл роутер для навигации между ними. Для создания страницы достаточно создать файл в папке routes
, соответствующий пути страницы. Например, файл src/routes/turn.svelte
будет соответстовать странице http://localhost:3000/turn
. Подбронее про роутинг и систему шаблонов можно прочитать в документации.
Поскольку начать игру можно только с главного экрана, нужно сделать редирект с остальных страниц в корень. Вообще, в SvelteKit есть функционал Loading, который позволяет выполнять код на стороне сервера, что-то вроде getServerSideProps из Next.js. Но я воспользовался функционалом Hooks, который позволяет перехватывать выполнение на стороне сервера и по-разному обрабатывать ответы. В файле src/hooks/index.js
содержится следующая логика обработки:
src/hooks/index.js
export async function handle({ request, resolve }) {
const response = ['/', '/rules', '/api'].includes(request.url.pathname)
? await resolve(request)
: { status: 303, headers: { location: '/' } };
return response;
}
Теперь при заходе на любой адрес, отличный от /
, /rules
и /api
, получим редирект в корень проекта. При этом переходы на уже загруженной странице будут обрабатываться как обычно.
Переходы между экранами
Во время разработки я захотел сделать переходы между страницами с эффектом прокрутки кинопленки. Svelte имеет богатый функционал анимаций, который легко можно встроить для анимаций переходов между страницами. Для этого я завернул страницы в компонент Frames.svelte
src/components/Frames.svelte
<script>
import {fly} from 'svelte/transition'
import {linear} from 'svelte/easing'
let windowHeight;
</script>
<div
class="frame"
in:fly={{ y: windowHeight, duration: 500, opacity: 1, easing: linear }}
out:fly={{ y: -windowHeight, duration: 500, opacity: 1, easing: linear}}
>
<div class="frameBg left" />
<div class="frameBg right" />
<slot />
</div>
<svelte:window bind:innerHeight={windowHeight} />
<style>
.frame {
overflow: hidden;
box-sizing: border-box;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 16px 40px;
}
.frameBg {
position: absolute;
top: 0;
bottom: 0;
width: 31px;
background-repeat: repeat-y;
background-image: url(/img/frame.svg);
z-index: 2;
}
.left {
left: 0;
}
.right {
right: 0;
}
</style>
Когда осуществляется переход, к текущей странице применяется анимация out:fly
, а к новой применяется анимация in:fly
. Задав нужные параметры, легко получить эффект прокрутки кинопленки. Кстати, обратите внимание на выражение:
<svelte:window bind:innerHeight={windowHeight} />
Такая конструкция позволяет хранить в переменной текущую высоту окна браузера. При изменении размеров, в переменной будет обновленное значение. Эта функция не раз спасала меня при верстке макетов для мобильных браузеров safari, где строка навигации включена в css выражение 100vh
.
Абсолютные импорты
Под капотом у SvelteKit скрывается сборщик Vite, что позволяет использовать возможности этого инструмента. В проекте я использовал абсолютные импорты, чтобы получить быстрый доступ к компонентам и стору. Для этого достаточно добавить в файл svelte.config.js
директиву, определяющую импорты
svelte.config.js
import adapter from '@sveltejs/adapter-auto';
import path from 'path';
const config = {
kit: {
adapter: adapter(),
target: '#svelte',
vite: {
resolve: {
alias: {
components: path.resolve('./src/components'),
store: path.resolve('./src/store.js')
}
}
}
}
};
export default config;
Деплой
Для деплоя я использовал площадку Vercel. Чтобы задеплоить проект, достаточно выбрать репозиторий и указать фреймворк SvelteKit. После клика Deploy
, проект будет собран и развернут на площадке. В дальнейшем, на каждый коммит в выбранную ветку будет автоматически запускаться сборка и деплой проекта.
В качестве заключения
На мой взгляд, разработка и деплой современных веб проектов не были никогда такими простыми. Больше не нужно вручную настраивать сборщик, SSR и кучу всего, что появилось в веб разработке за последние годы. SvelteKit из коробки предоставляет обширные возможности, которые дает разработчикам Svelte, при этом добавляя серверный рендеринг, возможности писать api ендпоинты, использовать файловый роутинг и многое другое. А Vercel позволяет развернуть проект за считаные секунды.
SvelteKit находится в фазе активной разработки и что-то к релизу версии 1.0.0 может измениться, но уже сейчас я рекомендую обратить внимание на этот фреймворк и попробовать его в пет проектах.
Телеграм-группа русского сообщества Svelte: @sveltejs
Комментарии (14)
elishagg
24.01.2022 19:44+1В случае длинного названия фильма кнопка уходит почти за видимую часть блока. Нужен скролл или адаптивность текста.
unfriend
Звучит пока довольно «сладко».
А какие-нибудь минусы SvelteKit можете назвать?
sanReal Автор
SvelteKit еще находится в стадии активной разработки и вероятность ломающих изменений крайне высока
Мало примеров и статей. Инструмент мощный, а документация покрывает только основной функционал. Например, теже переходы между экранами. В доке этого нет, сходу туториалы я только для Sapper нашел.
Отстутвуют best practice по организации кода. Слишком много свободы накладывает определнную ответственность на организацию кода. Легко можно получить спагетти код
xdef42
Раз уж SvelteKit находится в стадии активной разработки и вероятность ломающих изменений крайне высока - зачем вы его используете, если ни ssr, ни роутинг / иные свистелки кита не используете? Оглядываясь на sapper (предыдущая версия kit-а) - что будете делать, когда api используемой версии kit-а будет отличаться от документации? Каждый месяц чинить сломавшиеся зависимости при обновлении на next версию кита?
sanReal Автор
Вопрос из разряда Зачем брать react, если есть jQuery.
xdef42
Вопрос актуален для 2014 года. Вы взяли svektekit, фичи которого вам не нужны, при этом kit ужас какой сырой, чем обосновано включение кита в проект?
И еще нюанс к заключению, все вами написанное - правда, для проектов которые больше года жить не будут :)
sanReal Автор
Кажется, что статью вы не читали. Я использую фичи sveltekit, о которых рассказываю в статье. Можно это сделать на другом стеке? Безусловно. Почему я выбрал svelte? Потому что, в отличие от вас, он мне нравится. Вы же не считаете хабр местом, где стоит писать только о проверенных в 1 000 000 проектов технологиях, которые обязательно используют все компании из списка Forbes, у которых не менее 100500 звезд на гитхабе и 10 лет разработки?
xdef42
Не соглашусь, статью я прочитал, вы доступно описали как создать проект на kit, показали некоторые возможности svelte и кита, к самой статье вопросов нет, я лишь крайне не согласен с первым абзацем вашего заключения, внучную придется настраивать те вещи, о которых разработчик до знакомства со svelte и не подозревал, изобретать заного все велосипеды и тд, это никак нельзя назвать "очень простая разработка веб проектов".
А svelte и sveltekit мне очень даже нравятся, собственно, это мой основной инструмент из фронтенд стека, выбором я доволен, хорошо прокачивает скилы, рекомендовать не буду из-за большого порога вхождения в самостоятельное лечение детских болячек свелта.
sanReal Автор
Вы же умный человек, должны понимать, что у каждого инструмента есть свои проблемы, и с чем столкнулись вы, я, к счастью, не пересекался. Но я прекрасно помню боль настройки своего конфига EsLint для create-react-app через react-app-rewired, если не готов делать eject. Это же не делает react плохим инструментом. Просто большая часть новичков не столкнутся с такими сложностями. А если столкнутся, я уверен, у них хватит навыков выбрать наиболее подходящий под свои задачи инструмент.
xdef42
Могу, того набора фич, что в коробке sveltekit вам очень быстро может перестать хватать, а комьюнити пакеты вокруг кита очень слабые, взять, к примеру sveltekit-i18n и nuxt-i18n, возможности различаются на порядки, быстрый старт приложения на sveltekit приведет к тому, что нужно будет изобретать половину интернета самостоятельно.
Каждые несколько версий в ките меняется api + документация, совместимость с пакетами, сделанными специально под кит - приходится форкать и исправлять, потому что автор перестал заходить на гитхаб.
Реакт/vue не такие уж и ужасные, что бы сломя голову зарываться в svelte+kit и не высовывать голову, минусы всплывают почти сразу, как только svelte появляется в продакшене