Headless Univer

Headless Univer es el runtime de contenido de Univer sin interfaz de edición interactiva. Comparte modelos de contenido, comandos, cálculos y API Facade con el editor web. Puede procesar contenido en Node.js o ejecutar tareas sin interfaz en un navegador. Las capacidades disponibles dependen de los plugins de producto y función registrados.

En Node.js puede crear o cargar libros, modificar celdas, formatos, filas y columnas, calcular fórmulas y guardar instantáneas Univer. Filtros, ordenación, validación, tablas dinámicas y gráficos necesitan sus plugins de contenido. Cambiar datos de un gráfico no lo renderiza.

El ejemplo usa el modo plugin. @univerjs/core y los plugins de contenido del producto pertenecen a Headless; @univerjs/ui, los paquetes de producto *-ui y los presets básicos del navegador quedan fuera de esta configuración. @univerjs/engine-render se mantiene como dependencia compartida sin montar Canvas ni editor. Consulte los límites de paquetes Headless.

Las instantáneas locales no necesitan colaboración. El ejemplo colaborativo requiere además cliente, servidor y autenticación. La conversión Office y las capturas necesitan Server SDK y un runtime de renderizado, respectivamente. Importar /facade no registra los plugins ni convierte las API UI en API Headless.

Instalación

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

Uso

