ONLYOFFICEプラグインの作成:コツ、秘訣、そして隠れた落とし穴

2026年01月22日著者:Denis

ONLYOFFICEエディタ用のプラグインを構築することは簡単ですが、実際の開発では、パフォーマンスのボトルネック、ネットワークの問題、Web環境とデスクトップ環境の微妙な違いなど、予期しない課題が明らかになることがよくあります。この記事では、エディタやデプロイメントシナリオ全体でスムーズに動作する信頼性の高いプラグインを作成する際に遭遇する可能性が高い実用的なヒント、実証済みのテクニック、一般的な落とし穴について解説していきます。

Сreating ONLYOFFICE plugins: tips, tricks, and hidden pitfalls

ブリッジとワークフロー

プラグインのUIは独自のウィンドウで実行され、メッセージブリッジを通じてエディタと通信します。このブリッジは、少量のデータと迅速で焦点を絞った編集で最もよく機能します。UI作業(データの取得やリストのフィルタリングなど)をドキュメントの変更(テキストの挿入など)と分離しておくことで、すべてが高速になり、デバッグが容易になり、複数のユーザーが同時に編集する際の動作がより予測可能になります。

ドキュメントの編集は短く焦点を絞ったものにする

理由:エディタコマンドは一度に実行されます。関連する変更をグループ化することで、ちらつきを回避し、ドキュメントの状態を一貫性のあるものに保ちます。

例(ドキュメントエディタ、引用の挿入):

// UI側:コンパクトなデータを準備
const citation = `${title} - ${source}${date ?  ', ' + date : ''}`;
Asc.scope.citation = citation;

// エディタ側:アトミックに実行
window.Asc.plugin.callCommand(function () {
  var doc = Api.GetDocument();
  var p = Api.CreateParagraph();
  p.AddText(Asc.scope.citation);
  doc.InsertContent([p]);
}, true);

ヒント:プラグインに統合する前に、プレイグラウンドでエディタAPIコールをテストして、構文と動作を確認してください。

エディタコマンド内でデータを取得しない

理由:コマンド内でネットワークリクエストを待機すると、エディタがフリーズします。

例(アンチパターンと正しい方法):

    // アンチパターン:callCommand内で非同期(これを避けましょう)
window.Asc.plugin.callCommand(async function () {
  const res = await fetch(url);
  const text = await res.text();
  Api.GetDocument().InsertContent([Api.CreateParagraph().AddText(text)]);
}, true);

// 正しい方法:プラグインウィンドウでフェッチし、その後小さなデータを渡す
const res = await fetch(url);
const text = await res.text().then(t => t.slice(0, 200)); // トリミング
Asc.scope.snippet = text;
window.Asc.plugin.callCommand(function () {
  var p = Api.CreateParagraph();
  p.AddText(Asc.scope.snippet);
  Api.GetDocument().InsertContent([p]);
}, true);

ブリッジを介して少量のデータのみを送信する

理由:ブリッジはJSONのようなペイロード用に最適化されています。大きな文字列やネストされたオブジェクトは遅延を増加させます。

UI作業とドキュメント作業を分離する

理由:フェッチ、解析、フィルタリングはプラグインウィンドウで行い、最終的な挿入のみがエディタコマンドで実行されます。

セキュリティとネットワーク

プラグインは、RSSフィードやAPIなどの外部ソースからコンテンツを取得することがよくあります。適切なチェックがないと、誤って有害なコードをプラグインUIに入れたり、リクエストをブロックするクロスオリジンエラーに遭遇したり、HTTPとHTTPSを混在させた際に静かに失敗したりする可能性があります。シンプルなセキュリティとネットワーク計画により、これらの問題を防ぐことができます。

主要なプラクティスと例

表示する前に信頼できないHTMLをクリーンアップする

理由:フィードの要約やスニペットには、UIを壊したりセキュリティリスクをもたらすHTMLが含まれている可能性があります。

例:

// 迅速なプレーンテキスト抽出
function toPlainText(html) {
  const tmp = document.createElement("div");
  tmp.innerHTML = html;
  return tmp. textContent || "";
}
const safeText = toPlainText(untrustedHtml);

// 制御されたHTMLをレンダリングする場合は、サニタイザーを使用(例:DOMPurify)
// const safeHtml = DOMPurify.sanitize(untrustedHtml);
// container.innerHTML = safeHtml;

