Optimizar worker-threads Gutenberg con la version 1.13.0

En pocas palabras: @wordpress/worker-threads 1.13.0, publicado el 22 de julio de 2026 junto a Gutenberg 23.6, ahora rechaza automáticamente las llamadas RPC pendientes cuando un worker se cierra. Antes esas promesas quedaban colgadas para siempre y trababan el editor; con este cambio fallan al instante.

@wordpress/worker-threads 1.13.0 salió junto a Gutenberg 23.6 el 22 de julio de 2026 y suma el rechazo automático de las llamadas RPC pendientes cuando un worker se cierra. Si venías a optimizar worker-threads Gutenberg, este cambio evita que el editor quede colgado esperando respuestas que nunca van a llegar.

@wordpress/worker-threads es un paquete npm del block editor de WordPress que envuelve los web workers del navegador con un sistema RPC type-safe. Te deja mover cálculos pesados a un hilo aparte con expose() y wrap(), sin escribir postMessage a mano. Lo mantiene el equipo de Gutenberg y se publica con el resto de los paquetes @wordpress en cada release.

En 30 segundos

  • Qué es: un wrapper RPC type-safe sobre los web workers del navegador, parte del block editor de WordPress.
  • Novedad 1.13.0 (22/07/2026): las llamadas RPC que quedan pendientes se rechazan cuando el worker termina, en vez de colgarse para siempre.
  • Para qué sirve: sacar del main thread el trabajo pesado (parseos grandes, validaciones, criptografía) para que el editor no se congele.
  • API mínima: expose() del lado del worker, wrap() del lado del editor. Las llamadas devuelven promesas.
  • Cuándo NO lo necesitás: si tu bloque hace cálculos livianos, meter un worker es complejidad al pedo.

¿Por qué el editor de bloques se traba con tareas pesadas?

Porque JavaScript en el navegador corre en un solo hilo, el main thread, y ahí conviven el render de Gutenberg, tus eventos de teclado y cualquier cálculo que dispare tu bloque. Si una tarea tarda 300 ms, esos 300 ms el editor no responde.

Ponele que armás un bloque que valida un CSV de 5.000 filas antes de guardarlo. Mientras el bucle recorre las filas, el cursor se traba, el autosave se atrasa y el usuario piensa que se colgó todo. Cualquiera que haya escrito un bloque con lógica de verdad se topó con este freeze. Te puede servir nuestra cobertura de contribuir al desarrollo de WordPress.

Un web worker mueve ese trabajo a un hilo aparte. El problema es que la API nativa (postMessage más listeners de message) es engorrosa: mandás mensajes sueltos, los correlacionás vos, y no hay tipos. Ahí entra este paquete.

¿Cómo optimizar worker-threads Gutenberg contra el bloqueo del main thread?

El paquete te da un canal RPC en vez de mensajes crudos: llamás a una función del worker como si fuera local y te devuelve una promesa. Según la documentación oficial del block editor, la idea es exponer funciones desde el worker y consumirlas desde el hilo principal sin tocar postMessage.

Tres cosas que resuelve por vos:

  • RPC type-safe: llamás worker.calcular(datos) y recibís una promesa tipada, sin armar el ida y vuelta de mensajes a mano.
  • Transferencia automática: los objetos transferibles (como ArrayBuffer) se mueven sin copiarse, así no duplicás memoria al pasar payloads grandes.
  • Propagación de errores: si el worker tira una excepción, la promesa del lado del editor se rechaza con ese error, en vez de morir en silencio.

Comparado con el postMessage pelado, la diferencia es la de escribir una función y llamarla, contra montar un protocolo de mensajería propio cada vez. Menos código, menos bugs de correlación.

¿Cuándo necesitás de verdad un web worker en un bloque?

Cuando el cálculo bloquea el hilo lo suficiente como para que se note. Regla práctica: si una operación pasa de ~50 ms de forma sostenida y corre en respuesta a una interacción, es candidata a worker. Casos típicos donde zafa mandarlo a otro hilo:

  • Validación de datos grandes: parsear y chequear archivos CSV o JSON de miles de filas antes de renderizar.
  • Criptografía en cliente: hashing o cifrado de contenido sin frenar el tipeo.
  • Procesamiento de imágenes: filtros, redimensionado o análisis de píxeles sobre un canvas.
  • Diffs y transformaciones pesadas: comparar dos versiones largas de contenido o convertir formatos.

