😺

Svelteルーティングライブラリ'Routify'についてまとめる

2023/05/05に公開

Routify を選定するまで

Routify とは

Svelteにて使用するルーティングライブラリになるもの。SvelteはコンパイルしてHTML/CSS/JSを生成するものでRouterのような機能は用意されておらず、RoutifyのようなRouterを活用してSPAを作成していく。

なぜ Routify か

既存のプロジェクトにおいてpage.jsを使用してルーティングを行なっていた。見た目はSPAになっておりルーティングされているが、ページの永続化が実現できていなかった。
そのために上記のようなRouterにあたるものを使用する経緯となった。
他にも'svelte-routing'や'svelte-spa-router'などの他ライブラリももちろんありました。
https://github.com/EmilTholin/svelte-routing

https://github.com/ItalyPaleAle/svelte-spa-router

ですが、ドキュメントの細かさ、記述の方法(これは個人の意見が大きいかもしれません)においてRoutifyがいいかなと思い選定しました。

こちらRoutifyのドキュメントになります。
https://www.routify.dev/

使用方法

インストール

npm i -D @roxi/routify npm-run-all

package.jsonへの記述

package.json
  "scripts": {
    "webpack": "webpack",
+   "routify": "routify",
+   "build": "routify -b && webpack --mode production",
-   "build": "webpack --mode production",
+   "watch:routify": "routify",
+   "watch:webpack": "webpack --mode development --watch",
+   "dev": "run-p watch:*",
-   "dev": "webpack --mode development --watch",
    "start": "sirv public --single"
  },

コマンドについて

公式ドキュメントから

routify -b is shorthand for routify --single-build. Single-build doesn’t watch for file changes and produces a leaner routes.js file.
routify -b は、routify --single-build の省略形です。シングルビルドはファイルの変更を監視せず、無駄のない routes.js ファイルを生成します。(日本語訳)

Note: You might also want to add the .routify folder to .gitignore, since it is only needed during development.
注: 開発中にのみ必要になるため、.routify フォルダーを .gitignore に追加することもできます。(日本語訳)

run-pコマンドはroutifyと一緒にインストールしたnpm-run-allをインストールしていれば使用できた。
(自分はそれに気が付かずインストールしておらず、routify & webpack --mode development --watchとしてしまいRoutifyが監視状態になり処理が終了せずwebpackのビルドへ移行しなかった。)

記述方法について

ルートファイルのApp.svelteへ下記の記述を行う

/src/App.svelte
<script>
 
  import { Router } from "@roxi/routify";
  import { routes } from "../.routify/routes";

</script>

<Router {routes} />

構成について

どのようにしてURLごとに設定を行うかについてのイメージについて、SvelteのフレームワークであるSvelte Kitのような記述になると思っている。

In Routify, files in src/pages correspond to URLs.
Routify では/src/pages内のファイルが URL に対応します。(日本語訳)

  • /pages
    • _layout.svelte
    • /blog
      • index.svelte → /blog
    • /blog
      • [post].svelte → /blog/:post
    • about.svelte → /about
    • index.svelte → /

基本はこのようにファイル、またはディレクトリ名がURLとしてマッピングされることになる。

  • index.svelteは/の扱いになる
  • [post].svelteのような記述になる場合は、パラメータとしてpost=xxxxxxとして取得できる

Files and directories prefixed with an underscore will not be picked up by Routify.
アンダースコアで始まるファイルとディレクトリは、Routify によって取得されません。(日本語)

404s can be caught with _fallback.svelte. The first _fallback.svelte that's found while traversing back through parent folders will be used.
404 は _fallback.svelte でキャッチできます。親フォルダーをトラバースして戻るときに見つかった最初の _fallback.svelte が使用されます。(日本語)

今では標準だと思うが、このように404ページが用意されているのは個人的には嬉しい

ルーティング設定について追記(2023/5/8)

下記のように二つのURLのパターンがあったとする

  • /users/1/account
  • /users/example
    前者は
/users
  /[id]
    /account

と設定できるが後者の場合は/exampleの部分が先ほど設定した/[id]と重なってしまう。
試した結果

/users
  /[id]
  exmaple.svelte
    /account

とすると、[id]のワイルドカードの値の一つとして扱われる。

/users
  /exmaple
  /[id]
    /account

とすると、/exampleとして/users/exampleに一致するのでそのコンポーネントを表示してくれる。

さらに追記

ルーティングのパスの優先順位について
/xxxx/aにアクセスしたい場合、
/xxxx配下にある

  1. ディレクトリ名
  2. パスに一致するファイル名(上記例だとa.svelte)
  3. ワイルドカードに設定しているファイル
    の順番に表示される優先順位が設定される。

パラメータについて

