Los plugins nativos son paquetes npm instalados en el proyecto host y registrados en astro.config.mjs. El paquete necesita una entrada de servidor construida para su descriptor y createPlugin(). Si también envía componentes React o Astro, expórtalos como entrypoints de fuente separados para que el host pueda compilarlos para el entorno correcto.
Diseño del paquete
El siguiente diseño separa el runtime del servidor del código fuente del navegador y de Astro:
plugin-activity/
├── src/
│ ├── index.ts
│ ├── admin/
│ │ ├── index.tsx
│ │ └── ActivityPage.tsx
│ └── astro/
│ ├── index.ts
│ └── ActivityBlock.astro
├── dist/
│ ├── index.mjs
│ └── index.d.mts
├── package.json
├── tsconfig.json
└── README.md
dist/ se genera. Conserva src/admin/ y src/astro/ en el tarball publicado porque el build de Vite y Astro del host debe procesar esos entrypoints.
Exportaciones del paquete
El siguiente package.json construye la entrada del servidor y publica los tres entrypoints:
{
"name": "@example/plugin-activity",
"version": "0.1.0",
"type": "module",
"main": "./dist/index.mjs",
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs"
},
"./admin": "./src/admin/index.tsx",
"./astro": "./src/astro/index.ts"
},
"files": ["dist", "src/admin", "src/astro"],
"scripts": {
"build": "tsdown src/index.ts --format esm --dts --clean",
"dev": "tsdown src/index.ts --format esm --dts --watch",
"typecheck": "tsc --noEmit",
"prepublishOnly": "pnpm typecheck && pnpm build"
},
"peerDependencies": {
"@cloudflare/kumo": "*",
"@emdash-cms/admin": "*",
"@lingui/core": "*",
"@lingui/react": "*",
"@tanstack/react-query": "*",
"astro": ">=6.0.0-beta.0",
"emdash": "*",
"react": "^18.0.0 || ^19.0.0"
},
"devDependencies": {
"@types/react": "^19.0.0",
"tsdown": "^0.20.0",
"typescript": "^5.9.0"
},
"keywords": ["emdash", "emdash-plugin"],
"license": "MIT"
}
Elimina ./admin, src/admin y las peer dependencies solo de admin cuando el plugin no tenga UI React de confianza. Elimina ./astro, src/astro y el peer astro cuando no tenga un renderizador de Portable Text. Añade una peer dependency por cada biblioteca propiedad del host importada por un entrypoint de fuente exportado; esto evita que una segunda instancia de React, Kumo, Lingui o React Query entre en el bundle de administración.
Los entrypoints tienen distintos consumidores:
| Exportación | Obligatoria cuando | Consumidor |
|---|---|---|
. | Siempre | La configuración de Astro importa la factory del descriptor; EmDash importa el createPlugin() con nombre en runtime. |
./admin | adminEntry está establecido | El build del navegador del host importa los mapas de componentes React. |
./astro | componentsEntry está establecido | El build de Astro del host importa blockComponents. |
Los especificadores de módulo en el descriptor y el runtime deben coincidir con estas exportaciones:
export function activityPlugin(): PluginDescriptor {
return {
id: "plugin-activity",
version: "0.1.0",
format: "native",
entrypoint: "@example/plugin-activity",
adminEntry: "@example/plugin-activity/admin",
componentsEntry: "@example/plugin-activity/astro",
};
}
export function createPlugin() {
return definePlugin({
id: "plugin-activity",
version: "0.1.0",
admin: {
entry: "@example/plugin-activity/admin",
},
});
}
Mantén sincronizadas la versión del paquete npm, la versión del descriptor y la versión de definePlugin(). La versión mostrada a un administrador del sitio proviene de la definición del plugin, no automáticamente de package.json.
Identidad y versión del plugin
definePlugin() acepta un ID sin scope con letras minúsculas, dígitos y guiones, o un ID con scope en la forma @scope/name. Usa un ID sin scope en kebab-case para un plugin de sitio porque el ID también ocupa un segmento de ruta en /_emdash/api/plugins/<plugin-id>/<route>.
Los siguientes valores muestran las formas aceptadas y la separación recomendada entre el ID del plugin y el nombre del paquete npm:
id: "plugin-activity"; // Recomendado: válido en URL de rutas del plugin
id: "@example/plugin-activity"; // Aceptado por definePlugin(), pero no un segmento de URL
entrypoint: "@example/plugin-activity"; // El paquete npm puede seguir con scope
Las versiones deben comenzar con una secuencia semántica major.minor.patch. Usa una versión semántica completa para el descriptor y el runtime:
version: "1.0.0"; // Válida
version: "1.2.3-beta.1"; // Prerelease válida
version: "1.0"; // Inválida: falta la versión de parche
Configuración de TypeScript
El scaffold nativo crea un tsconfig.json adecuado. Si el plugin añade fuente React y Astro después del scaffolding, incluye ambos entornos JSX:
{
"compilerOptions": {
"target": "ES2022",
"module": "preserve",
"moduleResolution": "bundler",
"strict": true,
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
"jsx": "react-jsx",
"types": ["astro/client"]
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
Ejecuta pnpm typecheck contra los entrypoints de fuente antes de empaquetar. El script build compila solo src/index.ts; el host compila la fuente admin y Astro exportada cuando consume el paquete.
Inspeccionar el paquete
Prueba el contenido exacto del tarball antes de publicar. Los comandos siguientes asumen que un sitio desechable llamado my-emdash-site está junto al directorio del plugin.
-
Construye y comprueba tipos del paquete.
pnpm typecheck pnpm build -
Crea el tarball npm y revisa la lista de archivos que imprime npm.
npm packPara el paquete de ejemplo, npm crea
example-plugin-activity-0.1.0.tgz. -
Confirma que la salida contiene
dist/index.mjs,dist/index.d.mtsy cada archivo fuente alcanzable desde los módulos exportados./adminy./astro. -
Instala el tarball producido en el sitio EmDash desechable.
cd ../my-emdash-site pnpm add ../plugin-activity/example-plugin-activity-0.1.0.tgz -
Importa y registra la factory del descriptor en el
astro.config.mjsdel sitio desechable, siguiendo Crear y registrar el paquete. Luego construye el sitio host.pnpm buildAbre cada superficie de administración del plugin y renderiza cada bloque Portable Text aportado. Registrar antes del build hace que Astro resuelva las exportaciones
./adminy./astrodel tarball; una prueba solo de servidor del paquete no puede detectar un archivo fuente de navegador o.astrofaltante.
Contenidos del README
Da a un operador suficiente información para instalar y evaluar el paquete sin leer su código fuente. Incluye:
- una descripción de una frase y la versión de EmDash admitida
- el comando de instalación y el registro completo en
astro.config.mjs - el límite de confianza nativo y por qué el plugin necesita ejecución nativa
- cada capability declarada y host permitido, con la función que lo usa
- ajustes y sus valores predeterminados
- componentes de layout necesarios, como
EmDashBodyEndpara un fragmento body-end - pasos de actualización para cambios que requieren acción del operador
No describas las declaraciones de capability como un límite de aislamiento. Limitan las API de ctx, pero el código nativo aún puede usar imports, variables de entorno y llamadas de red directas disponibles para el proceso host.
Publicar en npm
Publica después de que pase la prueba del tarball:
npm publish --access public
La primera publicación pública de un paquete con scope necesita --access public. Usa versionado semántico para releases posteriores. Trata los cambios en opciones del constructor, datos almacenados, cambios requeridos del host, exportaciones del paquete o requisitos de confianza del plugin como decisiones de compatibilidad. Si una actualización requiere una nueva capability o host permitido, indícalo en las notas de la release aunque las instalaciones nativas no tengan un prompt de consentimiento de capabilities.
Instalar desde npm
Un operador instala el paquete publicado en el sitio EmDash:
pnpm add @example/plugin-activity
Luego importa y registra su factory del descriptor en astro.config.mjs como se muestra en Crear y registrar el paquete. Instalar la dependencia sola no activa el plugin; cambiar la configuración de Astro y desplegar el sitio completa la instalación.
Desarrollar contra un sitio host
Construye el plugin en modo watch:
pnpm dev
Instala el directorio local desde el sitio host:
pnpm add ../plugin-activity
Registra la factory del descriptor del plugin en astro.config.mjs y luego arranca el servidor de desarrollo del host. Reinicia el servidor tras cambiar metadatos del descriptor o exportaciones del paquete. Si una dependencia de archivo del gestor de paquetes copia archivos en lugar de enlazarlos en tu configuración, reinstálala tras reconstruir; una dependencia de workspace o pnpm link mantiene el paquete local conectado durante el desarrollo.
Límite del registro
Los paquetes nativos no se pueden publicar en el registro de EmDash. Los plugins del registro usan el formato de paquete sandboxed, el flujo de release firmado y el flujo de consentimiento de instalación. Si el plugin ya no necesita código de administración React, renderizadores Astro, fragmentos de confianza u otra dependencia in-process, conviértelo al formato sandboxed antes de publicar a través del registro.