LoginSignup
62
44

More than 1 year has passed since last update.

Svelte でゲーム音楽検索サイト作った話

Last updated at Posted at 2021-06-18

概要

私は ゲーム音楽 というサイトを個人開発 & 運営しています。
この記事では Svelte を中心に書いていきます。

結論

Svelte は素晴らしい。XState, Tailwind CSS との相性が抜群過ぎて、私は今のところこの組み合わせ以外は考えられないほどです。今後は Svelte も選定候補に上がると思います。
ちなみにフロントエンドのリポジトリはこちら。

バックエンドはこちら。

なぜ Svelte は素晴らしいの?

Svelte は軽い早いで知られていますが、使ってみると他の良さがありました。

1. Reactivity が素晴らしい

Svelte で開発する前、このサイトでは React で開発していました。React には React hooks という革命的な技術があります。簡単に言うと、クラスを書かずとも use〇〇 という関数をコンポーネント内で使用し、変数の変更を検知をしてコンポーネント内を再レンダリングするという仕組みです。簡単なコンポーネントであれば hooks で事足ります。ファットなコンポーネントを作ろうとすると(そもそもファットにすべきじゃないが)、レンダリングし過ぎてしまうことがあります。これを回避するためには、 useMemo などメモ化することで無駄に処理を実行させない方法があります。
React の性能を上げるにはメモ化することを考えなければいけません(私の実装が悪く性能が悪いと言うのもあります)。どの関数を useCallback するのかなど考えるのが割と大変です。
しかし、 Svelte はその逆です。どの処理をリアクティブにするのかを考えるだけで良いのです。リアクティブにしたい場合は以下のようにします。

<script>
let count = 0;

// リアクティブではない
// これは1度だけ "0だよ!" と表示されるだけ
console.log(`${count}だよ!1回だけだよ!`);

// リアクティブ
// count が変更される度に実行される
$: {
  console.log(`${count}だよ!`);
}

// リアクティブだが count がスコープ内に存在しないので1度しか実行されない!賢い。
$: {
  console.log("元気だよ!");
}

// 条件付きリアクティブ
// count が10以上だと実行される
$: if (count >= 10) {
  console.log("10以上だよ!");
}

const onClick = () => count += 1;
</script>

<button on:click={onClick}>
  カウント {count}
</button>

$ の書き方のクセはありますが、慣れるとかなり便利です。
このように $ のスコープ内だけ更新されると直感的に理解できて素晴らしいです。

2. Scoped CSS が素晴らしい

Svelte は、 script と style と component を同ファイルにまとめてかけます。
component は script タグと style タグ以外が component として扱われます。

<script>
let count = 0;
const onClick = () => count += 1;
</script>

<button on:click={onClick}>
  カウント {count}
</button>

<style>
button {
  display: block;
  width: 160px;
  height: 160px;
}
</style>

ここで、 「えっ、 button にスタイル書いたら全ての button タグに反映されるのでは?」と思う方もいるかもしれません。実は、 Svelte には Scoped CSS という仕組みがあります。そのためこのファイル内の button タグにしかこの style は適用されません。とてもスッキリしますね。
この Svelte ととても相性が良いのが、 Tailwind CSS です。Tailwind CSS は、簡単に言うとよく使う CSS class を集めたCSSフレームワークです。そのため、以下のように書けます。

<script>
let count = 0;
const onClick = () => count += 1;
</script>

<button class="block h-40 w-40" on:click={onClick}>
  カウント {count}
</button>

このようにインラインスタイルでかけます。とても省略された CSS class です。私のようなインラインスタイル派ではない人のための style タグの書き方もあります。

<script>
let count = 0;
const onClick = () => count += 1;
</script>

<button on:click={onClick}>
  カウント {count}
</button>

<style>
button {
  @apply block h-40 w-40
  /* Tailwind CSS 2.1 からは以下の書き方もできる */
  @apply block h-[160px] w-[160px]
}
</style>

とてもスッキリしますね。
この Scoped CSS には弱点があり、動的に生成されたHTMLには適用されません。その場合に効果的なのが、Tailwind CSS Typography です。

<div class="prose">
  {@html markdown}
</div>

このように class に "prose" を指定するだけでおしゃれなスタイルが効きます。
Scoped CSS は CSS ファイルと JavaScript ファイルとで行き来すると何がなんだかわからなくなりがちな私にとっては素敵な仕組みです。

3. Stores が素晴らしい

Svelte ではフロントエンドで困りがちな Redux などの store ライブラリの選定をしなくても問題ありません。
Svelte stores という store がフレームワークレベルで組み込まれています。
以下のように使います。

store を生成した後は $count のようにするだけで、どのコンポーネントで変更されてもリアクティブに変更されます。

オブジェクトが subscribe メソッドを正しく実装していれば、それはストアです。

これはわかりやすい。
この Svelte stores は、奇跡的に XState相性が抜群に良いです。 XState とはステートマシンを実装することが出来るようになるライブラリです。 ロジックは XState で作り込み、表示は js と css で作り込むだけで済みます。例えば、SPAで実装した時、共通したマシンを使用したいときは、

export const service = interpret(nanikasiranoMachine).start();

のように XState で service を生成するだけで、 あとは、 $service と書いておくだけでリアクティブ対象になります。これ本当に奇跡。
なぜ $service でリアクティブになるのかというと、 XState のサービスオブジェクトが subscribe メソッドを正しく実装しているからです!すごい!すごいぞ!
Svelte と XState の実装についての話し合いとかあったの? Svelte のために作ったの? ってぐらいの奇跡。
XState メインの記事は別で書きます。
このように Stores がとても便利です。

4. アニメーションが素晴らしい

Svelte ではアニメーションがフレームワークレベルで存在します。
とっても便利!

終わりに

後半尻すぼみすぎなんですが、このあたりにしておきます。
Svelte は素晴らしすぎるので、ぜひ皆さんも チュートリアル を学んで Svelte に足を踏み入れましょう!

62
44
0

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
  3. You can use dark theme
What you can do with signing up
62
44