Skip to content

Instantly share code, notes, and snippets.

@hdknr
Last active February 26, 2025 09:04
Show Gist options
  • Save hdknr/9de5db214a9d832bb77e3417d49c1d9b to your computer and use it in GitHub Desktop.
Save hdknr/9de5db214a9d832bb77e3417d49c1d9b to your computer and use it in GitHub Desktop.
Svelte

Svelte

Gradio

import gradio as gr

def greet(name):
    return f"Hello, {name}!"

demo = gr.Interface(
    fn=greet,
    inputs="text",
    outputs="text",
)

demo.launch()

Gradio App.svelte カスタマイズ

import gradio as gr

def greet(name):
    return f"Hello, {name}!"

gr.Interface(
    fn=greet,
    inputs="text",
    outputs="text",
    title="My Gradio App",
    description="A simple greeting app.",
    # App.svelteのパスを指定
    template_file="templates/custom_app.svelte"
    # カスタムCSS 
    css="custom.css"
).launch()

custom_app.svelte:

<script>
  export let title;
  export let description;
</script>

<h1>{title}</h1>
<p>{description}</p>

記事

each ブロック

Svelte で JSON の配列に格納されているコンテンツをループ処理でレンダリングするには、{#each} ブロックを使用します。

基本的な例

<script>
  let jsonData = [
    { id: 1, name: 'りんご', price: 100 },
    { id: 2, name: 'みかん', price: 50 },
    { id: 3, name: 'バナナ', price: 80 },
  ];
</script>

<h1>フルーツ一覧</h1>
<ul>
  {#each jsonData as item}
    <li>
      ID: {item.id} - 名前: {item.name} - 価格: {item.price}円
    </li>
  {/each}
</ul>

解説

  • jsonData 変数に JSON 配列を格納します。
  • {#each jsonData as item} で配列の各要素を item としてループ処理します。
  • li タグ内で item のプロパティ (id, name, price) を表示します。

より実践的な例

JSON データを外部ファイルから取得し、コンポーネントに渡してレンダリングする例です。

<script>
  import fruits from './fruits.json'; // fruits.json からデータを読み込む

  function handleDelete(id) {
    // 配列から要素を削除する処理など
  }
</script>

<h1>フルーツ一覧</h1>
<ul>
  {#each fruits as fruit}
    <li>
      ID: {fruit.id} - 名前: {fruit.name} - 価格: {fruit.price}円
      <button on:click={() => handleDelete(fruit.id)}>削除</button>
    </li>
  {/each}
</ul>

fruits.json

[
  { "id": 1, "name": "りんご", "price": 100 },
  { "id": 2, "name": "みかん", "price": 50 },
  { "id": 3, "name": "バナナ", "price": 80 }
]

その他

  • {#each} ブロックでは、index (インデックス) や key (キー) などの特別な変数も使用できます。
  • 配列が空の場合に表示する内容を {:else} ブロックで指定できます。
  • {#await} ブロックと組み合わせて、非同期処理で取得した JSON データをレンダリングすることもできます。

参考情報

資料

head の書き換え

Svelte でイベントが発生した時にページの title タグの内容を書き換えるには、いくつかの方法があります。

方法 1: bind:this を使う

要素の参照をコンポーネントの変数にバインドし、その変数の textContent プロパティを書き換えることで title タグの内容を変更できます。

<script>
  let titleElement;

  function handleClick() {
    titleElement.textContent = '新しいタイトル';
  }
</script>

<svelte:head>
  <title bind:this={titleElement}>元のタイトル</title>
</svelte:head>

<button on:click={handleClick}>タイトルを変更</button>

この例では、svelte:head 内の title 要素を titleElement 変数にバインドしています。ボタンがクリックされると handleClick 関数が実行され、titleElement.textContent を新しいタイトルに書き換えます。

方法 2: document.title を使う

JavaScript の document.title プロパティを使うことでも title タグの内容を変更できます。

<script>
  function handleClick() {
    document.title = '新しいタイトル';
  }
</script>

<svelte:head>
  <title>元のタイトル</title>
</svelte:head>

<button on:click={handleClick}>タイトルを変更</button>

この例では、ボタンがクリックされると handleClick 関数が実行され、document.title を新しいタイトルに書き換えます。

方法 3: svelte:head をリアクティブにする

svelte:head ブロック内で変数を使い、その変数の値を変更することで title タグの内容をリアクティブに変更できます。

<script>
  let title = '元のタイトル';

  function handleClick() {
    title = '新しいタイトル';
  }
</script>

<svelte:head>
  <title>{title}</title>
</svelte:head>

<button on:click={handleClick}>タイトルを変更</button>

この例では、title 変数の値を変更すると、svelte:head 内の title 要素の内容が自動的に更新されます。

おすすめの方法

通常は、方法 3: svelte:head をリアクティブにする が最もおすすめです。この方法を使うと、title タグの内容をリアクティブに変更できるため、ユーザーエクスペリエンスが向上します。

注意点

  • title タグの内容は、SEO (検索エンジン最適化) に重要な役割を果たします。適切に設定するようにしましょう。
  • title タグの内容は、ページの URL やコンテンツの内容と一致していることが望ましいです。

簡単なWeb Component

Svelte で Web Component を作成し、既存の HTML ページの指定したタグにマウントする方法は以下の通りです。

1. Svelte コンポーネントの作成

まず、Web Component として使用する Svelte コンポーネントを作成します。

<script>
  export let name = "World";
</script>

<h1>Hello {name}!</h1>

このコンポーネントは、name というプロパティを受け取り、それを <h1> タグに表示します。

2. Web Component としてコンパイル

Svelte コンポーネントを Web Component としてコンパイルするには、svelte:options タグを使用します。

<svelte:options tag="my-component" />

<script>
  export let name = "World";
</script>

<h1>Hello {name}!</h1>

tag 属性に Web Component のタグ名を指定します。この例では、my-component というタグ名になります。

3. ビルド

Svelte コンポーネントをビルドして、Web Component として使用できる JavaScript ファイルを生成します。

npm run build

4. HTML ページにマウント

生成された JavaScript ファイルを HTML ページに読み込み、Web Component をマウントします。

<!DOCTYPE html>
<html>
<head>
  <title>Svelte Web Component</title>
</head>
<body>
  <my-component name="John"></my-component>
  <script type="module" src="./build/bundle.js"></script>
</body>
</html>

my-component タグを HTML ページに追加し、name 属性に値を指定することで、Svelte コンポーネントをマウントできます。

注意点

  • Web Component のタグ名は、ハイフンを含む必要があります。
  • ビルドされた JavaScript ファイルは、type="module" 属性を指定した <script> タグで読み込む必要があります。

その他

  • Svelte コンポーネントのプロパティは、Web Component の属性として設定できます。
  • Svelte コンポーネントのイベントは、Web Component のカスタムイベントとしてディスパッチされます。

参考資料

プロジェクトの作り方

Svelte で Web コンポーネントを作成するプロジェクトを始めるには、以下の手順で進めます。

1. プロジェクトの作成

まず、Svelte の新しいプロジェクトを作成します。以下のコマンドをターミナルで実行します。

npm create vite@latest my-svelte-web-component --template svelte
cd my-svelte-web-component
npm install

これにより、my-svelte-web-component という名前の新しい Svelte プロジェクトが作成されます。

2. Web コンポーネントの作成

次に、Web コンポーネントを作成します。src ディレクトリ内に新しいファイルを作成し、例えば MyComponent.svelte という名前を付けます。

MyComponent.svelte の内容は以下のようになります。

<svelte:options tag="my-component" />

<script>
  export let name = "World";
</script>

<h1>Hello, {name}!</h1>

<svelte:options tag="my-component" /> は、このコンポーネントを my-component という名前のカスタム要素として登録するための設定です。

3. Web コンポーネントのビルド

Web コンポーネントをビルドするには、以下のコマンドを実行します。

npm run build

これにより、dist ディレクトリ内にビルドされたファイルが生成されます。

4. Web コンポーネントの使用

ビルドされた Web コンポーネントは、通常の HTML ファイル内で以下のように使用できます。

<!DOCTYPE html>
<html>
<head>
  <title>My Web Component</title>
</head>
<body>
  <my-component name="Svelte"></my-component>
  <script src="./dist/my-component.js"></script>
</body>
</html>

dist/my-component.js は、ビルドされた Web コンポーネントの JavaScript ファイルです。

補足

  • SvelteKit を使用している場合は、src/routes ディレクトリ内に Web コンポーネントを作成する必要があります。
  • Web コンポーネントのスタイルは、通常の Svelte コンポーネントと同様に <style> タグ内で記述できます。
  • Web コンポーネントのプロパティは、export let で定義します。
  • Web コンポーネントのイベントは、dispatchEvent を使用して発行します。

その他

Svelte で Web コンポーネントを作成する際には、以下の記事も参考になります。

$state, $props

Svelteの$state$propsは、それぞれ異なる役割を果たします。

$state

  • 役割: コンポーネントの内部状態を管理します。

  • 使い方: コンポーネント内で変数を宣言し、その変数が変更されると自動的にUIが再レンダリングされます。

  • :

    <script>
      let count = 0;
    </script>
    
    <button on:click={() => count += 1}>
      Clicked {count} times
    </button>

$props

  • 役割: 親コンポーネントから子コンポーネントにデータを渡すために使用されます。

  • 使い方: 子コンポーネントでexportキーワードを使ってプロパティを宣言し、親コンポーネントからそのプロパティに値を渡します。

  • :

    <!-- Parent.svelte -->
    <script>
      import Child from './Child.svelte';
      let message = "Hello from parent!";
    </script>
    
    <Child message={message} />
    
    <!-- Child.svelte -->
    <script>
      export let message;
    </script>
    
    <p>{message}</p>
    

**** ```

静的Webサイトへの組み込み

Svelte プロジェクトを既存の静的 HTML サイトに組み込むための構成はいくつか考えられます。以下に代表的な構成と、それぞれのメリット・デメリット、具体的な実装例を記載します。

1. Web Components としてビルドする

Svelte コンポーネントを Web Components としてビルドし、既存の HTML に JavaScript で読み込む方法です。

メリット

  • 既存のサイト構造に影響を与えにくい
  • Svelte コンポーネントを独立して管理できる
  • 必要に応じて複数の Svelte コンポーネントを組み込める

デメリット

  • Web Components の仕様に沿ったコードが必要になる
  • ブラウザによってはポリフィルが必要になる場合がある

実装例

// MyComponent.svelte
<script>
  export let name = 'world';
</script>

<h1>Hello {name}!</h1>

<style>
  h1 {
    color: blue;
  }
</style>
// main.js
import MyComponent from './MyComponent.svelte';

customElements.define('my-component', class extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    new MyComponent({ target: shadow, props: { name: this.getAttribute('name') } });
  }
});
<my-component name="Svelte"></my-component>
<script src="main.js"></script>

2. 特定の要素にマウントする

既存の HTML の特定の要素に Svelte コンポーネントをマウントする方法です。

メリット

  • 既存の HTML 構造を比較的自由に利用できる
  • Svelte コンポーネントの管理がしやすい

デメリット

  • マウント先の要素の構造に依存する
  • 複数の Svelte コンポーネントを組み込む場合に工夫が必要

実装例

// MyComponent.svelte
<script>
  export let name = 'world';
</script>

<h1>Hello {name}!</h1>

<style>
  h1 {
    color: blue;
  }
</style>
// main.js
import MyComponent from './MyComponent.svelte';

const target = document.querySelector('#svelte-app');
new MyComponent({ target, props: { name: 'Svelte' } });
<div id="svelte-app"></div>
<script src="main.js"></script>

3. iframe を利用する

Svelte アプリケーションを iframe 内に組み込み、既存の HTML から参照する方法です。

メリット

  • Svelte アプリケーションを完全に独立させることができる
  • 既存のサイト構造に影響を与えにくい

デメリット

  • iframe の制約を受ける
  • 親ページとの連携が難しい

実装例

// MyComponent.svelte
<h1>Hello Svelte!</h1>
<iframe src="svelte-app.html"></iframe>
<div id="svelte-app"></div>
<script>
  import MyComponent from './MyComponent.svelte';
  new MyComponent({ target: document.querySelector('#svelte-app') });
</script>

補足

  • 上記以外にも、SvelteKit を利用して一部のページを Svelte で生成し、既存のサイトに組み込む方法も考えられます。
  • どの方法を選択するかは、サイトの規模や構造、Svelte コンポーネントの役割によって異なります。

ご希望に応じて、より詳細な手順や具体的なコード例を提供できます。

Viteで開始

% node --version
v20.17.0
npm create vite@latest my-svelte-web-component --template svelte
[email protected]
Ok to proceed? (y) y

> npx
> create-vite my-svelte-web-component svelte

✔ Select a framework: › Svelte
✔ Select a variant: › TypeScript

Scaffolding project in /Users/hdknr/Projects/shiftone/my-svelte-web-component...

Done. Now run:

  cd my-svelte-web-component
  npm install
  npm run dev

Wizard フォーム

Svelte で 3 画面のウィザード形式フォームを作成し、結果を POST する Web Component のサンプルコード

以下に、Svelte を使用して 3 画面のウィザード形式フォームを作成し、結果を POST する Web Component のサンプルコードと、その解説を記載します。

ポイント:

  • Svelte コンポーネント: ウィザード形式のフォーム全体を WizardForm という Svelte コンポーネントとして作成します。
  • 状態管理: currentStep 変数で現在のステップを管理し、formValues オブジェクトでフォームの入力値を保持します。
  • ステップ表示: 各ステップの内容を Step1Step2Step3 という別の Svelte コンポーネントとして作成し、currentStep に応じて表示を切り替えます。
  • POST処理: 最後のステップで「送信」ボタンをクリックすると、handleSubmit 関数が実行され、formValues の内容を JSON 形式で POST します。
  • Web Component 化: Svelte コンポーネントを Web Component として定義し、HTML で簡単に利用できるようにします。

コード:

<script>
  import Step1 from './Step1.svelte';
  import Step2 from './Step2.svelte';
  import Step3 from './Step3.svelte';

  let currentStep = 1;
  let formValues = {
    name: '',
    email: '',
    message: ''
  };

  function nextStep() {
    currentStep++;
  }

  function prevStep() {
    currentStep--;
  }

  async function handleSubmit() {
    const response = await fetch('/your-api-endpoint', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(formValues)
    });

    if (response.ok) {
      alert('送信が完了しました!');
    } else {
      alert('送信に失敗しました。');
    }
  }
</script>

<div class="wizard-form">
  {#if currentStep === 1}
    <Step1 bind:values={formValues} on:next={nextStep} />
  {:else if currentStep === 2}
    <Step2 bind:values={formValues} on:prev={prevStep} on:next={nextStep} />
  {:else if currentStep === 3}
    <Step3 bind:values={formValues} on:prev={prevStep} on:submit={handleSubmit} />
  {/if}
</div>

<style>
  .wizard-form {
    /* スタイリング */
  }
</style>

Step1.svelte:

<script>
  export let values;
  export let next;
</script>

<div>
  <h2>ステップ 1</h2>
  <label for="name">名前:</label>
  <input type="text" id="name" bind:value={values.name} />
  <button on:click={next}>次へ</button>
</div>

Step2.svelte:

<script>
  export let values;
  export let prev;
  export let next;
</script>

<div>
  <h2>ステップ 2</h2>
  <label for="email">メールアドレス:</label>
  <input type="email" id="email" bind:value={values.email} />
  <button on:click={prev}>前へ</button>
  <button on:click={next}>次へ</button>
</div>

Step3.svelte:

<script>
  export let values;
  export let prev;
  export let submit;
</script>

<div>
  <h2>ステップ 3</h2>
  <label for="message">メッセージ:</label>
  <textarea id="message" bind:value={values.message}></textarea>
  <button on:click={prev}>前へ</button>
  <button on:click={submit}>送信</button>
</div>

Web Component として定義:

import WizardForm from './WizardForm.svelte';

customElements.define('wizard-form', class extends HTMLElement {
  constructor() {
    super();
    const shadowRoot = this.attachShadow({ mode: 'open' });
    new WizardForm({ target: shadowRoot });
  }
});

HTML での使用例:

<wizard-form></wizard-form>

解説:

  • 各ステップコンポーネント (Step1Step2Step3) は、bind:values で親コンポーネント (WizardForm) の formValues を共有し、on:nexton:prev でステップの移動を制御します。
  • 最後のステップ (Step3) で「送信」ボタンをクリックすると、handleSubmit 関数が実行され、fetch API を使ってフォームの入力値を POST します。
  • customElements.define を使用して、wizard-form という名前の Web Component として登録します。

注意点:

  • 上記のコードはあくまでサンプルです。実際には、フォームのバリデーションやエラー処理、API エンドポイントの設定など、必要な機能を追加する必要があります。
  • スタイリングは CSS で自由に変更できます。

このサンプルコードを参考に、Svelte を使って 3 画面のウィザード形式フォームを作成し、結果を POST する Web Component を作成してみてください。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment