Los plugins de EmDash se distribuyen en uno de dos formatos: sandboxed o native. La elección afecta cómo se instala el plugin, qué aplicación obtiene en tiempo de ejecución y qué características están disponibles.
Por defecto, sandboxed. Los plugins sandboxed pueden publicarse en el marketplace e instalarse desde la interfaz de administración con un clic. Los plugins nativos requieren un cambio de código, un npm install y un redespliegue en cada sitio que los quiera. Sandboxed es lo que los usuarios finales desean.
Elija nativo solo cuando necesite una característica que el sandbox no puede proporcionar.
De un vistazo
| Sandboxed | Native | |
|---|---|---|
| Forma de autoría | emdash-plugin.jsonc + src/plugin.ts | Descriptor definePlugin() |
| Método de instalación | Un clic desde el marketplace de administración | npm install + editar astro.config |
| Se ejecuta en | Un tiempo de ejecución aislado proporcionado por un sandbox runner | El mismo proceso que su sitio Astro |
| Capacidades | Aplicadas por el puente del sandbox | Aplicadas en proceso por el mismo puente |
| Límites de recursos | Aplicados por el runner — típicamente CPU, subrequests, wall-time, memoria | Ninguno |
| Acceso a red | Solo ctx.http, restringido a allowedHosts | Solo ctx.http, restringido a allowedHosts |
fetch() / process.env directos | Bloqueados por el runner | Posible (el código del plugin comparte el tiempo de ejecución) |
| Distribución | Bundle .tar.gz en el marketplace | Paquete npm |
| Interfaz de administración | Rutas Block Kit (descritas en JSON) | Componentes React, o Block Kit |
| Interfaz de configuración | Página Block Kit + lecturas KV | admin.settingsSchema (auto-formulario) o Block Kit |
| Componentes de renderizado de Portable Text | No disponible | componentsEntry proporciona componentes Astro |
| Contribuciones de metadatos de página | Hook page:metadata — etiquetas meta/property, rels <link> permitidos, JSON-LD | Hook page:metadata (misma superficie) |
| Inyección de fragmentos de página | No disponible — solo meta/JSON-LD vía page:metadata | Hook page:fragments — scripts inline, scripts externos, HTML crudo |
| Opciones del constructor | Ninguna — leer configuraciones de KV en tiempo de ejecución | options en el descriptor |
Lo que renuncias al elegir nativo
Los plugins nativos parecen una versión más poderosa de lo mismo, y lo son — pero el costo es alto:
- Sin marketplace. Cada sitio tiene que instalar tu paquete npm, editar
astro.config.mjsy redesplegar. - Sin aislamiento. Un error en tu plugin puede bloquear el proceso host o quemar su presupuesto de CPU. Un rechazo no manejado en un hook puede derribar la solicitud circundante con él.
- Carga de confianza en el usuario. Los plugins nativos tienen el mismo acceso que el sitio host. Los usuarios finales no pueden auditarlos solo a través de declaraciones de capacidades.
Si tu plugin puede hacer su trabajo en el sandbox, debería hacerlo.
Cuándo elegir nativo
Hay tres razones para elegir nativo, y todas se refieren a características que necesitan integración en tiempo de compilación con el sitio host:
-
Páginas o widgets de administración React personalizados. Los plugins sandboxed describen su interfaz de administración con Block Kit — un esquema JSON que el administrador renderiza en nombre del plugin. Si necesitas React completo (hooks personalizados, componentes de terceros, estado complejo), necesitas nativo.
-
Componentes Astro para renderizar bloques de Portable Text en el sitio público. Un plugin sandboxed puede declarar un tipo de bloque personalizado, pero los componentes Astro que lo renderizan en el sitio público deben cargarse en tiempo de compilación desde npm. Solo los plugins nativos pueden proporcionar un
componentsEntry. -
Inyectar HTML crudo, scripts o hojas de estilo en páginas públicas. El hook
page:fragmentsenvía código de primera parte a los navegadores de los visitantes — fuera de cualquier límite de sandbox. Está restringido a plugins nativos. Los plugins sandboxed aún pueden contribuir a páginas públicas a través del hookpage:metadata, que cubre muchos casos de uso reales:- Etiquetas
meta(name+content) — descripciones SEO, directivas de robots, tarjetas de Twitter - Etiquetas
property— OpenGraph y otros meta basados en propiedades - Etiquetas
linkcon una lista de permitidos rel bloqueada por seguridad (canonical,alternate,author,license,nlweb,site.standard.document) —stylesheet,prefetchy rels similares de carga de recursos no están permitidos deliberadamente - Grafos JSON-LD
Si tu necesidad de “inyección de página” son datos estructurados o metadatos SEO, mantente sandboxed y usa
page:metadata. Si realmente necesitas enviar JavaScript o HTML al navegador del visitante, ese es el caso para elegir nativo. - Etiquetas
Si no estás seguro, elige sandboxed. Siempre puedes migrar a nativo más tarde — pero al revés es más difícil, porque las características exclusivas de nativo no tienen equivalente en sandbox.
Sandbox runners y soporte de plataforma
El sandbox en sí es extensible. EmDash expone una opción de configuración sandboxRunner y el runner decide cómo se aísla el código del plugin — no hay nada específico de Cloudflare en el formato del plugin en sí.
El runner que la mayoría de los sitios usan hoy es sandbox() de @emdash-cms/cloudflare, que usa Dynamic Worker Loader de Cloudflare Workers. Worker Loader cachea el aislado V8 por id de plugin, por lo que el costo de arranque en frío del aislado solo se paga una vez; el runner construye un stub de worker fresco y bindings de puente en cada invocación, ya que los stubs y bindings están vinculados al contexto de I/O de la solicitud que llama. Los runners para otras plataformas (Node.js vía workerd, y potencialmente Deno) están en desarrollo.
Si no se configura ningún runner, o si el runner configurado reporta como no disponible en la plataforma actual, los plugins listados bajo sandboxed: [] se omiten en el inicio con un log de nivel de depuración.
Si deseas que un plugin sandboxed se ejecute en una plataforma sin un sandbox runner, muévelo de sandboxed: [] al array plugins: [] — se ejecutará en proceso. Las declaraciones de capacidades aún se respetan (la misma factory PluginContext controla ctx.content, ctx.http y amigos), pero no hay límite de aislamiento, no hay límites de recursos, y un plugin defectuoso o malicioso puede llamar a fetch() directamente, leer variables de entorno o bloquear el bucle de eventos. Sin un sandbox runner activo, trata cada plugin como un plugin nativo con fines de confianza.