¿Y si tu bloque solo formatea texto o pinta un par de campos? No metas worker. La comunicación entre hilos tiene su propio costo (serialización, latencia del mensaje) y para tareas chicas termina siendo más lento y más difícil de mantener. En crear landing pages de alto rendimiento profundizamos sobre esto.

¿Cómo implementar @wordpress/worker-threads en tus bloques?

Se instala como cualquier paquete del ecosistema: npm install @wordpress/worker-threads. Del lado del worker exponés funciones con expose(); del lado del editor las envolvés con wrap() y las llamás con await. Un ejemplo mínimo, un worker que suma:

// suma.worker.js
import { expose } from '@wordpress/worker-threads';

expose( {
 sumar( a, b ) {
 return a + b;
 },
} );

// edit.js (dentro de tu bloque)
import { wrap } from '@wordpress/worker-threads';

const worker = wrap( new Worker(
 new URL( './suma.worker.js', import.meta.url ),
 { type: 'module' }
) );

const total = await worker.sumar( 2, 3 ); // 5, sin bloquear el editor

Fijate que worker.sumar() devuelve una promesa aunque la función original sea sincrónica. Eso es esperado: la respuesta viaja entre hilos, así que siempre la esperás con await. Si sumar tirara un error, el await lo recibe como rechazo y lo podés atrapar con try/catch.

¿Qué cambió en la versión 1.13.0?

La 1.13.0, publicada con Gutenberg 23.6 el 22 de julio de 2026, agrega el rechazo de las llamadas RPC que quedan pendientes cuando el worker se termina. Antes, si cerrabas o reiniciabas el worker con una llamada a mitad de camino, esa promesa quedaba colgada sin resolverse nunca.

¿Por qué importa? Porque una promesa que nunca se resuelve es una fuga silenciosa. El código que la esperaba se queda ahí, esperando, y si tenías un spinner atado a esa promesa, el spinner gira para siempre. Con el cambio, al terminar el worker esas llamadas se rechazan de una, así tu catch se dispara y podés limpiar el estado, reintentar o avisarle al usuario.

Es una mejora de fiabilidad, no una feature nueva de API. No trae breaking changes visibles: si ya manejabas errores en tus llamadas, este comportamiento encaja solo. Tomalo con pinzas igual y revisá tus catch, porque ahora vas a recibir rechazos en escenarios de terminación que antes se tragaban en silencio. Sobre eso hablamos en probar cambios en un entorno seguro.

¿Qué alternativas hay y cuándo conviene cada una?

No todo se resuelve con un worker. A veces te alcanza con partir el bundle o diferir la carga. Esta tabla ordena las opciones por lo que resuelven de verdad:

TécnicaQué resuelveComplejidadCuándo elegirla
@wordpress/worker-threadsBloqueo del main thread por cálculo pesadoMediaTareas CPU-intensivas dentro de un bloque
postMessage nativoIgual que arriba, pero a manoAltaCasi nunca: el paquete lo hace mejor
SharedArrayBufferMemoria compartida entre hilos sin copiarAltaDatos enormes compartidos, requiere headers COOP/COEP
Code splitting / lazy loadingPeso inicial del bundle del editorBajaEl bloque tarda en cargar, no en calcular
Service WorkerCacheo y red offlineMediaInterceptar peticiones, no aliviar el CPU

Ojo con confundir problemas: si tu bloque tarda en aparecer, eso es carga de bundle y se arregla con code splitting, no con workers. Los workers atacan el cálculo, no el peso del JavaScript inicial.

