Creación de plugins para ONLYOFFICE: consejos, trucos y trampas ocultas

21 enero 2026Por Dea

Crear plugins para los editores ONLYOFFICE puede ser sencillo, pero el desarrollo en escenarios reales suele revelar desafíos inesperados: cuellos de botella de rendimiento, peculiaridades de red y sutiles diferencias entre los entornos web y de escritorio. Este artículo cubre consejos prácticos, técnicas probadas y errores comunes que probablemente encontrarás al crear plugins fiables que funcionen sin problemas en distintos editores y escenarios de despliegue.

Creación de plugins para ONLYOFFICE: consejos, trucos y trampas ocultas

Puente y flujo de trabajo

La interfaz de tu plugin se ejecuta en su propia ventana y se comunica con el editor a través de un puente de mensajes. Este puente funciona mejor con pequeñas cantidades de datos y ediciones rápidas y bien definidas. Mantener el trabajo de la UI (como obtener datos o filtrar listas) separado de los cambios en el documento (como insertar texto) hace que todo sea más rápido, más fácil de depurar y más predecible cuando varios usuarios editan al mismo tiempo.

Mantén las ediciones del documento cortas y enfocadas

Por qué: Los comandos del editor se ejecutan de una sola vez; agrupar cambios relacionados evita parpadeos y mantiene el estado del documento consistente.

Ejemplo (Editor de documentos, insertar una cita):

// UI side: prepare compact data
const citation = `${title} - ${source}${date ?  ', ' + date : ''}`;
Asc.scope.citation = citation;

// Editor side: run atomically
window.Asc.plugin.callCommand(function () {
  var doc = Api.GetDocument();
  var p = Api.CreateParagraph();
  p.AddText(Asc.scope.citation);
  doc.InsertContent([p]);
}, true);

Consejo: Prueba las llamadas a la API del editor en el playground para verificar la sintaxis y el comportamiento antes de integrarlas en el plugin.

No obtengas datos dentro de los comandos del editor

Por qué: Esperar solicitudes de red dentro de un comando congela el editor.

Ejemplo (antipatrón vs. correcto):

    // Anti-pattern: async in callCommand (don't do this)
window.Asc.plugin.callCommand(async function () {
  const res = await fetch(url);
  const text = await res.text();
  Api.GetDocument().InsertContent([Api.CreateParagraph().AddText(text)]);
}, true);

// Correct: fetch in the plugin window, then pass small data
const res = await fetch(url);
const text = await res.text().then(t => t.slice(0, 200)); // trim
Asc.scope.snippet = text;
window.Asc.plugin.callCommand(function () {
  var p = Api.CreateParagraph();
  p.AddText(Asc.scope.snippet);
  Api.GetDocument().InsertContent([p]);
}, true);

Envía solo pequeñas cantidades de datos a través del puente

Por qué: El puente está optimizado para cargas útiles tipo JSON; cadenas grandes u objetos muy anidados incrementan la latencia.

Mantén separado el trabajo de la UI y el trabajo del documento

Por qué: La obtención, el análisis y el filtrado pertenecen a la ventana del plugin; solo la inserción final debe ocurrir dentro del comando del editor.

Seguridad y redes

Los plugins a menudo consumen contenido de fuentes externas como feeds RSS o APIs. Sin las comprobaciones adecuadas, puedes permitir accidentalmente la entrada de código dañino en la UI del plugin, encontrarte con errores de origen cruzado que bloquean solicitudes o fallos silenciosos al mezclar HTTP y HTTPS. Un plan simple de seguridad y redes evita estos dolores de cabeza.

Prácticas clave, con ejemplos

Limpia el HTML no confiable antes de mostrarlo

Por qué: Los resúmenes de feeds o fragmentos pueden contener HTML que rompa tu interfaz o introduzca riesgos de seguridad.

Ejemplo:

// Quick plain-text extraction
function toPlainText(html) {
  const tmp = document.createElement("div");
  tmp.innerHTML = html;
  return tmp. textContent || "";
}
const safeText = toPlainText(untrustedHtml);

// If rendering controlled HTML, use a sanitizer (e. g., DOMPurify)
// const safeHtml = DOMPurify.sanitize(untrustedHtml);
// container.innerHTML = safeHtml;

Prefiere insertar texto plano en los documentos

Justificación: El texto plano evita arrastres inesperados de formato y mantiene pequeñas las cargas de datos del puente; reserva el formato enriquecido para un uso deliberado de la API del editor del lado del editor.

Usa HTTPS y evita contenido mixto

Justificación: Los navegadores bloquean recursos HTTP en contextos seguros; los fallos silenciosos son comunes cuando los endpoints no usan HTTPS.

Usa un proxy simple para solicitudes de origen cruzado

Example (Node/Express sketch):Justificación: Muchos endpoints no permiten acceso directo entre orígenes; un pequeño proxy añade cabeceras CORS y normaliza la salida.

Ejemplo (boceto con Node/Express):

 // Minimal CORS/normalize proxy (server-side)
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();
    // Convert to normalized JSON shape server-side as needed
    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);

Rendimiento, empaquetado y preparación antes del lanzamiento

Los plugins se ejecutan mientras los usuarios editan activamente documentos, por lo que la capacidad de respuesta es crucial. Buenos hábitos de rendimiento, un empaquetado limpio y pruebas exhaustivas antes del lanzamiento mantienen tu plugin rápido, predecible y fácil de actualizar.

El rendimiento depende de hábitos consistentes: aplica debounce a búsquedas y filtros, virtualiza listas largas y pre-calcula las cadenas exactas que se insertarán para reducir el coste por acción. Al cerrar, limpia temporizadores, cancela solicitudes en curso y elimina listeners para evitar fugas lentas que se acumulan a lo largo de las sesiones.

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

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

Prácticas clave

  1. Empaqueta tu JavaScript y CSS localmente en lugar de depender de CDNs externos.
  2. Define tus propios esquemas de color claro y oscuro en vez de asumir que el editor los proporcionará.
  3. Mantén estable el identificador (GUID) del plugin entre versiones para que las actualizaciones funcionen sin problemas.
  4. Usa números de versión claros (1.0.0, 1.1.0, 2.0.0) que indiquen qué cambió.
  5. Incluye todos los iconos y metadatos requeridos para el Administrador de Plugins y el Marketplace.
  6. Prueba con URLs similares a producción para detectar rutas rotas de imágenes o scripts.

Antes de publicar, realiza una revisión compacta pero estricta en editores compatibles (documentos, hojas de cálculo, presentaciones), entornos (web y escritorio), temas (claro y oscuro), colaboración (inserciones simultáneas), condiciones de red (sin conexión, lenta, proxy caído), tamaños de datos (muy pequeños y muy grandes), y una CSP más estricta, sin scripts ni estilos en línea, para que el comportamiento sea consistente cuando usuarios reales y redes reales pongan a prueba el plugin.

Conclusión

Los plugins sólidos nacen de hábitos sencillos: preparar los datos con antelación, realizar los cambios en el documento en un único paso bien definido, sanear el contenido externo, canalizar las llamadas de red a través de un pequeño proxy y empaquetar todo localmente para que funcione igual en todas partes. Prueba en distintos editores, entornos, temas y condiciones de red antes de lanzar, para que tu plugin se comporte de forma predecible cuando usuarios reales y redes reales lo utilicen.

Crea tu cuenta gratuita de ONLYOFFICE

Visualiza, edita y colabora en documentos, hojas, diapositivas, formularios y archivos PDF en línea.