Svelte に関するメモ
※ REPL は svelte.dev でしか利用できません
入門
チュートリアルが充実しているので一通りやるとよさそう。
実際にコードを試したいときは REPL にてオンラインで動かすことができます。
メリット
- チュートリアルが充実してる
- コンポーネント単位でコードや CSS を書ける
- 素の CSS で十分(学習コストが低い)
- 素の JS っぽく書ける(学習コストが低い)
- ストア機能がある(Vuex, Pinia 相当)
- ストアを含めた Reactivity が便利
- *.svelte では async/await よりこちらを活かせる書き方をする
-
<head>
を動的に書き換えられる(Vue にはなかった) - Vercel, Cloudflare Pages へのデプロイが簡単
- ブラウザで GitHub 連携するだけ
- PR 作成時にプレビュー環境へ自動デプロイ
デメリット
- ライブラリ等のエコシステムがまだ充実していない
- SvelteKit だとルーティングでエイリアスが張れない?(ファイルパスベースのため)
- クライアントに初期化用のフックがない
- サーバーにはあるので一般的なログイン処理は書けそう
-
bind:this
で HTML Element やコンポーネントをバインドすると未定義 (undefined) な瞬間がある- 厳密に型を定義する場合
Element | undefined
として?.
でメソッドを呼び出す必要がある - 単に
Element
にしてしまってもさほど実害はなさそう
- 厳密に型を定義する場合
-
onMount
,afterNavigate
以外の箇所ではサーバーとクライアント両方で実行されてしまうのでクライアントだけで行いたい処理はif (browser) {}
で囲う必要がある- import も動的に行う必要がある
const { ClientOnly } = await import('client-only');
- import も動的に行う必要がある
コンポーネント
機能単位で *.svelte
コンポーネントを作成できる。
ViewModel + View という印象。コアロジックは lib/*.ts
に書いた方がよさそう。
コンポーネント間で情報を受け渡しする方法
- 親コンポーネントから子コンポーネントへ一方通行なら Context API
-
lib/*.ts
で変数をexport
- 購読をしたいなら ストア
複数のページで使われるものは libs/components/*.svelte
に置く。
単一のページでしか使われないコンポーネントは routes/*.svelte
に置いてもいい。
export
export function
ルーティング
**/+page.svelte
のファイルパスがそのままルーティングになる。
エイリアスは張れなさそう?今のところ +page.svelte
だけ複数置いて中身をコンポーネントにしてる。
レンダリングの前に処理をしたい場合は +page.ts
や +layout.ts
で処理して +page.svelte
や +layout.svelte
にて export let data: PageData; // or LayoutData
で受け取る。
ライブラリ作成
ライフサイクル
Server or Client
Client
onMount
や afterNavigate
内の処理はクライアントとしてレンダリングされるので window
プロパティ等が使用できる。
if (browser)
でもクライアント用の処理を書ける。
Logic
lib/**.ts
に書く。import { ClassName } from '$lib/ClassName
で読み込み。
ストアの置き場所はどこが適切?
→ 各クラスと同居させるか lib/stores/*.ts
に置くのが良さそう。stores/*.ts
に置いてしまうとディレクトリを移動した際に自動で修正してもらえない。
補完機能の実装
XSS 脆弱性がありそうなのでサニタイズちゃんとやった方がよさそう。
インポート
onMount(async () => {
const { default: Tribute } = await import('tributejs');
});
サンプルコード
Service Worker
-
$lib
で参照できなさそう?-
./lib
は使える
-
CSS
動的に CSS を変更したい
クラスを切り替える。
コンポーネントをまたいだ CSS を定義したい
デプロイ
Vercel
動かないときのチェックリスト
-
リモートリポジトリに変更が反映されている
- プッシュしている
- コミットしている
-
ローカル
npm run dev
で動く -
ローカル
npm run build && npm run preview
で動く - プラットフォームの障害がないか
- 再デプロイ
PWA
要件は以下の 4 点。
- HTTPS
- アイコン
- Service Worker
- マニフェストファイル
最低限の設定
HTTPS
現代の Web サイトでは当然なので割愛します。
アイコン
144x144 以上の PNG(SVG だとうまく表示されなさそう?)を用意して static
ディレクトリに置きます。
ファイル名は任意で構いません。マニフェストファイルで指定します。
static/icon.png
に置いたものとします。
Service Worker
空の src/service-worker.js
を作成します。
マニフェストファイル
<link rel="manifest" href="%sveltekit.assets%/manifest.webmanifest" />
{
"name": "<your_app_name>",
"short_name": "<your_app_name>",
"start_url": ".",
"display": "standalone",
"background_color": "#fff",
"icons": [
{
"src": "icon.png",
"sizes": "144x144",
"type": "image/png"
}
]
}
動作確認
トラブルシューティングには Lighthouse が便利です。
Chrome であればデベロッパーツール (F12) の Lighthouse タブから利用できます。
プラグイン
プラグインもありマニフェストファイル等を生成したりできるようですが結局アイコンを用意したりマニフェストファイルの設定を書いたりしないといけないのであまり有用性が分かりませんでした。
細かい設定をするのには便利なのかもしれません。
OGP
自サイトの画像生成
他サイトの CORS 回避
その他
UI
仮想リスト
仕組み
ローカライズ (i18n)
Linter, Formatter
Biome は未対応なので ESLint + Prettier を使用。
npx sv create
でプロジェクトを作成する場合は対話中に選択。
npm create vite@latest
でプロジェクトを作成する場合はインストールされていないので手動でインストールする。
ESLint
npm init @eslint/config@latest
√ What do you want to lint? · javascript
√ How would you like to use ESLint? · problems
√ What type of modules does your project use? · esm
√ Which framework does your project use? · none
√ Does your project use TypeScript? · No / Yes
√ Where does your code run? · browser
√ Which language do you want your configuration file be written in? · js
The config that you've selected requires the following dependencies:
eslint, @eslint/js, globals, typescript-eslint
√ Would you like to install them now? · No / Yes
√ Which package manager do you want to use? · npm
設定ファイルに TypeScript を選択すると Node.js 24.3.0 未満では Jiti のインストールを求められる。
*.svelte
へ適用
npm install --save-dev svelte eslint eslint-plugin-svelte globals
import ...;
import svelte from "eslint-plugin-svelte";
import svelteConfig from "./svelte.config.js";
export default defineConfig([
...,
svelte.configs.recommended,
{
files: ["**/*.svelte", "**/*.svelte.ts", "**/*.svelte.js"],
languageOptions: {
parserOptions: {
projectService: true,
extraFileExtensions: [".svelte"],
parser: tseslint.parser,
svelteConfig,
},
},
rules: { "svelte/require-each-key": "warn" },
},
]);
Prettier
npm install --save-dev --save-exact prettier
node --eval "fs.writeFileSync('.prettierrc','{}\n')"
node --eval "fs.writeFileSync('.prettierignore','# Ignore artifacts:\nbuild\ncoverage\n')"
*.svelte
へ適用
npm install --save-dev prettier-plugin-svelte prettier
{
"plugins": ["prettier-plugin-svelte"],
"overrides": [
{
"files": "*.svelte",
"options": {
"parser": "svelte"
}
}
]
}
package.json scripts
scripts に追加しておくと便利。
{
"scripts": {
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
}