Headless Univer

Headless Univer は、対話型エディター UI を持たない Univer の内容ランタイムです。ブラウザー版と内容モデル、コマンド、計算、Facade API を共有します。Node.js での内容処理やブラウザー内の UI を使わない処理に利用でき、登録する製品・機能プラグインによって利用可能な機能が決まります。

Node.js で文書を作成・読み込みし、段落、テキスト、構造、書式を編集して Univer スナップショットを保存できます。表、リスト、段組み、数式、図形には対応する内容プラグインが必要です。内容の変更だけではページ画像は生成されません。

以下はプラグインモードを使います。@univerjs/core と製品の内容プラグインは Headless 層に含まれますが、@univerjs/ui、製品の *-ui、標準ブラウザープリセットは含めません。@univerjs/engine-render は共有依存として登録し、Canvas やエディターはマウントしません。詳細はパッケージの境界を参照してください。

ローカルスナップショット処理に共同編集は不要です。共同編集サンプルにはクライアント、サーバー、認証が必要です。Office 変換と画像出力にはそれぞれ Server SDK と描画ランタイムを接続します。/facade の読み込みだけでは機能プラグインの登録や UI API の Headless 化は行われません。

インストール

Shell
pnpm add @univerjs/core @univerjs/engine-render @univerjs/engine-formula @univerjs/docs

使い方

TypeScript
import { LocaleType, Univer } from '@univerjs/core'import { FUniver } from '@univerjs/core/facade'import { UniverDocsPlugin } from '@univerjs/docs'import { UniverFormulaEnginePlugin } from '@univerjs/engine-formula'import { UniverRenderEnginePlugin } from '@univerjs/engine-render'import '@univerjs/docs/facade'const univer = new Univer({  locale: LocaleType.JA_JP,  locales: {    [LocaleType.JA_JP]: {},  },})univer.registerPlugin(UniverRenderEnginePlugin)univer.registerPlugin(UniverFormulaEnginePlugin)univer.registerPlugin(UniverDocsPlugin)const univerAPI = FUniver.newAPI(univer)univerAPI.createDocument({})

Node.js 環境での共同編集の例

Node.js を共同編集クライアントとして使用し、サーバー上の既存のドキュメントを読み込み、Facade API で内容を変更して、同じドキュメントを開いている他のクライアントに同期できます。実行前に、共同編集サービス、クライアントライセンス、アクセス可能なドキュメント ID を用意してください。

サンプルファイル

次の構成でファイルを配置します。

text
src/docs/node/├── main.ts└── univer.ts
  • univer.ts:Univer を作成し、ドキュメント機能のプラグイン、Facade 拡張、Node.js 共同編集クライアントを登録します。
  • main.ts:共同編集ドキュメントを読み込み、段落、テキスト、ヘッダーとフッター、コールアウト、コードブロック、引用ブロック、リスト、図形、表、段組みの API を順に実行します。

univer.ts の your-license、サーバー URL、Cookie と、main.ts のドキュメント ID を置き換えてください。

