Il tuo primo plugin native

In questa pagina

Un plugin native è un pacchetto npm che EmDash importa nello stesso processo del sito Astro. Questo tutorial crea un plugin che registra i salvataggi di contenuto, lo installa in un sito e lo registra in astro.config.mjs.

Usa il formato native quando il plugin ha bisogno di una funzione in-process come componenti di amministrazione React, componenti di rendering Astro o frammenti di pagina di fiducia. Se hook, route, storage e Block Kit coprono la funzione, inizia con un plugin sandboxed. Scegliere un formato di plugin confronta i formati.

Prerequisiti

Inizia con un sito EmDash che usa pnpm e può avviare il suo server di sviluppo. Il sito deve già dipendere da emdash, che fornisce il comando emdash usato sotto.

I comandi chiamano la directory del sito my-emdash-site e creano plugin-activity accanto. Sostituisci my-emdash-site con il nome della directory del tuo sito.

Creare e registrare il pacchetto

  1. Genera un pacchetto native accanto al sito.

    pnpm exec emdash plugin init --native --name @example/plugin-activity --dir ../plugin-activity

    Il comando rimuove lo scope npm quando crea l’ID del plugin. Il nome del pacchetto è @example/plugin-activity, mentre l’ID del plugin è plugin-activity.

  2. Installa le dipendenze del pacchetto.

    cd ../plugin-activity
    pnpm install
  3. Sostituisci il src/index.ts generato con un hook di salvataggio contenuti.

    import { definePlugin } from "emdash";
    import type { PluginDescriptor } from "emdash";
    
    export interface ActivityPluginOptions {
        logUpdates?: boolean;
    }
    
    export function activityPlugin(
        options: ActivityPluginOptions = {},
    ): PluginDescriptor<ActivityPluginOptions> {
        return {
            id: "plugin-activity",
            version: "0.1.0",
            format: "native",
            entrypoint: "@example/plugin-activity",
            options,
        };
    }
    
    export function createPlugin(options: ActivityPluginOptions = {}) {
        return definePlugin({
            id: "plugin-activity",
            version: "0.1.0",
            capabilities: ["content:read"],
            hooks: {
                "content:afterSave": async (event, ctx) => {
                    if (!event.isNew && options.logUpdates === false) return;
    
                    ctx.log.info("Content saved", {
                        collection: event.collection,
                        contentId: event.content.id,
                        isNew: event.isNew,
                    });
                },
            },
        });
    }
    
    export default createPlugin;

    content:afterSave richiede la capability content:read. EmDash salta l’hook quando quella capability manca.

  4. Compila il pacchetto.

    pnpm build
  5. Installa il pacchetto locale nel sito.

    cd ../my-emdash-site
    pnpm add ../plugin-activity
  6. Registra la factory del descriptor nell’integrazione EmDash.

    import { defineConfig } from "astro/config";
    import emdash from "emdash/astro";
    import { activityPlugin } from "@example/plugin-activity";
    
    export default defineConfig({
        integrations: [
            emdash({
                plugins: [activityPlugin({ logUpdates: true })],
            }),
        ],
    });

    I descriptor native appartengono a plugins, non a sandboxed. EmDash rifiuta un descriptor native nell’array sandboxed.

  7. Avvia il sito e salva una voce nel pannello di amministrazione.

    pnpm dev

    Il log del server include Content saved con la collection, l’ID del contenuto e se la voce è stata creata.

Confine descriptor / runtime

L’export del pacchetto ha due compiti. EmDash usa ciascuno in una fase diversa:

  • La factory del descriptor, activityPlugin(), viene eseguita mentre Astro valuta la sua configurazione. Restituisce metadati serializzabili di build-time: id, version, format, entrypoint e options. Anche gli entrypoint React e Astro appartengono a questo descriptor.
  • L’export con nome createPlugin() viene eseguito quando EmDash si inizializza. EmDash lo importa da entrypoint, passa le options serializzate e si aspetta un plugin risolto da definePlugin().

L’export con nome createPlugin è obbligatorio. Un export di default può essere utile ai consumatori del pacchetto, ma il loader native di EmDash importa createPlugin per nome.

Mantieni id e version identici nel descriptor e in definePlugin(). Usa un ID plugin senza scope e in kebab-case come plugin-activity; conserva lo scope npm nel nome del pacchetto e in entrypoint. Così l’ID resta utilizzabile come unico segmento di plugin nelle URL delle route API.

Identità e versionamento del plugin elenca le forme di ID e versione accettate.

Il comportamento runtime appartiene a definePlugin():

  • capabilities e allowedHosts
  • storage
  • hooks e routes
  • dichiarazioni di impostazioni, pagina, widget e Portable Text di admin

Il descriptor porta le voci statiche che Astro deve importare o esporre in build-time. Le guide mirate mostrano quali campi di amministrazione richiedono dichiarazioni descriptor e runtime corrispondenti.

Handler di route native

Gli handler di route native ricevono un RouteContext. Combina l’input convalido e i dati della richiesta con il PluginContext abituale:

routes: {
	status: {
		permission: "plugins:read",
		handler: async (ctx) => ({
			pluginId: ctx.plugin.id,
			callerId: ctx.user?.id ?? null,
		}),
	},
},

L’handler sandboxed equivalente riceve (routeCtx, ctx) come due argomenti. Autenticazione, permessi, schemi di input e URL delle route seguono altrimenti il contratto condiviso delle route API.

Avvolgi una route native in definePluginRoute() quando dichiara request.body; l’helper inferisce ctx.input dalla modalità del body. Una route native con response: "raw" restituisce pluginResponse(). Importa entrambi gli helper da emdash. La guida condivisa delle route API elenca le modalità del body, i limiti, la policy di risposta e i default di compatibilità.

Aggiungere un’altra superficie