チュートリアル: JavaScript

Web Components Islands

Islands と Web Components を組み合わせてスタイルのカプセル化と相互運用性を実現します。

なぜ Web Components か?

Web Components が提供するもの:

機能メリット
Shadow DOMスタイルのカプセル化
Custom Elements標準 API
Declarative Shadow DOMSSR サポート
相互運用性どこでも動作

Web Component Island の作成

サーバーレンダリングされた HTML

サーバーが Web Component 属性を持つ Island をレンダリング:

MoonBit でのサーバーサイドレンダリングについては、MoonBit チュートリアルを参照してください。

<wc-counter
  luna:wc-url="/static/wc-counter.js"
  luna:wc-state="0"
  luna:wc-trigger="load"
>
  <template shadowrootmode="open">
    <style>
      :host { display: block; padding: 16px; }
      button { background: blue; color: white; }
    </style>
    <button>Count: 0</button>
  </template>
</wc-counter>

クライアントサイド(TypeScript)

// wc-counter.ts
import { createSignal, hydrateWC } from '@luna_ui/luna';

interface CounterProps {
  initial: number;
}

function Counter(props: CounterProps) {
  const [count, setCount] = createSignal(props.initial);

  return (
    <>
      <style>
        {`:host { display: block; padding: 16px; }
          button { background: blue; color: white; }`}
      </style>
      <button onClick={() => setCount(c => c + 1)}>
        Count: {count()}
      </button>
    </>
  );
}

// Web Component として登録
hydrateWC("wc-counter", Counter);

Declarative Shadow DOM

Luna は SSR に Declarative Shadow DOM を使用:

<my-component>
  <template shadowrootmode="open">
    <style>/* スコープ付きスタイル */</style>
    <!-- Shadow DOM コンテンツ -->
  </template>
</my-component>

メリット:

  • スタイルが即座に適用(FOUC なし)

  • 初期レンダリングに JavaScript 不要

  • ハイドレーション前にコンテンツが表示

スタイルのカプセル化

Shadow DOM 内のスタイルはスコープ付き:

/* これらはコンポーネントにのみ影響 */
:host {
  display: block;
  border: 1px solid #ccc;
}

button {
  /* 外側のボタンには影響しない */
  background: blue;
}

WC vs 通常の Islands

観点通常の IslandWC Island
スタイルグローバル CSSスコープ付き(Shadow DOM)
要素<div>カスタム要素
SSRinnerHTMLDeclarative Shadow DOM
スロットサポートなしサポート
外部スタイリング簡単CSS parts が必要

Web Components を使うタイミング

WC Islands を使用:

  • スタイル分離が必要なコンポーネント

  • 異なるプロジェクトで再利用可能

  • スロットを持つコンポーネント

  • デザインシステムコンポーネント

通常の Islands を使用:

  • シンプルなインタラクティブウィジェット

  • グローバルスタイルが必要なコンポーネント

  • 素早いプロトタイピング

CSS Parts

外部からのカスタマイズ用にスタイルフックを公開:

// コンポーネント内
<button part="button">クリック</button>
/* 外部から */
wc-counter::part(button) {
  background: red;  /* 内部スタイルを上書き */
}

まとめ

Luna チュートリアルを完了しました!以下を学びました:

  • Signals - リアクティブな状態

  • Effects - 副作用

  • Memos - 計算値

  • 制御フロー - 条件/リストレンダリング

  • ライフサイクル - マウント/クリーンアップ

  • Islands - 部分的ハイドレーション

  • Web Components - カプセル化

次のステップ