この記事はレコチョク Advent Calendar 2023の17日目の記事となります。
はじめに
こんにちは。株式会社レコチョクでmurketというサービスのフロントエンドエンジニアをしている坂本と申します。
最近は作業のおともにエイハブさんの「アクター」や「クィホーティ」を聴いています。
さて、本題に入ろうかと思うのですが、みなさんはJavaScriptのフレームワークといえば何を思い浮かべるでしょうか。Vue.js?それともReact?
JavaScriptのフレームワークといえばこの二強という印象がありますが、今回は最近勢いのある第三勢力Svelteを触ってみたので記事にします。
Svelteとは
ここでSvelteの概要について軽く触れておきたいのですが、要約が面倒くさい難しかったのでChatGPT先生に「JavaScriptのフレームワークであるSvelteについて、300文字程度でJavaScript中級者に対して説明してください。」と聞いたら以下のような答えが返ってきました。
Svelteはコンパイル時にUIを構築する革新的なアプローチを採用したJavaScriptフレームワークです。ReactやVueのような従来のフレームワークがブラウザでの実行時にDOMを操作するのと対照的に、Svelteはビルド時に必要なコードを生成し、ブラウザが理解できる最適化された命令セットに変換します。このため、実行時のライブラリ依存がなく、軽量で高速な実行が可能です。Svelteコンポーネントは可読性が高く、宣言的なHTML、CSS、JavaScriptのコードで構成されており、リアクティブなステート管理を直感的に行えます。開発体験はシンプルでありながら、パフォーマンスとメンテナンス性のバランスを巧みにとっています。
だそうです。つまりVue.jsやReactとの大きな違いは、Svelteはコンパイラであり仮想DOMを使用しないところにあります。そのため実行速度が他のフレームワークに比べて優れているとのこと。
その辺りの仕様についても検証してみたいところですが、まずはこの記事ではSvelteKit(SvelteとViteで構成されたフレームワーク)を使っていいねボタンを作ってみることで、ざっくりとしたディレクトリ構成やリアクティビティシステムに触れるところまでをやってみます。
SvelteKitのインストールとセットアップ
ではさっそく試しに以下のコマンドを打ち込んでSvelteを手元で動かしてみます。myapp
の部分には適宜好きなアプリ名を入力してください。
npm create svelte@latest myapp
セットアップするのにいくつか質問されるので、以下を参考に環境構築をしてみてください。
Ok to proceed? (y)
yを押してインストールを進めます。
┌ Welcome to SvelteKit!
│
◆ Which Svelte app template?
│ ● SvelteKit demo app (A demo app showcasing some of the features of SvelteKit
- play a word guessing game that works without JavaScript!)
│ ○ Skeleton project (Barebones scaffolding for your new SvelteKit app)
│ ○ Library project(Barebones scaffolding for your new Svelte library)
上から
- デモアプリ
- SvelteKitでアプリを作成
- Svelteのライブラリを作成
になります。今回は2つ目を選択しました。
さっくりSvelteがどんなものか知りたい人は1つ目を選択してみても良いと思います。選ぶと単語当てクイズアプリが作成されます。
◆ Add type checking with TypeScript?
│ ● Yes, using JavaScript with JSDoc comments
│ ○ Yes, using TypeScript syntax
│ ○ No
└
TypeScriptを使うかどうかを選びます。今回は1つ目(使わない)を選択しました。
◆ Select additional options (use arrow keys/space bar)
│ ◻ Add ESLint for code linting
│ ◻ Add Prettier for code formatting
│ ◻ Add Playwright for browser testing
│ ◻ Add Vitest for unit testing
│ ◻ Try out Svelte 5 beta
└
オプションをスペースキーを押して選択していきます。今回は一旦全部チェックなしで進めました。
ここまででセットアップは完了です。
Next steps:
1: cd myapp
2: npm install
3: git init && git add -A && git commit -m "Initial commit" (optional)
4: npm run dev -- --open
Next stepsに従ってcd myapp
でディレクトリを移動し、npm install
を実行します。手順3は今回必要無いのでスキップします。
npm run dev -- --open
を実行して以下のような画面が表示されればOKです。
ディレクトリの構造
インストールとセットアップが済んだところで、さっそく手を動かしつつディレクトリの構造と各ディレクトリ・ファイルの役割を確認していきます。
(以下の図では/.svelte-kit
と/node_modules
を直接いじることは無いので割愛しています。)
myapp/
├ src/
│ ├ lib/
│ │ └ index.js
│ ├ routes/
│ │ └ +page.svelte
│ ├ app.html
│ ├ app.d.ts
├ static/
│ └ favicon.png
├ package.json
├ svelte.config.js
├ tsconfig.json
└ vite.config.js
indexページを編集してみる
まず、src/routes/
にある+page.svelte
を見てみます。
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
このような内容になっており、npm run dev -- --open
を実行して最初に現れるページの内容がこのファイルに書かれていることがわかりました。
試しに以下のように変更してみます。
<h1>Welcome to my site</h1>
<a href="#">About my site</a>
保存すると画面上での表示も変わりましたね!
ページを追加する
では次に、新しいページを追加していきたいと思います。
src/routes/
配下にabout
という名前でディレクトリを作り、+page.svelte
という名前でファイルを作成します。内容は一旦以下だけ記述しておきます。
<h1>about</h1>
Svelteではルーティングがsrc/routes/
配下にあるディレクトリごとに切り分けられており、各ページの内容は+page.svelte
というファイルに記述していきます。つまり、今作ったページのアドレスはhttp://localhost:xxxx/about
になります。
直接URLを叩いて確認しても良いですが、せっかくなのでindexページを以下のように変更してみます。
<h1>Welcome to my site</h1>
<a href="/about">About my site</a>
保存したあとにもう一度画面を見てみると、リンクが正しく動作しaboutページが表示されることが確認できました。
共通レイアウトを追加する
大まかなルーティングの仕組みが分かったところで、次は共通レイアウトを追加してみます。ヘッダーメニューやフッターなど、全ページに共通して表示させたいものはsrc/routes/
配下に+layout.svelte
という名前でファイルを作成し、そこに記述すれば全てのページに適用されます。
試しに共通のnav要素とfooterを追加してみました。+page.svelte
の内容は<slot />
部分に表示されます。
<div>
<nav>
<span>my app</span>
<ul>
<li>menu1</li>
<li>menu2</li>
<li>menu3</li>
</ul>
</nav>
<main>
<slot /> // ここに+page.svelteがレンダリングされる
</main>
<footer>
<p>footer</p>
</footer>
</div>
また、スタイルはファイルにstyle
タグを置いてその中に直接CSSを記述することもできますし、もちろん別ファイルをインポートすることでも適用できます。その場合はファイルの頭で以下のように宣言します。
<script>
import "./styles.css"; // 適用したいファイルのパス
</script>
ぱっと見でわかりやすいように適当にスタイルを当てたものが以下になります(CSSは割愛します)。
リアクティビティシステムを扱ってみる
ここまででざっくりディレクトリの構造について確認してみましたが、次はいいねボタンを設置することでリアクティビティシステムを扱ってみます。
src/routes
にLikeButton.svelte
という名前でファイルを作り、以下の内容を記述します。
<script>
let count = 0;
function increment() {
count += 1;
}
</script>
<div>
<button on:click={increment}>
like {count}
</button>
</div>
また、src/routes/+page.svelte
にLikeButton.svelte
を設置します。
<script>
import LikeButton from "./LikeButton.svelte";
</script>
<h1>Welcome to my site</h1>
<a href="/about">About my site</a>
<LikeButton />
するとこのようにいいねボタンを設置することができました。
次は10回しかいいねボタンを押せないようにし、ボタンの下に残りの回数を表示するようにします。
残り回数はcount
の増加に連動して値を変える必要があるため、これを実装するにはリアクティブ宣言を使う必要があります。そのため、残り回数を管理する変数(countsLeft
とします)は以下のように宣言します。
$: countsLeft = 10 - count;
リアクティブ宣言を行うとき、内容が未定義の変数への代入だけだった場合はsvelteが自動でlet
宣言してくれるため、countsLeft
の頭にlet
をつける必要はありません。
また、count
が10に達した時、ユーザーへもういいねボタンを押すことができないことをalert()
で知らせる処理も追加してみます。
リアクティブ宣言では、countsLeft
のような値だけでなく以下のようにconsole.log
やif文といったステートメントもリアクティブに扱うことができます。また、{}
を使ってブロックを作ることでステートメントをまとめることもできます。
$: {
console.log('like button clicked')
if (count >= 10) {
alert('Thanks a lot!');
}
}
maxCount
という定数を新たに定義して、すでにある処理と上記の記述を合体させたものが以下になります。
<script>
let count = 0;
const maxCount = 10;
$: countsLeft = maxCount - count;
$: {
console.log('like button clicked')
if (count >= maxCount) {
alert('Thanks a lot!');
}
}
function increment() {
if (count < maxCount) {
count += 1;
}
}
</script>
<div class="like-button">
<button on:click={increment}>
like {count}
</button>
<p>You can push {countsLeft} more times.</p>
</div>
するとこのようにいいねの残り回数とアラートが表示されるようになりました。
おわりに
ここまでで、SvelteKitで作成されたアプリのディレクトリ構成やリアクティビティシステムに触れてきました。
特徴的なファイル名であったりリアクティブ宣言であったり、あまり見慣れない構文に戸惑う場面は多々ありましたが、他のjsフレームワークを扱った経験があれば慣れることはそこまで難しくは無さそうな印象を受けました。
まだVue.jsやReactと比べるとライブラリやツールが少なかったり情報が充実しているとは言えなかったり(とはいえ有志によって日本語化が進められていたり、DiscordにSvelteの日本コミュニティがあったりします)といった欠点はありそうですが、フロントエンド開発手段の選択肢を増やすためにも引き続き学習を続けていきたいと思っています。
明日の レコチョク Advent Calendar 2023 は18日目「AWS LambdaのCI・CD環境を構築してみた」です。お楽しみに!
参考にしたもの
この記事はレコチョクのエンジニアブログの記事を転載したものとなります。