mcpField
U
umbraco-example-generator

umbraco-example-generator

github.com/umbraco開発27375 回インストール6 週間前に更新
リポジトリ

umbraco-example-generator について

Umbraco Example Generator は、テスト可能な Umbraco backoffice 拡張のサンプルを作成し、Umbraco ソースの開発環境で実行するためのスキルです。外部パスからの読み込み、API のモック、ホットリロードに対応します。

主な機能

  1. 01backoffice 拡張サンプルの作成
  2. 02ソース内または外部パスから読み込み
  3. 03API をモックして拡張を実行
  4. 04開発中のホットリロード
  5. 05サンプルへの単体・E2E テスト追加

活用シーン

  1. 01デモ用およびテスト可能な拡張の作成
  2. 02拡張の変更を素早く開発・確認
  3. 03.NET バックエンドなしでの拡張テスト

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/umbraco/umbraco-cms-backoffice-skills --skill umbraco-example-generator

インストール後、Claude Code で/umbraco-example-generatorを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

examples/workspace-feature-toggle/
feature-toggle-action.ts
feature-toggle-context.test.ts
feature-toggle-context.ts
feature-toggle-footer.element.ts
feature-toggle-view.element.ts
index.ts
package-lock.json
package.json
README.md
tsconfig.json
web-test-runner.config.mjs
examples/workspace-feature-toggle/tests/
feature-toggle.spec.ts
playwright.config.ts
warmup.setup.ts

詳細

Umbraco サンプルジェネレーター

Umbraco バックオフィス向けの完全でテスト可能なサンプル拡張機能を生成し、Umbraco ソースの開発インフラストラクチャを使用して実行します。

使用する場面

  • デモ用の拡張機能を作成するとき
  • テスト可能な拡張機能のサンプルを構築するとき
  • ホットリロードによる迅速な開発
  • .NET バックエンドなしで拡張機能をテストするとき

関連スキル

  • umbraco-unit-testing - サンプルにユニットテストを追加します
  • umbraco-mocked-backoffice - E2E テストのパターン
  • umbraco-backoffice - 拡張機能タイプのブループリント

クイックスタート

1. Umbraco ソースをクローンする(初回のみのセットアップ)
git clone https://github.com/umbraco/Umbraco-CMS
cd Umbraco-CMS/src/Umbraco.Web.UI.Client
npm install
2. 拡張機能フォルダーを作成する
my-extension/
├── index.ts           # REQUIRED - exports manifests
└── my-element.ts      # Your element(s)
3. index.ts を作成する(マニフェストをエクスポートします)
import './my-element.js';

export const manifests = [
  {
    type: 'dashboard',
    alias: 'My.Dashboard',
    name: 'My Dashboard',
    element: 'my-element',
    meta: { label: 'My Dashboard', pathname: 'my-dashboard' },
    conditions: [{ alias: 'Umb.Condition.SectionAlias', match: 'Umb.Section.Content' }]
  }
];
4. 要素を作成する
// my-element.ts
import { LitElement, html, customElement } from '@umbraco-cms/backoffice/external/lit';

@customElement('my-element')
export class MyElement extends LitElement {
  render() {
    return html`<uui-box headline="Hello">It works!</uui-box>`;
  }
}
5. 実行する
cd Umbraco-CMS/src/Umbraco.Web.UI.Client
VITE_EXAMPLE_PATH=/full/path/to/my-extension VITE_UMBRACO_USE_MSW=on npm run dev

http://localhost:5173 を開きます - 拡張機能が Content セクションに表示されます。


仕組み

Umbraco ソース(Umbraco-CMS/src/Umbraco.Web.UI.Client)は、拡張機能を読み込む 2 つの方法を提供します。

1. 内部サンプル(npm run example)

Umbraco ソース内の examples/ フォルダーに配置されたサンプルです。

cd Umbraco-CMS/src/Umbraco.Web.UI.Client
npm run example
# Select from list of examples

仕組み: VITE_EXAMPLE_PATH を設定し、./examples/{name}/index.ts をインポートします

2. 外部拡張機能(絶対パスの VITE_EXAMPLE_PATH)

ファイルシステム上の任意の場所にある拡張機能 - パッケージの開発に最適です。

cd Umbraco-CMS/src/Umbraco.Web.UI.Client
VITE_EXAMPLE_PATH=/path/to/your/extension VITE_UMBRACO_USE_MSW=on npm run dev

