Distribuir plugins nativos

En esta página

Los plugins nativos son paquetes de npm que se instalan en el proyecto host y se registran en astro.config.mjs. El paquete necesita un punto de entrada de servidor compilado para su descriptor y para createPlugin(). Si además incluye componentes de React o de Astro, expórtalos como puntos de entrada de código fuente independientes 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. Mantén src/admin/ y src/astro/ en el tarball publicado, porque la compilación de Vite y de Astro del host debe procesar esos puntos de entrada.

Exportaciones del paquete

El siguiente package.json compila el punto de entrada del servidor y publica los tres puntos de entrada:

{
	"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 dependencias peer exclusivas de administración cuando el plugin no tenga una interfaz de React de confianza. Elimina ./astro, src/astro y el peer astro cuando no tenga un renderizador de Portable Text. Añade una dependencia peer por cada biblioteca propiedad del host que importe un punto de entrada de código fuente exportado; así evitas que una segunda instancia de React, Kumo, Lingui o React Query entre en el bundle de administración.

Los puntos de entrada tienen consumidores distintos:

ExportaciónNecesaria cuandoConsumidor
.SiempreLa configuración de Astro importa la factoría del descriptor; EmDash importa en runtime el createPlugin() con nombre.
./adminadminEntry está definidoLa compilación de navegador del host importa los mapas de componentes de React.
./astrocomponentsEntry está definidoLa compilación de Astro del host importa blockComponents.

Los especificadores de módulo del descriptor y del 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 de npm, la versión del descriptor y la versión de definePlugin(). La versión que ve el administrador del sitio procede de la definición del plugin, no automáticamente de package.json.

Identidad y versión del plugin

definePlugin() acepta un ID sin ámbito, que contenga letras minúsculas, dígitos y guiones, o un ID con ámbito con la forma @scope/name. Usa un ID sin ámbito 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 de npm:

id: "plugin-activity"; // Recommended: valid in plugin route URLs
id: "@example/plugin-activity"; // Accepted by definePlugin(), but not one URL segment

entrypoint: "@example/plugin-activity"; // The npm package may stay scoped

Las versiones deben comenzar con una secuencia semántica major.minor.patch. Usa una versión semántica completa tanto en el descriptor como en el runtime:

version: "1.0.0"; // Valid
version: "1.2.3-beta.1"; // Valid prerelease
version: "1.0"; // Invalid: missing patch version

Configuración de TypeScript

El siguiente tsconfig.json cubre un plugin nativo con código fuente de React y de Astro:

{
	"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 sobre los puntos de entrada de código fuente antes de empaquetar. El script build compila solo src/index.ts; el host compila el código fuente exportado de administración y de Astro cuando consume el paquete.

Inspeccionar el paquete

Prueba el contenido exacto del tarball antes de publicar. Los comandos siguientes suponen que un sitio desechable llamado my-emdash-site se encuentra junto al directorio del plugin.

  1. Compila el paquete y comprueba los tipos.

    pnpm typecheck
    pnpm build
  2. Crea el tarball de npm y revisa la lista de archivos que imprime npm.

    npm pack

    Para el paquete de ejemplo, npm crea example-plugin-activity-0.1.0.tgz.

  3. Confirma que la salida contiene dist/index.mjs, dist/index.d.mts y todos los archivos de código fuente accesibles desde los módulos exportados ./admin y ./astro.

  4. Instala el tarball generado en el sitio de EmDash desechable.

    cd ../my-emdash-site
    pnpm add ../plugin-activity/example-plugin-activity-0.1.0.tgz
  5. Importa y registra la factoría del descriptor en el astro.config.mjs del sitio desechable, siguiendo Crear y registrar el paquete. Después, compila el sitio host.

    pnpm build

    Abre todas las superficies de administración del plugin y renderiza todos los bloques de Portable Text aportados. Registrar el plugin antes de compilar hace que Astro resuelva las exportaciones ./admin y ./astro del tarball; una prueba del paquete solo en el servidor no puede detectar un archivo de código fuente de navegador o .astro que falte.

Contenidos del README

Dale a un operador información suficiente 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 compatible
  • 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 cada host permitido, con la función que los usa
  • los ajustes y sus valores por defecto
  • los componentes de diseño necesarios, como EmDashBodyEnd para un fragmento al final del body
  • los pasos de actualización para los cambios que requieren una acción del operador

No describas las declaraciones de capabilities como un límite de aislamiento. Controlan el acceso a las API de ctx, pero el código nativo todavía puede usar las importaciones, las variables de entorno y las llamadas de red directas disponibles para el proceso del host.

Publicar en npm

Publica después de que la prueba del tarball haya pasado:

npm publish --access public

La primera publicación pública de un paquete con ámbito necesita --access public. Usa el versionado semántico en las publicaciones posteriores. Trata los cambios en las opciones del constructor, los datos almacenados, los cambios necesarios en el host, las exportaciones del paquete o los requisitos de confianza del plugin como decisiones de compatibilidad. Si una actualización requiere una nueva capability o un nuevo host permitido, indícalo en las notas de la versión aunque las instalaciones nativas no tengan un aviso de consentimiento de capabilities.

Instalar desde npm

Un operador instala el paquete publicado en el sitio de EmDash:

pnpm add @example/plugin-activity

Después, importa y registra su factoría de descriptor en astro.config.mjs como se muestra en Crear y registrar el paquete. Instalar la dependencia por sí sola no activa el plugin; la instalación se completa al cambiar la configuración de Astro y desplegar el sitio.

Desarrollar contra un sitio host

Compila el plugin en modo watch:

pnpm dev

Instala el directorio local desde el sitio host:

pnpm add ../plugin-activity

Registra la factoría de descriptor del plugin en astro.config.mjs y luego inicia el servidor de desarrollo del host. Reinicia el servidor después de cambiar los metadatos del descriptor o las exportaciones del paquete. Si en tu configuración una dependencia de archivo del gestor de paquetes copia los archivos en lugar de enlazarlos, vuelve a instalarla después de recompilar; una dependencia de workspace o pnpm link mantiene conectado el paquete local 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 en sandbox, el flujo de publicación firmado y el flujo de consentimiento de instalación. Si el plugin ya no necesita código de administración de React, renderizadores de Astro, fragmentos de confianza ni otra dependencia en el mismo proceso, conviértelo al formato en sandbox antes de publicarlo a través del registro.