Zur Plugin-CLI migrieren

Auf dieser Seite

Dieser Leitfaden richtet sich an Autoren sandboxed Plugins, die gegen die frühere definePlugin()-Form geschrieben wurden. Arbeiten Sie die Breaking Changes der Reihe nach ab. Keiner davon ändert, wie Ihre Hooks oder Routes zur Laufzeit verhalten; sie ändern, wie das Plugin deklariert, gebaut und veröffentlicht wird.

Die vollständige Liste der Änderungen in jedem Paket finden Sie im jeweiligen Eintrag auf der Releases-Seite.

Breaking Changes

Umbenannt: @emdash-cms/registry-cli ist jetzt @emdash-cms/plugin-cli

Frühere Releases lieferten die CLI als @emdash-cms/registry-cli mit einer emdash-registry-Binary.

Das Paket heißt jetzt @emdash-cms/plugin-cli und die Binary ist emdash-plugin. Das alte Paket wird nicht mehr veröffentlicht.

Was soll ich tun?

Ersetzen Sie die Abhängigkeit:

pnpm remove @emdash-cms/registry-cli
pnpm add -D @emdash-cms/plugin-cli

Ersetzen Sie emdash-registry überall, wo Sie es aufrufen, durch emdash-plugin. Jeder Unterbefehl behält seinen Namen (bundle, publish, login, whoami, switch, validate), und init, build sowie dev kommen hinzu. Siehe The plugin CLI.

Umbenannt: Capability-Namen verwenden resource-first Schreibweise

Frühere Manifeste verwendeten Capability-Namen wie read:content und network:fetch. Das Authoring-Manifest akzeptiert nur die aktuellen Namen, obwohl die Runtime Legacy-Namen in bereits veröffentlichten Bundles während des Kompatibilitätsfensters weiterhin normalisiert.

Was soll ich tun?

Ersetzen Sie jeden Legacy-Namen im Manifest:

Früherer NameAktueller Name
network:fetchnetwork:request
network:fetch:anynetwork:request:unrestricted
read:contentcontent:read
write:contentcontent:write
read:mediamedia:read
write:mediamedia:write
read:usersusers:read
email:providehooks.email-transport:register
email:intercepthooks.email-events:register
page:injecthooks.page-fragments:register

Verwenden Sie network:request mit einer nicht leeren allowedHosts-Liste. Verwenden Sie network:request:unrestricted mit einer leeren Liste nur, wenn ein Operator das Ziel zur Laufzeit wählt. Capabilities and security erklärt die aktuellen Berechtigungen und Netzwerkregeln.

Geändert: Sandboxed Plugins nutzen eine explizite SandboxedPlugin-Annotation

Frühere Releases wrappeten die Hooks und Routes des Plugins in definePlugin(), importiert aus emdash, wobei die Parameter jedes Handlers von Hand annotiert wurden.

Ein Sandboxed Plugin weist seine Definition einer SandboxedPlugin-typisierten Konstanten zu und exportiert diese Konstante als Default. Importieren Sie den Typ aus emdash/plugin mit import type; der Bundler löscht diesen Import. Derselbe Subpath exportiert auch die leichten Runtime-Helfer pluginRoute() und pluginResponse(). TypeScript leitet event und ctx jedes Handlers aus dem Hook- oder Route-Namen ab, sodass Handler-Parameter keine Annotationen brauchen. Die explizite Annotation hält generierte Deklarationen unter isolierten Paketmanager-Layouts portabel.

Was soll ich tun?

Nehmen Sie vier Änderungen an der Quelldatei des Plugins vor. Ersetzen Sie den Import:

import { definePlugin, type ContentHookEvent, type PluginContext } from "emdash";
import type { SandboxedPlugin } from "emdash/plugin";

Ersetzen Sie den definePlugin()-Wrapper durch eine explizit typisierte Konstante:

export default definePlugin({ /* hooks, routes */ });
const plugin: SandboxedPlugin = { /* hooks, routes */ };

export default plugin;

Entfernen Sie die Parameter-Annotationen aus jedem Handler:

handler: async (event: ContentHookEvent, ctx: PluginContext) => {
handler: async (event, ctx) => {

Das Ergebnis ist ein default-exportiertes Objekt:

import type { SandboxedPlugin } from "emdash/plugin";

const plugin: SandboxedPlugin = {
	hooks: {
		"content:beforeSave": {
			handler: async (event, ctx) => {
				return event.content;
			},
		},
	},
};

export default plugin;

Um einen Event-Typ in einer Hilfsfunktion zu benennen, importieren Sie ihn aus emdash/plugin:

import type { ContentHookEvent, PluginContext } from "emdash/plugin";

Das event eines Handlers ist immer der kanonische Typ für diesen Hook. Einen Handler mit einer engeren Schnittstelle zu annotieren führt nicht mehr zum Type-Check. Validieren Sie Felder, von denen Sie abhängen, zur Laufzeit mit einem typeof-Check oder einem Guard — der richtige Ansatz für Daten von außerhalb des Typsystems.

Geändert: Ein Plugin ist eine src/plugin.ts plus emdash-plugin.jsonc

Frühere Releases teilten ein Plugin in zwei Dateien: src/index.ts lieferte einen PluginDescriptor (id, version, capabilities, storage, entrypoint), und src/sandbox-entry.ts enthielt die Hooks und Routes.

Ein Plugin ist jetzt eine Runtime-Datei, src/plugin.ts (Hooks und Routes), und ein handbearbeitetes Manifest, emdash-plugin.jsonc (Identität und der Trust-Vertrag). Die Felder entrypoint und format sind weg; der Build verdrahtet sie.

Was soll ich tun?

Verschieben Sie die Hooks und Routes in src/plugin.ts mit der Form oben. Verschieben Sie die Metadaten des Descriptors in emdash-plugin.jsonc neben package.json. Die Descriptor-id wird zum Manifest-slug; capabilities, allowedHosts und storage behalten ihre Form; version wird aus package.json gelesen, also weglassen.

Das folgende Beispiel zeigt das Manifest-Äquivalent eines Descriptors, der eine Storage-Collection deklarierte:

{
	"$schema": "./node_modules/@emdash-cms/plugin-cli/schemas/emdash-plugin.schema.json",

	"slug": "plugin-hello",
	"publisher": "did:plc:abc123def456",

	"license": "MIT",
	"author": { "name": "Jane Doe", "url": "https://example.com" },
	"security": { "email": "security@example.com" },

	"capabilities": [],
	"allowedHosts": [],
	"storage": { "events": { "indexes": ["timestamp"] } }
}

Siehe The plugin manifest für jedes Feld und Publisher pinning für das Feld publisher.

In package.json zeigen Sie den "./sandbox"-Export auf die gebaute Runtime-Datei:

"./sandbox": "./dist/sandbox-entry.mjs"
"./sandbox": "./dist/plugin.mjs"

Fügen Sie das Manifest zu files hinzu, damit es mit dem Paket ausgeliefert wird:

"files": ["dist"]
"files": ["dist", "emdash-plugin.jsonc"]

Geändert: Bauen mit emdash-plugin build

Frühere Releases bauten die beiden Quelldateien mit einem handgeschriebenen tsdown-Skript.

emdash-plugin build liest emdash-plugin.jsonc und src/plugin.ts und erzeugt die dist/-Artefakte. emdash-plugin dev beobachtet und baut neu.

Was soll ich tun?

Ersetzen Sie das Build-Skript und fügen Sie ein Watch-Skript hinzu:

"scripts": {
	"build": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --clean"
	"build": "emdash-plugin build",
	"dev": "emdash-plugin dev"
}

Dann validieren und bauen:

emdash-plugin validate
emdash-plugin build

Entfernt: Standard-Format-Typ- und Funktions-Exports aus emdash

Frühere Releases exportierten StandardPluginDefinition, StandardHookHandler, StandardHookEntry, StandardRouteHandler, StandardRouteEntry und die Funktion isStandardPluginDefinition aus emdash.

Diese sind entfernt. Sie waren Hilfsaliase für die frühere definePlugin-Form.

Was soll ich tun?

Verwenden Sie SandboxedPlugin aus emdash/plugin für denselben Zweck. Die exportierte Definition eines Sandboxed Plugins ist bereits durch seine SandboxedPlugin-Annotation typisiert, daher gibt es keinen Ersatz für isStandardPluginDefinition; identifizieren Sie ein Plugin bei Bedarf an seiner Struktur ({ hooks?, routes? }).

Umbenannt: Sandbox-Runner-Handles nutzen SandboxedPluginInstance

Dies betrifft nur Autoren eines eigenen SandboxRunner, etwa @emdash-cms/cloudflare. Die meisten Plugin-Autoren können es überspringen.

Der autorenseitige Typ SandboxedPlugin ist über den Authoring-Entry-Point emdash/plugin verfügbar. Das Runtime-Handle, das SandboxRunner.load zurückgibt, wird aus emdash als SandboxedPluginInstance exportiert.

Was soll ich tun?

Wenn Sie SandboxedPlugin aus emdash importieren, um einen Sandbox-Runner zu typisieren oder Runtime-Plugin-Handles zu halten, ändern Sie den Import zu SandboxedPluginInstance:

import type { SandboxedPlugin } from "emdash";
import type { SandboxedPluginInstance } from "emdash";

Informieren Sie Ihre Nutzer

Sites, die Ihr Plugin installieren, müssen auch ihren Import ändern. Verweisen Sie sie auf die neue Form: Klammern und () weglassen.

import { helloPlugin } from "@my-org/plugin-hello";
import hello from "@my-org/plugin-hello";

export default defineConfig({
	integrations: [
		emdash({
			sandboxed: [helloPlugin()],
			sandboxed: [hello],
		}),
	],
});

Wenn Ihr Plugin Konfiguration über seine Factory akzeptierte, verschieben Sie diese Konfiguration auf eine Admin-Einstellungsseite und lesen Sie sie aus ctx.settings. Sandboxed-Plugin-Descriptoren sind Plain Objects und können keine Konstruktoroptionen empfangen. Siehe Settings.

Das migrierte Plugin verifizieren

Führen Sie die Tests des Plugins aus, validieren Sie das Authoring-Manifest und führen Sie die vollständigen Build- und Bundle-Checks aus:

pnpm test
pnpm exec emdash-plugin validate
pnpm exec emdash-plugin build
pnpm exec emdash-plugin bundle --validate-only

Installieren Sie dann das lokale Paket in eine Entwicklungssite und üben Sie jeden migrierten Hook und jede Route. Der Build kann ihre Namen und Formen bestätigen, aber nicht, dass eine Route die beabsichtigten Daten zurückgibt oder dass ein Hook Inhalt korrekt erhält.

Weiter