仕組み:

  1. VITE_UMBRACO_USE_MSW=on がコアの Umbraco API をモックします
  2. 絶対パスの VITE_EXAMPLE_PATH が Vite の /@fs/ プレフィックスを通じて配信されます
  3. index.ts が <VITE_EXAMPLE_PATH>/index.ts をインポートし、そのエクスポートを umbExtensionsRegistry に登録します
  4. 共有パッケージリゾルバーが @umbraco-cms/backoffice、lit、@umbraco-ui/uui をクライアント側のコピーにマッピングします(Lit/UUI の重複を回避します)

絶対パスのサポート(ステップ 2 と 4)には、外部サンプルをサポートしてビルドされた v18 クライアントが必要です。このリポジトリのモック E2E スイートを実行する場合、Playwright ハーネスがそのサポートを UMBRACO_CLIENT_PATH のクライアントに自動的に注入し、その後元に戻します — umbraco-mocked-backoffice スキルを参照してください。

拡張機能の読み込み(index.ts)
// From Umbraco-CMS/src/Umbraco.Web.UI.Client/index.ts
if (import.meta.env.VITE_EXAMPLE_PATH) {
  const examplePath = import.meta.env.VITE_EXAMPLE_PATH;
  // Absolute paths (external extensions) are served via Vite's /@fs/ prefix; relative paths load from ./
  const importPath = examplePath.startsWith('/') ? '/@fs' + examplePath : './' + examplePath;
  const js = await import(importPath + '/index.ts');
  if (js) {
    Object.keys(js).forEach((key) => {
      const value = js[key];
      if (Array.isArray(value)) {
        umbExtensionsRegistry.registerMany(value);
      } else if (typeof value === 'object') {
        umbExtensionsRegistry.register(value);
      }
    });
  }
}

重要なポイント: index.ts は、自動的に登録されるマニフェスト(配列またはオブジェクト)をエクスポートする必要があります。


セットアップ

前提条件

Umbraco ソースをクローンしてセットアップします。

git clone https://github.com/umbraco/Umbraco-CMS
cd Umbraco-CMS/src/Umbraco.Web.UI.Client
npm install
拡張機能の構造

拡張機能には、この最小限の構造が必要です。

my-extension/
├── index.ts              # Exports manifests array (REQUIRED)
├── my-element.ts         # Your element(s)
├── my-context.ts         # Context (if needed)
├── package.json          # Optional - for IDE support and tests
├── tsconfig.json         # Optional - for IDE support
└── README.md             # Documentation
必須: index.ts

index.ts は、登録されるマニフェストを必ずエクスポートする必要があります。

import './my-dashboard.element.js';

export const manifests = [
  {
    type: 'dashboard',
    alias: 'My.Dashboard',
    name: 'My Dashboard',
    element: 'my-dashboard',
    weight: 100,
    meta: {
      label: 'My Dashboard',
      pathname: 'my-dashboard'
    },
    conditions: [
      {
        alias: 'Umb.Condition.SectionAlias',
        match: 'Umb.Section.Content'
      }
    ]
  }
];
任意: package.json(IDE サポート用)
{
  "name": "my-extension",
  "type": "module",
  "devDependencies": {
    "@umbraco-cms/backoffice": "^18.0.0",
    "typescript": "~5.8.0"
  }
}

重要: @umbraco-cms/backoffice 依存関係は、IDE の TypeScript サポートのためのものだけです。実行時には、インポートはメインの Umbraco プロジェクトから解決されます。


拡張機能の実行

モックされたバックオフィスを起動する
cd /path/to/Umbraco-CMS/src/Umbraco.Web.UI.Client
VITE_EXAMPLE_PATH=/absolute/path/to/my-extension VITE_UMBRACO_USE_MSW=on npm run dev
ブラウザーで開く

http://localhost:5173 に移動します - 拡張機能が自動的に読み込まれます。

ホットリロード

拡張機能のファイルへの変更はホットリロードをトリガーします - 再起動は不要です。


パターン

基本的な要素
// my-dashboard.element.ts
import { LitElement, html, css, customElement } from '@umbraco-cms/backoffice/external/lit';

@customElement('my-dashboard')
export class MyDashboardElement extends LitElement {
  static override styles = css`
    :host {
      display: block;
      padding: var(--uui-size-layout-1);
    }
  `;

  override render() {
    return html`
      <uui-box headline="My Extension">
        <p>Running in the mocked backoffice!</p>
      </uui-box>
    `;
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'my-dashboard': MyDashboardElement;
  }
}
コンテキストを持つ要素
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { EXAMPLE_MY_CONTEXT } from './my-context.js';