Qué está confirmado y qué no

  • Confirmado: la 1.13.0 rechaza las llamadas RPC pendientes al terminar el worker, según las notas de la release en GitHub.
  • Confirmado: el paquete se distribuye con cada versión de Gutenberg y expone expose() y wrap() como API central.
  • Pendiente de verificar por vos: el impacto exacto en tu plugin depende de cómo terminás tus workers. Probalo en tu flujo antes de asumir que nada se rompe.
  • No confirmado: que esta API esté pensada para uso masivo en el front-end del sitio. Vive en el contexto del block editor; para el front hacé tus pruebas.

Errores comunes al usar worker-threads

  • Pasar funciones al worker: las funciones no se clonan entre hilos. Si mandás un callback como argumento, revienta. Pasá datos serializables y devolvé resultados, no lógica.
  • Mandar objetos no clonables: instancias de clases con métodos, nodos del DOM o referencias circulares no cruzan el structured clone. Convertí a objetos planos antes de enviar.
  • Tocar window o el DOM desde el worker: el worker no tiene acceso al document ni a window. Si tu función depende del DOM, no va a andar ahí adentro.
  • No esperar la promesa: toda llamada vuelve async. Si te olvidás el await, trabajás con una promesa en vez del valor y el bug es de esos que te comen la tarde.
  • Debuggear a ciegas: los errores del worker viven en su propio contexto. Usá la pestaña de workers en las DevTools del navegador, no la consola principal, para ver qué pasa adentro.

Un detalle de infra: si vas a servir un bloque con workers en producción, asegurate de que tu hosting entregue bien los módulos JS con el MIME correcto y sin reescrituras raras. En un hosting WordPress como el de Donweb subís el build y listo, pero conviene chequear los headers si usás SharedArrayBuffer (te van a hacer falta COOP y COEP).

Preguntas Frecuentes

¿Para qué sirve @wordpress/worker-threads en WordPress?

Sirve para mover cálculos pesados fuera del main thread del block editor, así el editor no se congela. Envuelve los web workers del navegador con un canal RPC type-safe: exponés funciones con expose() y las llamás desde el editor con wrap(), sin escribir postMessage a mano.

¿Cómo mejora el rendimiento del editor Gutenberg?

Libera el hilo principal. Al correr las tareas CPU-intensivas en un worker aparte, el cursor, el autosave y la interfaz siguen respondiendo mientras el cálculo pasa en segundo plano. No hace tu código más rápido, evita que bloquee la interacción. Lo explicamos a fondo en evitar errores que ralenticen tu web.

¿Qué diferencia hay con los web workers nativos?

Los web workers nativos usan postMessage y listeners de mensajes que tenés que correlacionar vos, sin tipos. El paquete pone encima un RPC: llamás funciones como si fueran locales, recibís promesas tipadas, la transferencia de objetos transferibles es automática y los errores se propagan solos.

¿Cuándo NO conviene usar un web worker?

Cuando la tarea es liviana (por debajo de ~50 ms) o cuando necesitás tocar el DOM, que el worker no puede. La comunicación entre hilos tiene costo de serialización y latencia, así que para operaciones chicas termina siendo más lento y suma complejidad que no te devuelve nada.

¿La versión 1.13.0 rompe algo del código existente?

No trae breaking changes de API. El cambio es que ahora las llamadas RPC pendientes se rechazan cuando el worker termina, en vez de quedar colgadas. Si ya atrapabas errores en tus llamadas, encaja solo; revisá igual tus bloques catch porque vas a recibir rechazos en casos de terminación que antes pasaban en silencio.

Conclusión

La 1.13.0 no reinventa nada, arregla un agujero real: las promesas que quedaban colgadas cuando cerrabas un worker ahora se rechazan, y eso te evita spinners eternos y estados zombies en el editor. Si desarrollás bloques con lógica pesada, actualizá el paquete con tu próximo build de Gutenberg y aprovechá para revisar que cada llamada RPC tenga su manejo de error.

El consejo de fondo sigue igual: usá workers cuando el cálculo bloquea de verdad, medí antes con las DevTools, y no metas un hilo aparte para tareas que se resuelven en dos milisegundos. La herramienta es buena, pero como todo en performance, primero medí, después optimizá.

Fuentes

Volver a

Novedades

Publicaciones relacionadas