Open15

Svelte に関するメモ

雪猫雪猫

入門

チュートリアルが充実しているので一通りやるとよさそう。

実際にコードを試したいときは 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');
雪猫雪猫

コンポーネント

機能単位で *.svelte コンポーネントを作成できる。
ViewModel + View という印象。コアロジックは lib/*.ts に書いた方がよさそう。

コンポーネント間で情報を受け渡しする方法

  • 親コンポーネントから子コンポーネントへ一方通行なら Context API
  • lib/*.ts で変数を export
  • 購読をしたいなら ストア

複数のページで使われるものは libs/components/*.svelte に置く。
単一のページでしか使われないコンポーネントは routes/*.svelte に置いてもいい。

https://kit.svelte.jp/docs/project-structure

export

export function

https://svelte.jp/tutorial/module-exports
https://svelte.dev/repl/f5304fef5c6e43edb8bf0d25d634f965?version=4.2.0

ルーティング

**/+page.svelte のファイルパスがそのままルーティングになる。
エイリアスは張れなさそう?今のところ +page.svelte だけ複数置いて中身をコンポーネントにしてる。

レンダリングの前に処理をしたい場合は +page.ts+layout.ts で処理して +page.svelte+layout.svelte にて export let data: PageData; // or LayoutData で受け取る。

ライブラリ作成

https://qiita.com/oekazuma/items/d6a0dc6f7c3c2d912f64
https://zenn.dev/rabee/articles/sveltekit-for-vanilla-js-library

ライフサイクル

https://zenn.dev/miruoon_892/articles/2c9efd2c302c56bd41a6

雪猫雪猫

Server or Client

Client

onMountafterNavigate 内の処理はクライアントとしてレンダリングされるので window プロパティ等が使用できる。

if (browser) でもクライアント用の処理を書ける。

雪猫雪猫

Logic

lib/**.ts に書く。import { ClassName } from '$lib/ClassName で読み込み。
ストアの置き場所はどこが適切?
→ 各クラスと同居させるか lib/stores/*.ts に置くのが良さそう。stores/*.ts に置いてしまうとディレクトリを移動した際に自動で修正してもらえない。

雪猫雪猫

デプロイ

Vercel

動かないときのチェックリスト

  • リモートリポジトリに変更が反映されている
    • プッシュしている
    • コミットしている
  • ローカル npm run dev で動く
  • ローカル npm run build && npm run preview で動く
  • プラットフォームの障害がないか
  • 再デプロイ
雪猫雪猫

PWA

https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps
https://developer.mozilla.org/ja/docs/Web/Progressive_web_apps/Tutorials/js13kGames/Installable_PWAs

要件は以下の 4 点。

  • HTTPS
  • アイコン
  • Service Worker
  • マニフェストファイル

最低限の設定

HTTPS

現代の Web サイトでは当然なので割愛します。

アイコン

144x144 以上の PNG(SVG だとうまく表示されなさそう?)を用意して static ディレクトリに置きます。
ファイル名は任意で構いません。マニフェストファイルで指定します。

static/icon.png に置いたものとします。

https://www.pwabuilder.com/imageGenerator

Service Worker

空の src/service-worker.js を作成します。

https://kit.svelte.jp/docs/service-workers

マニフェストファイル

src/app.html
<link rel="manifest" href="%sveltekit.assets%/manifest.webmanifest" />
static/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 タブから利用できます。

プラグイン

プラグインもありマニフェストファイル等を生成したりできるようですが結局アイコンを用意したりマニフェストファイルの設定を書いたりしないといけないのであまり有用性が分かりませんでした。
細かい設定をするのには便利なのかもしれません。

https://github.com/vite-pwa/sveltekit
https://vite-pwa-org.netlify.app/frameworks/svelte.html

雪猫雪猫

Linter, Formatter

Biome は未対応なので ESLint + Prettier を使用。
npx sv create でプロジェクトを作成する場合は対話中に選択。
npm create vite@latest でプロジェクトを作成する場合はインストールされていないので手動でインストールする。

ESLint

https://eslint.org/

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 へ適用

https://sveltejs.github.io/eslint-plugin-svelte/

npm install --save-dev svelte eslint eslint-plugin-svelte globals
eslint.config.js
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

https://prettier.io/

npm install --save-dev --save-exact prettier
node --eval "fs.writeFileSync('.prettierrc','{}\n')"
node --eval "fs.writeFileSync('.prettierignore','# Ignore artifacts:\nbuild\ncoverage\n')"

*.svelte へ適用

https://github.com/sveltejs/prettier-plugin-svelte

npm install --save-dev prettier-plugin-svelte prettier
.prettierrc
{
  "plugins": ["prettier-plugin-svelte"],
  "overrides": [
    {
      "files": "*.svelte",
      "options": {
        "parser": "svelte"
      }
    }
  ]
}

package.json scripts

scripts に追加しておくと便利。

{
  "scripts": {
    "lint": "prettier --check . && eslint .",
    "format": "prettier --write ."
  },
}