@customElement('example-my-feature-view')
export class ExampleMyFeatureViewElement extends UmbLitElement {
  @state()
  private _value?: string;

  constructor() {
    super();
    this.consumeContext(EXAMPLE_MY_CONTEXT, (context) => {
      this.observe(context.value, (value) => {
        this._value = value;
      });
    });
  }

  override render() {
    return html`
      <uui-box headline="My Feature Example">
        <p>Current value: ${this._value ?? 'Loading...'}</p>
      </uui-box>
    `;
  }
}

export default ExampleMyFeatureViewElement;

declare global {
  interface HTMLElementTagNameMap {
    'example-my-feature-view': ExampleMyFeatureViewElement;
  }
}
コンテキスト
import { UmbContextToken } from '@umbraco-cms/backoffice/context-api';
import { UmbContextBase } from '@umbraco-cms/backoffice/class-api';
import { UmbStringState } from '@umbraco-cms/backoffice/observable-api';
import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

export class ExampleMyContext extends UmbContextBase {
  #value = new UmbStringState('initial');
  readonly value = this.#value.asObservable();

  constructor(host: UmbControllerHost) {
    super(host, EXAMPLE_MY_CONTEXT);
  }

  setValue(value: string) {
    this.#value.setValue(value);
  }

  getValue() {
    return this.#value.getValue();
  }

  public override destroy(): void {
    this.#value.destroy();
    super.destroy();
  }
}

export const EXAMPLE_MY_CONTEXT = new UmbContextToken<ExampleMyContext>(
  'ExampleMyContext'
);

export { ExampleMyContext as api };

テストの追加

ユニットテスト

@open-wc/testing を使用してユニットテストを追加します。完全なセットアップについては umbraco-unit-testing スキルを参照してください。

npm install --save-dev @open-wc/testing @web/test-runner @web/test-runner-playwright
E2E テスト(Playwright)

モックされたバックオフィスに対して実行される E2E テストを追加します。パターンについては umbraco-mocked-backoffice スキルを参照してください。

npm install --save-dev @playwright/test
npx playwright install chromium

サンプル

リファレンスサンプル

場所: ./examples/workspace-feature-toggle/

以下を示す完全なスタンドアロンのサンプルです:

  • UmbArrayState を使用したワークスペースコンテキスト
  • コンテキストを利用するワークスペースビュー
  • コンテキストメソッドを実行するワークスペースアクション
  • 概要を表示するワークスペースフッターアプリ
  • 38 件のユニットテスト + 13 件の E2E テスト
cd examples/workspace-feature-toggle
npm install
npm test              # Unit tests
npm run test:e2e      # E2E tests (requires mocked backoffice running)
公式 Umbraco サンプル

場所: Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/

すべての拡張機能タイプを網羅する 27 件の公式サンプルです。任意のサンプルを実行できます:

cd Umbraco-CMS/src/Umbraco.Web.UI.Client
npm run example
# Select from list

命名規則

項目規則例
ディレクトリ機能を表す kebab-caseworkspace-context-counter
エイリアス接頭辞example.example.workspaceView.counter
要素接頭辞example-example-counter-view
コンテキストトークンEXAMPLE_ + SCREAMING_CASEEXAMPLE_COUNTER_CONTEXT

トラブルシューティング

拡張機能が表示されない
  1. index.ts が manifests 配列をエクスポートしているか確認する
  2. VITE_EXAMPLE_PATH のパスが絶対パスであることを確認する
  3. ブラウザのコンソールで 📦 Loading external example from: メッセージを確認する
  4. 条件が、表示しているセクションと一致していることを確認する
インポートエラー

インポートには @umbraco-cms/backoffice/* を使用してください。Vite プラグインがこれらをメインプロジェクトから解決します。

"CustomElementRegistry" がすでに定義されている

拡張機能の node_modules が、メインプロジェクトのものではなく使用されています。external-example-resolver プラグインがこれを処理するはずですが、以下を確認してください:

  • VITE_EXAMPLE_PATH=<abs> VITE_UMBRACO_USE_MSW=on npm run dev を使用している
  • インポートが node_modules への相対パスではなく @umbraco-cms/backoffice/* を使用している
変更がホットリロードされない

ファイルが VITE_EXAMPLE_PATH で指定されたパス内にあることを確認してください。そのディレクトリツリー内のファイルのみが監視されます。

コメント