Мы с друзьями любим играть в настольные игры, но не всегда под рукой оказываются громоздкие коробки с играми. Тут на помощь приходит смартфон. Раньше я написал игру Ну, этот, аналог коробочной игры Бум. Затем родилась идея игры с похожей механикой, но вместо слов - случайные фильмы с кинопоиска. В качестве основы проекта я взял 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&not_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)


  1. unfriend
    24.01.2022 12:06

    Звучит пока довольно «сладко».

    А какие-нибудь минусы SvelteKit можете назвать?


    1. sanReal Автор
      24.01.2022 12:09

      1. SvelteKit еще находится в стадии активной разработки и вероятность ломающих изменений крайне высока

      2. Мало примеров и статей. Инструмент мощный, а документация покрывает только основной функционал. Например, теже переходы между экранами. В доке этого нет, сходу туториалы я только для Sapper нашел.

      3. Отстутвуют best practice по организации кода. Слишком много свободы накладывает определнную ответственность на организацию кода. Легко можно получить спагетти код


      1. xdef42
        25.01.2022 20:31

        Раз уж SvelteKit находится в стадии активной разработки и вероятность ломающих изменений крайне высока - зачем вы его используете, если ни ssr, ни роутинг / иные свистелки кита не используете? Оглядываясь на sapper (предыдущая версия kit-а) - что будете делать, когда api используемой версии kit-а будет отличаться от документации? Каждый месяц чинить сломавшиеся зависимости при обновлении на next версию кита?


        1. sanReal Автор
          25.01.2022 20:32

          Вопрос из разряда Зачем брать react, если есть jQuery.


          1. xdef42
            25.01.2022 21:34

            Вопрос актуален для 2014 года. Вы взяли svektekit, фичи которого вам не нужны, при этом kit ужас какой сырой, чем обосновано включение кита в проект?
            И еще нюанс к заключению, все вами написанное - правда, для проектов которые больше года жить не будут :)


            1. sanReal Автор
              25.01.2022 21:57

              Кажется, что статью вы не читали. Я использую фичи sveltekit, о которых рассказываю в статье. Можно это сделать на другом стеке? Безусловно. Почему я выбрал svelte? Потому что, в отличие от вас, он мне нравится. Вы же не считаете хабр местом, где стоит писать только о проверенных в 1 000 000 проектов технологиях, которые обязательно используют все компании из списка Forbes, у которых не менее 100500 звезд на гитхабе и 10 лет разработки?


              1. xdef42
                25.01.2022 22:28

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

                А svelte и sveltekit мне очень даже нравятся, собственно, это мой основной инструмент из фронтенд стека, выбором я доволен, хорошо прокачивает скилы, рекомендовать не буду из-за большого порога вхождения в самостоятельное лечение детских болячек свелта.


                1. sanReal Автор
                  25.01.2022 23:02

                  Вы же умный человек, должны понимать, что у каждого инструмента есть свои проблемы, и с чем столкнулись вы, я, к счастью, не пересекался. Но я прекрасно помню боль настройки своего конфига EsLint для create-react-app через react-app-rewired, если не готов делать eject. Это же не делает react плохим инструментом. Просто большая часть новичков не столкнутся с такими сложностями. А если столкнутся, я уверен, у них хватит навыков выбрать наиболее подходящий под свои задачи инструмент.


    1. xdef42
      25.01.2022 21:43

      Могу, того набора фич, что в коробке sveltekit вам очень быстро может перестать хватать, а комьюнити пакеты вокруг кита очень слабые, взять, к примеру sveltekit-i18n и nuxt-i18n, возможности различаются на порядки, быстрый старт приложения на sveltekit приведет к тому, что нужно будет изобретать половину интернета самостоятельно.

      Каждые несколько версий в ките меняется api + документация, совместимость с пакетами, сделанными специально под кит - приходится форкать и исправлять, потому что автор перестал заходить на гитхаб.

      Реакт/vue не такие уж и ужасные, что бы сломя голову зарываться в svelte+kit и не высовывать голову, минусы всплывают почти сразу, как только svelte появляется в продакшене


  1. elishagg
    24.01.2022 19:44
    +1

    В случае длинного названия фильма кнопка уходит почти за видимую часть блока. Нужен скролл или адаптивность текста.


    1. sanReal Автор
      24.01.2022 19:45

      а можете прислать скрин? И девайс, на котором происходит такое поведение?


      1. elishagg
        24.01.2022 19:56

        Мобильный девайс. Окно браузера 360 × 657px.


      1. elishagg
        24.01.2022 19:58


        1. sanReal Автор
          24.01.2022 21:40

          Спасибо! Обязательно исправлю