Creación de plugins para ONLYOFFICE: consejos, trucos y trampas ocultas
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.

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
- Empaqueta tu JavaScript y CSS localmente en lugar de depender de CDNs externos.
- Define tus propios esquemas de color claro y oscuro en vez de asumir que el editor los proporcionará.
- Mantén estable el identificador (GUID) del plugin entre versiones para que las actualizaciones funcionen sin problemas.
- Usa números de versión claros (1.0.0, 1.1.0, 2.0.0) que indiquen qué cambió.
- Incluye todos los iconos y metadatos requeridos para el Administrador de Plugins y el Marketplace.
- 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.