ドキュメントにはプレーンテキストの挿入を優先する

根拠:プレーンテキストは予期しないフォーマットの持ち越しを回避し、ブリッジのペイロードを小さく保ちます。リッチフォーマットは、意図的なエディタ側API使用のために予約してください。

HTTPSを使用し、混合コンテンツを避ける

根拠:ブラウザは安全なコンテキストでHTTPリソースをブロックします。エンドポイントがHTTPSでない場合、サイレント障害が一般的です。

クロスオリジンリクエストにはシンプルなプロキシを使用する

根拠:多くのエンドポイントは直接クロスオリジンアクセスを許可していません。小さなプロキシはCORSヘッダーを追加し、出力を正規化します。

例(Node/Expressのスケッチ):

 // 最小限のCORS/正規化プロキシ(サーバー側)
import express from "express";
import fetch from "node-fetch";

const app = express();
app.get("/feed", async (req, res) => {
  try {
    const url = new URL(req.query.src);
    const r = await fetch(url.toString(), { timeout: 8000 });
    const text = await r.text();
    // 必要に応じてサーバー側で正規化されたJSON形状に変換
    res.set("Access-Control-Allow-Origin", "*");
    res.json({ items: normalizeToCommonShape(text) });
  } catch (e) {
    res.set("Access-Control-Allow-Origin", "*");
    res.status(502).json({ error: "Upstream fetch failed" });
  }
});

app.listen(3000);

パフォーマンス、パッケージング、出荷前の準備

プラグインはユーザーがドキュメントを積極的に編集している間に実行されるため、応答性が重要です。優れたパフォーマンス習慣、クリーンなパッケージング、リリース前の徹底的なテストにより、プラグインを高速で予測可能、かつ更新が容易に保つことができます。

パフォーマンスは一貫した習慣に依存します:検索とフィルターをデバウンスし、長いリストを仮想化し、挿入される正確な文字列を事前計算してアクションごとのコストを削減します。クローズ時には、タイマーをクリアし、実行中のリクエストを中止し、リスナーを削除して、セッション間で蓄積する遅いリークを防ぎます。

const controller = new AbortController();
const timer = setInterval(refresh, 300000);

window.Asc.plugin.button = function () {
  controller.abort();
  clearInterval(timer);
  window.Asc.plugin.executeCommand("close", "");
};

主要なプラクティス

  1. 外部CDNに依存するのではなく、JavaScriptとCSSをローカルにバンドルします。
  2. エディタが提供すると想定するのではなく、独自のライトテーマとダークテーマの配色を定義します。
  3. 更新がスムーズに機能するように、バージョン間でプラグイン識別子(GUID)を安定させておきます。
  4. 何が変更されたかを示す明確なバージョン番号(1.0.0、1.1.0、2.0.0)を使用します。
  5. プラグインマネージャーとマーケットプレイスに必要なすべてのアイコンとメタデータを含めます。
  6. 本番環境のようなURLでテストして、壊れた画像やスクリプトパスをキャッチします。

出荷前に、サポートされているエディタ(ドキュメント、スプレッドシート、プレゼンテーション)、環境(Webとデスクトップ)、テーマ(ライトとダーク)、コラボレーション(同時挿入)、ネットワーク条件(オフライン、低速、プロキシダウン)、データセットサイズ(小さいものと非常に大きいもの)、およびインラインスクリプトやスタイルのないより厳格なCSP全体で、コンパクトかつ厳密なパスを実行して、実際のユーザーと実際のネットワークがプラグインをテストする際に動作が一貫性を保つようにします。

まとめ

堅実なプラグインは、シンプルな習慣から生まれます。まずデータを準備し、焦点を絞った1つのステップでドキュメントを変更し、外部コンテンツをサニタイズし、小さなプロキシを通じてネットワークコールをルーティングし、すべてをローカルにパッケージ化して、どこでも同じように機能するようにします。出荷前にエディタ、環境、テーマ、ネットワーク条件全体でテストして、実際のユーザーと実際のネットワークがプラグインを機能させる際に、プラグインが予測どおりに動作するようにしましょう。

ONLYOFFICEの無料アカウントを登録する

オンラインでドキュメント、スプレッドシート、スライド、フォーム、PDFファイルの閲覧、編集、共同作業