🥚

Svelte context="module"のちょっとよさげな使い方

2023/09/22に公開

概要

基本的な使い方はこの辺のチュートリアルを見てください。

Svelteでは通常のscriptタグ以外に、もう一つcontext="module"つきのscriptタグを使用することができます。

例 Context

例えばsetContext,getContextを使用する場合、キー名やそのContextにどういう値が入ってくるのかの型を親コンポーネント側のcontext="module"でexportしておくことで、

  • 子孫コンポーネントでそれをimportすれば間違ったキー名を指定しなくてすむ
  • setContextされた値がどんな型なのかを共有できる

などの利点があります。

親と子で別々で書いてしまうと片方に変更があった場合修正漏れが発生してしまいそうですし、
「このコンポーネントがsetContextしていてそれを子で使う」というのが
import { KEY_WORD_CONTEXT, type WordContext } from './Parent.svelte';
の部分で明確になります。

Contextを使用する場合、これどこでsetContextされたやつなん…?になりがちなので、親コンポーネントのcontext="module"でexportするとよいでしょう。

context="module"を使わず、仮になにか別の.tsファイルを作成してそちらに書いておく場合、
「そのコンポーネントに関連する値」という意図が少し薄れてしまって予想外のところで使用されてしまうかもしれません。

この懸念から、そのコンポーネントに密接に関連している値や関数はcontext="module"からexportするようにしています。

以下が使用例です。

Parent.svelte
<script context="module" lang="ts">
  import type { Writable } from 'svelte/store';
  export const KEY_WORD_CONTEXT = Symbol('word');
  export type WordContext = Writable<string>;
</script>

<script lang="ts" strictEvents>
  import { setContext } from 'svelte';
  import { writable } from 'svelte/store';
  type $$Slots = {
    default: unknown;
  };
  let word: WordContext = writable('Hello World')
  setContext<WordContext>(KEY_WORD_CONTEXT, word);
</script>

<slot />
Grandchild.svelte
<script lang="ts" strictEvents>
  import { getContext } from 'svelte';
  import { KEY_WORD_CONTEXT, type WordContext } from './Parent.svelte';
  let word = getContext<WordContext>(KEY_WORD_CONTEXT);
</script>

<p>{$word}</p>

例 テスト

また、他にもテストで使用しやすいようにcontext="module"から固定値やコンポーネント内でのみ使用するロジックをexportしておいたりもします。

<script context="module" lang="ts">
  export const label = 'パンくずリスト'
</script>
<nav aria-label={label} />

テストファイルでlabelをimportして、aria-labelの値がこれと一致しているかテストします。
テストファイル内にそのまま書いてしまうと、変更があった時にコンポーネント側とテストファイル側で2回書かなくてはならなくなります。

まとめ

<script context="module" lang="ts">は使い慣れればめっちゃ便利だな になるのですが、最初ドキュメントを読んでもイマイチピンと来ないかもしれません。

便利なので使い倒しましょう。

Discussion