Headless Univer

Headless Univer 是 Univer 的無介面內容執行環境,與瀏覽器編輯器共用內容模型、命令、計算和 Facade API。它按需組合外掛,不掛載互動式編輯器 UI,可在 Node.js 中處理內容,也可用於瀏覽器中的無介面任務。可用能力由註冊的產品與功能外掛決定。

在 Node.js 中可建立或載入文件、讀寫段落與文字、修改結構和樣式,並儲存 Univer 快照。表格、清單、分欄、公式與形狀需對應內容外掛;內容修改不等於產生頁面截圖。

以下使用外掛模式。@univerjs/core 與產品內容外掛屬於 Headless 內容層;@univerjs/ui、產品 *-ui 套件和瀏覽器核心預設組合不屬於此設定。範例保留 @univerjs/engine-render 作為共用相依項目,不掛載 Canvas 或編輯器。分類與例外見 Headless 套件邊界。

本機快照操作不需協同服務。協同範例另需用戶端、伺服器與身分驗證;Office 轉換和截圖分別需 Server SDK 與渲染執行環境。僅匯入 /facade 不會註冊功能外掛,也不會讓 UI API 變成 Headless API。

安裝

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.ZH_TW,  locales: {    [LocaleType.ZH_TW]: {},  },})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、服務位址和 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.ZH_TW,    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.