これなに
2021年12月22日に個人でリリースした映画診断サイト「Go! Go! Movie!」の技術について書いてます。
TOP | 診断 | 結果 |
---|---|---|
いくつか質問に答えたら、おすすめの映画を紹介してくれます。
なんで作った?
- 先日、コーヒーサブスクの診断コンテンツがTwitterで表示されてやってみたところ、面白かったので 「Svelteで作るならどうなるだろう?」 と衝動にかられて
- コロナでミニシアターが苦しんでいるので、どうせなら映画館に足を運ぶきっかけになったらいいなと思って
構想
- 質問/結果のノード
- 回答を次の質問のノードに関連づける
で作れそうと分かりました。
Go!Go!Movie!を支える技術
TypeScript
TypeScriptの型を記述することで、先に述べた2点を表現できて開発しやすかった
- 質問/結果のノード
- 回答を次の質問のノードに関連づける
**ノードの型のコード**(開くならクリック)
ノードの型
type NodeType = 'question' | 'result';
type BaseNode = {
id: number;
nodeType: NodeType;
text: string;
imagePath: string;
}
type Answer = { text: string; nextNodeId: number; };
/** 質問ノード */
export type QuestionNode = BaseNode & {
answers: Answer[];
}
/** 結果ノード */
export type ResultNode = BaseNode & {
url: string;
}
export type Node = QuestionNode | ResultNode;
Svelte
- Svelteの魅力の一つは、storeを簡単に扱えること
- 今回の診断サイトでは回答するだけでなく戻ることもできるため、
nodeHistory
というカスタムストアを作成して処理を集約しました
**nodeHistoryのコード**(開くならクリック)
nodeHistory.ts(カスタムストア)
import { get, writable } from "svelte/store";
/** カスタムストアを作成する */
const createStore = () => {
const INITIAL_VALUE = [1];
const store = writable(INITIAL_VALUE);
return {
subscribe: store.subscribe,
/** 現在のノードIDを取得 */
current: () => {
const value = get(store);
return value[value.length - 1];
},
/** 回答したら次のノードIDをセットする */
next: (nextNodeId: number) => store.update(n => [...n, nextNodeId]),
/** 戻るときに最新のノードIDを削除する */
back: () => store.update(n => n.slice(0, -1)),
/** 初期化 */
clear: () => store.set(INITIAL_VALUE),
/** 最初のノードか判定 */
isFirst: () => get(store).length === 1,
}
}
export const nodeHistory = createStore();
SvelteKit + Vercel
-
Viteを使用しておりビルドが高速なため開発体験が良い
- 以前、書いた「Vite (ヴィート)はなぜ早い?」もよろしければ読んでください
- Vercel
- アダプターを切り替えるだけでVercelなどに最適なビルドをしてくれる
- SvelteKitが公式に提供している
adapter-vercel
を使える - デプロイ手順は以前書いたこちらの記事を参照
- SvelteKitが公式に提供している
- 無料でアプリケーションをホストしてくれる(個人開発なら十分)
- GitHubにプルリクだすと自動で検証環境を用意してくれるから楽
- アダプターを切り替えるだけでVercelなどに最適なビルドをしてくれる
Tailwind CSS
- マークアップやったことないエンジニアでもとっつきやすい
- スタイル書いたことなくてもtailwindcomponents を参考にすれば効率はよい
- class名を考える必要がないので開発効率UP
- 下記のようなアニメーションも簡単に作れます
**アニメーションの設定**(開くならクリック)
-
gogo
というカスタムアニメーションを定義する
tailwind.config.cjs
const config = {
content: ['./src/**/*.{html,js,svelte,ts}'],
theme: {
extend: {
+ animation: {
+ gogo: 'gogo 1s infinite',
+ },
+ keyframes: {
+ gogo: {
+ '0%, 100%': {
+ transform: 'translateX(25%)',
+ animationTimingFunction: 'cubic-bezier(0.8, 0, 1, 1)'
+ },
+ '50%': {
+ transform: 'translateX(0)',
+ animationTimingFunction: 'cubic-bezier(0, 0, 0.2, 1)'
+ },
+ }
+ }
}
},
plugins: []
};
module.exports = config;
- 呼び出し側はclassに
animate-gogo
と書くだけ
呼び出し側(一部省略)
<div>
<a href="/question">
<span>無料</span>おすすめ映画診断をする
<svg class="animate-gogo">
<path d="..."/>
</svg>
</a>
</div>
画像、SVGの素材
無料のMITライセンスのものを選びました
- Lorem Picsum はキレイな画像がAPIで取得できる
- css.gg はSVGアイコンなど
おわりに
- お気づきかもしれませんが、今回は質問を取得するためのAPIなど使っていません。本当はCMSとか使ってやろうかなと思ったのですが、データの流し込みが面倒そうで...
- やはりSvelteは開発しやすいのでもっと普及してほしいですね〜
- ぜひ、みなさんも「Go!Go!Movie!」を触っていただき、映画館(特にミニシアター)に足を運んでいただければ幸いです
Appendix
ディレクトリ構成
- 使用技術とは関係ないですが、今回のディレクトリ構成です。