search
LoginSignup
2

More than 1 year has passed since last update.

posted at

updated at

Go!Go!Movie!を支える技術

これなに

2021年12月22日に個人でリリースした映画診断サイト「Go! Go! Movie!」の技術について書いてます。

TOP 診断 結果
top.png question.png result.png

いくつか質問に答えたら、おすすめの映画を紹介してくれます。

なんで作った?

  1. 先日、コーヒーサブスクの診断コンテンツがTwitterで表示されてやってみたところ、面白かったので 「Svelteで作るならどうなるだろう?」 と衝動にかられて
  2. コロナでミニシアターが苦しんでいるので、どうせなら映画館に足を運ぶきっかけになったらいいなと思って

構想

構想.jpg
ノートにばーっと書いたら、ポイントは2つ

  • 質問/結果のノード
  • 回答を次の質問のノードに関連づける

で作れそうと分かりました。

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を使用しておりビルドが高速なため開発体験が良い
  • Vercel
    • アダプターを切り替えるだけでVercelなどに最適なビルドをしてくれる
    • 無料でアプリケーションをホストしてくれる(個人開発なら十分)
    • GitHubにプルリクだすと自動で検証環境を用意してくれるから楽

Tailwind CSS

  • マークアップやったことないエンジニアでもとっつきやすい
  • スタイル書いたことなくてもtailwindcomponents を参考にすれば効率はよい
  • class名を考える必要がないので開発効率UP
  • 下記のようなアニメーションも簡単に作れます tailwind.gif
    アニメーションの設定(開くならクリック)
    1. 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;
    
    1. 呼び出し側はclassにanimate-gogoと書くだけ
    呼び出し側(一部省略)
    <div>
        <a href="/question">
            <span>無料</span>おすすめ映画診断をする
            <svg class="animate-gogo">
                <path d="..."/>
            </svg>
        </a>
    </div>
    

    画像、SVGの素材

    無料のMITライセンスのものを選びました

    おわりに

    • お気づきかもしれませんが、今回は質問を取得するためのAPIなど使っていません。本当はCMSとか使ってやろうかなと思ったのですが、データの流し込みが面倒そうで...
    • やはりSvelteは開発しやすいのでもっと普及してほしいですね〜
    • ぜひ、みなさんも「Go!Go!Movie!」を触っていただき、映画館(特にミニシアター)に足を運んでいただければ幸いです:relaxed:

    Appendix

    ディレクトリ構成

    • 使用技術とは関係ないですが、今回のディレクトリ構成です。

    image.png

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
2