下記のように記述する

/src/blog/[post].svelte
<script>
  import { params } from "@roxi/routify";
  export let post
  $: post = $params.post
</script>

インポートしたparamsをデコレータとして使用し、/blog/100と100という値を取得したい場合、[post]の部分がワイルドカードとなる。後述するがクエリパラメータやaタグ内のhref属性についても$urlのようにデコレータとして機能を活用できる。

レイアウトについて

基本的には下記にある_layout.svelteにてコンポーネントのラッピングを行う。
サンプルコード

/src/pages/_layout.svelte
<slot>
  <!-- この部分で設定したルーティングが行われる -->
</slot>

Layouts are recursive, so whenever a page is displayed, all layouts from all its parent folders are applied. Layouts must always have a <slot> tag.
レイアウトは再帰的であるため、ページが表示されるたびに、すべての親フォルダーのすべてのレイアウトが適用されます。 レイアウトには常に <slot> タグが必要です。(日本語)

SSR、SSGについて

サポートはされているが今回は使用していないので割愛させていただきます。

ナビゲーションについて

aタグを使用したナビゲーションは下記の通り

foo.svelte
import { url } from "@roxi/routify";

<a href={$url('/introduction')}>
  A link to the introduction section on your left
</a>
  • URLhttp://localhost:8000/introduction

  • /src/pages/introduction/index.svelte or /src/pages/introduction.svelte が描写される
    $urlは単なるリンクではなく、現在配置されているレイアウトに相対的な値にする

  • $isActiveのようなヘルパーも用意されている(後述に記載)

Helpers について

今回routifyを使用する上で主に使用した機能

  1. $url
  • /src/pages配下にあるファイル、ディレクトリに関するパスをうまくまとめ、ブラウザのURLの影響を受けないURLとなる。
    $urlをつけないパスの場合はページ自体が読み込まれる。
  1. $isActive
  • 指定されたパスと現在の位置が一致するか判別してくれます。active時にスタイルを変える際に使用。
  1. $goto
  • プログラムによりナビゲーションしてくれる。
  1. $params
  • パラメーターを受け取りたい時に使用。[]内に指定した値がキーとして取得できるようになる。
  1. $metatags
  • ページのメタデータを設定する際に使用する。主にtitleやdescriptionになる。
  1. $afterPageLoad
  • ページが読み込まれた後に呼び出される。ページ自体が読み込まれるより、コンポーネントが切り替わるイメージなのでタブを切り替えた後にAPIを叩く。などに使用した。
  1. $isChangingPage
  • ページが読み込まれている場合はtrueを返す。ローディング画面などユーザビリティを下げないために使用した。

他にも使用できる機能や、紹介した機能の詳細などは下記をご覧ください。
https://www.routify.dev/docs/helpers

Config について

今回は例としてドキュメントにそってシンプルな/src/pagesとしましたが、実際のプロジェクトになると一貫していかないと思うのでConfigファイルを少しだけですが紹介します。

設定場所

下記のように種類があります。
上から順に優先順位が高いようです。今回は自分は2番目のroutify.config.jsを使用しました。

Location Example Case style
package.json "routify": {"routifyDir": ".routify"} camelCase
routify.config.js module.exports = { routifyDir: '.routify'} camelCase
.env ROUTIFY_DIR=.routify SNAKE_CASE
CLI npx routify --routify-dir .routify kebab-case

設定したオプション

  1. pages
    Default value ./src/pages
  • パスを設定ためにRoutifyに読み込ませるために/pagesディレクトリのパスを設定できる
    2. sourceDir
    Default value ドキュメントに記載なし
  • 設定するHTMLファイルのパスを設定できる。ドキュメントに記載がなく、開発時にnpm run devを打った際に作成されたRoutifyのファイル群を見て設定できるか試したら無事できたので載せておく。
/src/routify.config.js
module.exports = {
	sourceDir: './public/html',
	pages: './src/interface/presenters/pages',
	// childProcess: true,
}

デバックやignoreなど他機能はあるので詳細は下記をご覧ください。
https://www.routify.dev/docs/config/build

まとめ

最後に選定にあたって、ドキュメントの充実さを上げましたが使用事例などネットで調べた際になかなか見つからなかったのがあり今回使用した機能などを中心に記事を書かせていただきました。もちろん他に便利な機能もあるのは承知ですがライブラリの移行をメインに行ったので今後も上記にあがらなかった機能を使用していくことになると思うので、その際は別記事でまたまとめていきたいと思います。
なるべくドキュメントに沿っていますが、自分なりの解釈が入っています。日本語の記事が少なかったので記事にさせていただきましたが、お手数ですが詳細を知りたい方はドキュメントの方をご覧になってください。

Discussion