TypeScript
import { LocaleType, mergeLocales, 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 { UniverSheetsPlugin } from '@univerjs/sheets'import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'import SheetsEsES from '@univerjs/sheets/locale/es-ES'import '@univerjs/engine-formula/facade'import '@univerjs/sheets/facade'import '@univerjs/sheets-formula/facade'import '@univerjs/sheets-numfmt/facade'const univer = new Univer({  locale: LocaleType.ES_ES,  locales: {    [LocaleType.ES_ES]: mergeLocales(      SheetsEsES,    ),  },})univer.registerPlugin(UniverRenderEnginePlugin)univer.registerPlugin(UniverFormulaEnginePlugin)univer.registerPlugin(UniverDocsPlugin)univer.registerPlugin(UniverSheetsPlugin)univer.registerPlugin(UniverSheetsFormulaPlugin)univer.registerPlugin(UniverSheetsNumfmtPlugin)const univerAPI = FUniver.newAPI(univer)univerAPI.createWorkbook({})

Ejemplo de colaboración en Node.js

Node.js puede actuar como cliente de colaboración: cargar un libro existente del servidor, modificar su contenido mediante la API de Facade y sincronizar los cambios con otros clientes que tengan abierto el mismo documento. Antes de ejecutarlo, prepara un servicio de colaboración, una licencia de cliente y un ID de documento accesible.

Archivos del ejemplo

Organiza los archivos con esta estructura:

text
src/sheets/node/├── main.ts├── univer.ts└── worker.ts
  • univer.ts: crea Univer y registra los plugins de funciones, el cliente de colaboración y el plugin RPC opcional del proceso principal.
  • worker.ts: registra el motor de fórmulas del lado de cálculo y los plugins de fórmulas remotas, filtros y tablas dinámicas, y se comunica con el proceso principal mediante RPC.
  • main.ts: carga el documento colaborativo y muestra las API de permisos, operaciones básicas de hojas, formato condicional, validación de datos, tablas, tablas dinámicas, minigráficos, imágenes, gráficos, formas, agrupación e hipervínculos.

Sustituye your-license en ambos archivos por la misma licencia y adapta la URL del servidor, la Cookie, el ID del documento y los ID de usuario. El ejemplo de permisos de main.ts también configura colaboradores y rangos protegidos; usa usuarios reales de tu aplicación y una identidad con los permisos de administración necesarios.

TypeScript
import { UniverCollaborationPlugin } from '@univerjs-pro/collaboration'import { UniverCollaborationClientPlugin } from '@univerjs-pro/collaboration-client'import {  NodeCollaborationSocketService,  UniverCollaborationClientNodePlugin,} from '@univerjs-pro/collaboration-client-node'import { UniverProFormulaEnginePlugin } from '@univerjs-pro/engine-formula'import { UniverLicensePlugin } from '@univerjs-pro/license'import { UniverSheetsChartPlugin } from '@univerjs-pro/sheets-chart'import { UniverSheetsOutlinePlugin } from '@univerjs-pro/sheets-outline'import { UniverSheetsPivotTablePlugin } from '@univerjs-pro/sheets-pivot'import { UniverSheetsShapePlugin } from '@univerjs-pro/sheets-shape'import { UniverSheetSparklinePlugin } from '@univerjs-pro/sheets-sparkline'import { IAuthzIoService, IImageIoService, IUndoRedoService, LocaleType, Univer } from '@univerjs/core'import { UniverDataValidationPlugin } from '@univerjs/data-validation'import { UniverDocsPlugin } from '@univerjs/docs'import { UniverDocsDrawingPlugin } from '@univerjs/docs-drawing'import { UniverDrawingPlugin } from '@univerjs/drawing'import { UniverRenderEnginePlugin } from '@univerjs/engine-render'import { UniverNetworkPlugin } from '@univerjs/network'import { UniverRPCNodeMainPlugin } from '@univerjs/rpc-node'import { UniverSheetsPlugin } from '@univerjs/sheets'import { UniverSheetsConditionalFormattingPlugin } from '@univerjs/sheets-conditional-formatting'import { UniverSheetsDataValidationPlugin } from '@univerjs/sheets-data-validation'import { UniverSheetsDrawingPlugin } from '@univerjs/sheets-drawing'import { UniverSheetsFilterPlugin } from '@univerjs/sheets-filter'import { UniverSheetsFormulaPlugin } from '@univerjs/sheets-formula'import { UniverSheetsHyperLinkPlugin } from '@univerjs/sheets-hyper-link'import { UniverSheetsNotePlugin } from '@univerjs/sheets-note'import { UniverSheetsNumfmtPlugin } from '@univerjs/sheets-numfmt'import { UniverSheetsSortPlugin } from '@univerjs/sheets-sort'import { UniverSheetsTablePlugin } from '@univerjs/sheets-table'import { UniverThreadCommentPlugin } from '@univerjs/thread-comment'import path from 'node:path'// Las API de Facade usadas aquí forman parte de packages/facade/src/apis/everything.ts// Algunos plugins tienen implementaciones incompletas, por lo que sus API no se incluyen aquí.import '@univerjs/engine-formula/facade'import '@univerjs/sheets/facade'import '@univerjs/sheets-formula/facade'import '@univerjs/sheets-numfmt/facade'import '@univerjs/sheets-conditional-formatting/facade'import '@univerjs/sheets-data-validation/facade'import '@univerjs/sheets-filter/facade'import '@univerjs/sheets-hyper-link/facade'import '@univerjs/sheets-note/facade'import '@univerjs/sheets-table/facade'import '@univerjs/sheets-drawing/facade'import '@univerjs/sheets-thread-comment/facade'import '@univerjs-pro/engine-shape/facade'import '@univerjs-pro/sheets-pivot/facade'import '@univerjs-pro/sheets-sparkline/facade'import '@univerjs-pro/sheets-chart/facade'import '@univerjs-pro/sheets-shape/facade'import '@univerjs-pro/sheets-outline/facade'import '@univerjs-pro/collaboration-client/facade'export interface ICreateUniverOnNodeOptions {  useComputingWorker?: boolean}export function createUniverOnNode(options: ICreateUniverOnNodeOptions = {}): Univer {  const { useComputingWorker = false } = options  const univer = new Univer({    locale: LocaleType.ES_ES,    locales: {},    override: [      [IAuthzIoService, null],      [IUndoRedoService, null],    ],  })  univer.registerPlugin(UniverLicensePlugin, {    license: 'your-license',  })  registerBasicPlugins(univer, useComputingWorker)  registerSharedPlugins(univer)  if (useComputingWorker) {    registerRPCPlugin(univer)  }  registerDocPlugins(univer)  registerSheetPlugins(univer, useComputingWorker)  registerCollaborationPlugins(univer)  return univer}function registerBasicPlugins(univer: Univer, useComputingWorker: boolean): void {  univer.registerPlugin(UniverProFormulaEnginePlugin, { notExecuteFormula: useComputingWorker })}function registerSharedPlugins(univer: Univer): void {  univer.registerPlugin(UniverRenderEnginePlugin)  univer.registerPlugin(UniverThreadCommentPlugin)  univer.registerPlugin(UniverDrawingPlugin, {    override: [[IImageIoService, null]],  })}function registerDocPlugins(univer: Univer): void {  univer.registerPlugin(UniverDocsPlugin)  univer.registerPlugin(UniverDocsDrawingPlugin)}function registerSheetPlugins(univer: Univer, useComputingWorker: boolean): void {  univer.registerPlugin(UniverSheetsPlugin, { notExecuteFormula: useComputingWorker })  univer.registerPlugin(UniverSheetsFormulaPlugin, { notExecuteFormula: useComputingWorker })  univer.registerPlugin(UniverSheetsNumfmtPlugin)  univer.registerPlugin(UniverSheetsConditionalFormattingPlugin)  univer.registerPlugin(UniverDataValidationPlugin)  univer.registerPlugin(UniverSheetsDataValidationPlugin)  univer.registerPlugin(UniverSheetsFilterPlugin)  univer.registerPlugin(UniverSheetsHyperLinkPlugin)  univer.registerPlugin(UniverSheetsNotePlugin)  univer.registerPlugin(UniverSheetsDrawingPlugin)  univer.registerPlugin(UniverSheetsSortPlugin)  univer.registerPlugin(UniverSheetsTablePlugin)  univer.registerPlugin(UniverSheetsChartPlugin)  univer.registerPlugin(UniverSheetsShapePlugin)  univer.registerPlugin(UniverSheetsPivotTablePlugin, {    notExecuteFormula: useComputingWorker ? true : undefined,  })  univer.registerPlugin(UniverSheetSparklinePlugin)  univer.registerPlugin(UniverSheetsOutlinePlugin)}function registerRPCPlugin(univer: Univer): void {  // Define la ruta del worker según la ubicación real del archivo compilado.  const childPath = path.join(__dirname, 'worker.js')  univer.registerPlugin(UniverRPCNodeMainPlugin, { workerSrc: childPath })}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: {      // Ejemplo: si tu servidor Univer requiere autenticación mediante cookies, puedes definir aquí la cabecera 'cookie'.      cookie: 'your-cookie',      // ... más cabeceras    },  })  univer.registerPlugin(UniverCollaborationClientNodePlugin)}

Activar el worker de cálculo

createUniverOnNode() usa useComputingWorker: false de forma predeterminada y calcula las fórmulas en el proceso actual. El archivo main.ts anterior pasa explícitamente useComputingWorker: true para activar el worker de cálculo:

  1. En el proceso principal, UniverProFormulaEnginePlugin, UniverSheetsPlugin, UniverSheetsFormulaPlugin y UniverSheetsPivotTablePlugin establecen notExecuteFormula: true para delegar el cálculo al proceso hijo mediante RPC.
  2. UniverRPCNodeMainPlugin inicia el archivo worker.js compilado indicado por workerSrc.
  3. El proceso hijo recibe los datos y realiza los cálculos mediante UniverRPCNodeWorkerPlugin y UniverRemoteSheetsFormulaPlugin.

UniverSheetsPivotTablePlugin distingue tres modos: true en el proceso principal con worker, false en el worker y la opción omitida o con valor undefined sin worker, para registrar tanto los servicios de tablas dinámicas como la lógica de cálculo en el proceso actual. Por eso el proceso principal usa useComputingWorker ? true : undefined en lugar de pasar useComputingWorker directamente.

Node.js inicia este worker con child_process.fork(). Usa la herramienta de compilación de tu proyecto para compilar main.ts y worker.ts como puntos de entrada independientes y configura workerSrc para que apunte al archivo worker compilado. El ejemplo supone que worker.js está en el mismo directorio que el resultado de la entrada principal; adapta la ruta, la extensión y el formato de módulo a tu compilación. El ejemplo usa __dirname de CommonJS para localizar el archivo; los proyectos ESM deben usar el método de resolución correspondiente.

Notas de ejecución

loadSheetAsync() carga un documento existente del servidor; no necesitas llamar a createWorkbook(). El servicio de colaboración identifica al usuario y comprueba sus permisos mediante la información de autenticación, como la Cookie incluida en customHeaders. El servidor devuelve el memberID de la conexión.

Este ejemplo desactiva la caché sin conexión del navegador y el bloqueo de instancia entre pestañas, por lo que no es necesario llamar a setCurrentUser() para aislar la caché por cuenta. Si más adelante usas funciones como comentarios, que dependen del usuario actual local, puedes establecer el usuario de la aplicación mediante UserManagerService; esto no sustituye la autenticación del servidor.

El ejemplo mantiene la conexión colaborativa después de ejecutarse. Abre el mismo documento en un navegador para ver los cambios. flush() espera la confirmación del servidor para los cambios pendientes. Si lo conviertes en un script de una sola ejecución, llama a univer.dispose() cuando hayan terminado todas las operaciones asíncronas y la sincronización.

¿Cómo es esta guía?

© 2026 DreamNum Co., Ltd.