svelte5ダイナミックコンポーネントを使ったテーマ変更

更新


プログラミング/svelte

svelte5 ではコンポーネント名を動的に決められるのだそうです

通常であれば

LANG:html
<Component>Hello!</Component>

と書くところを、

LANG:html
<theme.Component>Hello!</theme.Component>

と書ける。


そこで、theme にいろいろなコンポーネントを持たせておいて、 動的にその中身を差し替えることでテーマを変更することが可能になる。

LANG:ts
  const defaultTheme = {Component: DefaultComponent};
  const alternativeTheme = {Component: AlternativeComponent} satisfies Theme;
  let theme = $derived(sw ? defaultTheme : alternativeTheme);

としておくと、

LANG:html
<theme.Component />

と書いた部分を DefaultComponent と AlternativeComponent の間で動的に切り替えられるわけです。


こちらで試せます: https://svelte-5-preview.vercel.app/...

LANG:html
<script lang="ts">
	import DefaultComponent from './DefaultComponent.svelte';
	import AlternativeComponent from './AlternativeComponent.svelte';

	// default theme
	const defaultTheme = {Component: DefaultComponent};
	type Theme = typeof defaultTheme;

	// one theme may contain many components

	// default theme
	const alternativeTheme = {Component: AlternativeComponent} satisfies Theme;

	// `satisfies Theme` above confirms each component in alternativeTheme
	// is compatible with the correspondent in the defaultTheme.

	// theme can be easily switched
	let sw = $state(true);
	let theme = $derived(sw ? defaultTheme : alternativeTheme);
</script>

<button onclick={()=> sw = !sw}>
	Tollge Theme
</button>

<theme.Component></theme.Component>

DefaultComponent.svelte

LANG:html
<p>DEFAULT</p>

AlternativeComponent.svelte

LANG:html
<p>ALTERNATIVE</p>

とても便利!

これをコンポーネント化する際には気を付けないといけないのかもしれません?

発生理由をちゃんと把握できていないのですが、全体を npm コンポーネントにして他のプロジェクトで使おうとした場合、

<theme.Component>

という書き方をしているとうまく展開されない場合があるのかもしれません?

  const { Component } = theme;
</script>

<Component>

のような書き方の方が無難かもしれない???

他のいろんなエラーと重なったりで未検証ですがメモとして残しておきます。

svelte コンポーネントを npm パッケージにする際の vite の設定

https://github.com/sveltejs/svelte/discussions/11376#discussioncomment-9262171 にあるように、

vite.config.ts に

 optimizeDeps: {
   exclude: ['svelte'],
 },

を加えないと

Error: onMount can only be used during component initialisation.

のようなエラーで表示が止まることがあるようでした。


Counter: 889 (from 2010/06/03), today: 2, yesterday: 10