TypeScript
import { UniverCollaborationPlugin } from '@univerjs-pro/collaboration'import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'import {  NodeCollaborationSocketService,  UniverCollaborationClientNodePlugin,} from '@univerjs-pro/collaboration-client-node'import { UniverDocsCalloutPlugin } from '@univerjs-pro/docs-callout'import { UniverDocsCodePlugin } from '@univerjs-pro/docs-code'import { UniverDocsColumnPlugin } from '@univerjs-pro/docs-column'import { UniverDocsLatexPlugin } from '@univerjs-pro/docs-latex'import { UniverDocsListPlugin } from '@univerjs-pro/docs-list'import { UniverDocsQuotePlugin } from '@univerjs-pro/docs-quote'import { UniverDocsReferencePlugin } from '@univerjs-pro/docs-reference'import { UniverDocsShapePlugin } from '@univerjs-pro/docs-shape'import { UniverDocsTablePlugin } from '@univerjs-pro/docs-table'import { UniverLicensePlugin } from '@univerjs-pro/license'import {  IAuthzIoService,  IImageIoService,  IMentionIOService,  IUndoRedoService,  LocaleType,  Univer,} from '@univerjs/core'import { UniverDocsPlugin } from '@univerjs/docs'import { UniverDocsDrawingPlugin } from '@univerjs/docs-drawing'import { UniverDocsHyperLinkPlugin } from '@univerjs/docs-hyper-link'import { UniverDrawingPlugin } from '@univerjs/drawing'import { UniverRenderEnginePlugin } from '@univerjs/engine-render'import { UniverNetworkPlugin } from '@univerjs/network'import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'import '@univerjs/docs/facade'import '@univerjs/docs-drawing/facade'import '@univerjs-pro/docs-shape/facade'import '@univerjs-pro/docs-callout/facade'import '@univerjs-pro/docs-reference/facade'import '@univerjs-pro/docs-code/facade'import '@univerjs-pro/docs-list/facade'import '@univerjs-pro/docs-quote/facade'import '@univerjs-pro/docs-table/facade'import '@univerjs-pro/docs-column/facade'import '@univerjs-pro/docs-latex/facade'import '@univerjs-pro/collaboration-client/facade'export function createUniverOnNode(): Univer {  const univer = new Univer({    locale: LocaleType.JA_JP,    locales: {},    override: [      [IAuthzIoService, null],      [IUndoRedoService, null],      [IMentionIOService, null],    ],  })  univer.registerPlugin(UniverLicensePlugin, {    license: 'your-license',  })  univer.registerPlugin(UniverRenderEnginePlugin)  univer.registerPlugin(UniverThreadCommentPlugin)  univer.registerPlugin(UniverDrawingPlugin, {    override: [[IImageIoService, null]],  })  univer.registerPlugin(UniverDocsPlugin)  univer.registerPlugin(UniverDocsDrawingPlugin)  univer.registerPlugin(UniverDocsHyperLinkPlugin)  univer.registerPlugin(UniverDocsReferencePlugin)  univer.registerPlugin(UniverDocsCalloutPlugin)  univer.registerPlugin(UniverDocsCodePlugin)  univer.registerPlugin(UniverDocsListPlugin)  univer.registerPlugin(UniverDocsQuotePlugin)  univer.registerPlugin(UniverDocsShapePlugin)  univer.registerPlugin(UniverDocsTablePlugin)  univer.registerPlugin(UniverDocsColumnPlugin)  univer.registerPlugin(UniverDocsLatexPlugin)  registerCollaborationPlugins(univer)  return univer}function registerCollaborationPlugins(univer: Univer): void {  const serverUrl = 'https://your-univer-server.example.com'  univer.registerPlugin(UniverNetworkPlugin)  univer.registerPlugin(UniverCollaborationPlugin)  univer.registerPlugin(UniverCollaborationClientPlugin, {    socketService: NodeCollaborationSocketService,    enableOfflineEditing: false,    enableSingleActiveInstanceLock: false,    snapshotServerUrl: `${serverUrl}/universer-api/snapshot`,    collabSubmitChangesetUrl: `${serverUrl}/universer-api/comb`,    collabWebSocketUrl: `${serverUrl}/universer-api/comb/connect`,    wsSessionTicketUrl: `${serverUrl}/universer-api/user/session-ticket`,    uploadFileServerUrl: `${serverUrl}/universer-api/stream/file/upload`,    signUrlServerUrl: `${serverUrl}/universer-api/file/{fileID}/sign-url`,    downloadEndpointUrl: serverUrl,    authzUrl: `${serverUrl}/universer-api/authz`,    sendChangesetTimeout: 200,    retryConnectingInterval: 1000,    customHeaders: {      // 例:Univer サーバーが Cookie 認証を必要とする場合、ここで 'cookie' ヘッダーを設定できます。      cookie: 'your-cookie',      // ... その他のヘッダー    },  })  univer.registerPlugin(UniverCollaborationClientNodePlugin)}

実行時の注意点

loadDocAsync() はサーバー上の既存ドキュメントを読み込むため、createDocument() を呼び出す必要はありません。共同編集サービスは customHeaders の Cookie などの認証情報からユーザーを識別し、権限を確認します。接続の memberID はサーバーから返されます。

この例ではブラウザのオフラインキャッシュと複数タブ間のインスタンスロックを無効にしているため、アカウントごとのキャッシュ分離を目的とした setCurrentUser() の呼び出しは不要です。後からコメントなどローカルの現在のユーザーに依存する機能を使用する場合は、UserManagerService で業務ユーザーを設定できます。これはサーバー認証の代わりにはなりません。

ヘッダーとフッターのサンプルはページ分割されたドキュメント、段組みのサンプルはモダンドキュメントでのみ使用できます。サンプルは isModern() でドキュメントのモードを判定し、対応していない操作をスキップします。

サンプルは既存ドキュメントに内容を挿入するため、テスト用ドキュメントで実行することをお勧めします。 サンプルは実行後も共同編集接続を維持します。ブラウザで同じドキュメントを開くと変更を確認できます。flush() はキュー内の変更に対するサーバーの確認を待ちます。単発のスクリプトにする場合は、すべての非同期処理と同期が完了してから univer.dispose() でインスタンスを解放してください。

このガイドはいかがですか?

© 2026 DreamNum Co., Ltd.