Distribuir plugins nativos

Nesta página

Plugins nativos são pacotes npm instalados no projeto host e registrados em astro.config.mjs. O pacote precisa de uma entrada de servidor construída para seu descriptor e createPlugin(). Se também enviar componentes React ou Astro, exporte-os como entry points de fonte separados para que o host possa compilá-los para o ambiente correto.

Layout do pacote

O layout a seguir separa o runtime do servidor do código-fonte do navegador e do 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/ é gerado. Mantenha src/admin/ e src/astro/ no tarball publicado porque o build Vite e Astro do host deve processar esses entry points.

Exportações do pacote

O package.json a seguir constrói a entrada do servidor e publica os três entry points:

{
	"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"
}

Remova ./admin, src/admin e as peer dependencies só de admin quando o plugin não tiver UI React confiável. Remova ./astro, src/astro e o peer astro quando não tiver um renderizador Portable Text. Adicione uma peer dependency para cada biblioteca do host importada por um entry point de fonte exportado; isso impede que uma segunda instância de React, Kumo, Lingui ou React Query entre no bundle de administração.

Os entry points têm consumidores diferentes:

ExportaçãoObrigatória quandoConsumidor
.SempreA configuração Astro importa a factory do descriptor; EmDash importa o createPlugin() nomeado em runtime.
./adminadminEntry está definidoO build do navegador do host importa os mapas de componentes React.
./astrocomponentsEntry está definidoO build Astro do host importa blockComponents.

Os especificadores de módulo no descriptor e no runtime devem corresponder a estas exportações:

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",
		},
	});
}

Mantenha sincronizadas a versão do pacote npm, a versão do descriptor e a versão de definePlugin(). A versão mostrada a um administrador do site vem da definição do plugin, não automaticamente de package.json.

Identidade e versão do plugin

definePlugin() aceita um ID sem scope contendo letras minúsculas, dígitos e hífens, ou um ID com scope na forma @scope/name. Use um ID sem scope em kebab-case para um plugin de site porque o ID também ocupa um segmento de caminho em /_emdash/api/plugins/<plugin-id>/<route>.

Os valores a seguir mostram as formas aceitas e a separação recomendada entre o ID do plugin e o nome do pacote npm:

id: "plugin-activity"; // Recomendado: válido em URLs de rotas do plugin
id: "@example/plugin-activity"; // Aceito por definePlugin(), mas não um segmento de URL

entrypoint: "@example/plugin-activity"; // O pacote npm pode permanecer com scope

As versões devem começar com uma sequência semântica major.minor.patch. Use uma versão semântica completa para o descriptor e o runtime:

version: "1.0.0"; // Válida
version: "1.2.3-beta.1"; // Prerelease válida
version: "1.0"; // Inválida: falta a versão de patch

Configuração TypeScript

O scaffold nativo cria um tsconfig.json adequado. Se o plugin adicionar fonte React e Astro após o scaffolding, inclua ambos os ambientes 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"]
}

Execute pnpm typecheck contra os entry points de fonte antes de empacotar. O script build compila apenas src/index.ts; o host compila a fonte admin e Astro exportada quando consome o pacote.

Inspecionar o pacote

Teste o conteúdo exato do tarball antes de publicar. Os comandos abaixo assumem que um site descartável chamado my-emdash-site fica ao lado do diretório do plugin.

  1. Construa e verifique os tipos do pacote.

    pnpm typecheck
    pnpm build
  2. Crie o tarball npm e revise a lista de arquivos impressa pelo npm.

    npm pack

    Para o pacote de exemplo, o npm cria example-plugin-activity-0.1.0.tgz.

  3. Confirme que a saída contém dist/index.mjs, dist/index.d.mts e cada arquivo de fonte alcançável a partir dos módulos exportados ./admin e ./astro.

  4. Instale o tarball produzido no site EmDash descartável.

    cd ../my-emdash-site
    pnpm add ../plugin-activity/example-plugin-activity-0.1.0.tgz
  5. Importe e registre a factory do descriptor no astro.config.mjs do site descartável, seguindo Criar e registrar o pacote. Em seguida construa o site host.

    pnpm build

    Abra cada superfície de administração do plugin e renderize cada bloco Portable Text contribuído. Registrar antes do build faz o Astro resolver as exportações ./admin e ./astro do tarball; um teste só de servidor do pacote não consegue detectar um arquivo de fonte de navegador ou .astro ausente.

Conteúdo do README

Dê a um operador informação suficiente para instalar e avaliar o pacote sem ler seu código-fonte. Inclua:

  • uma descrição em uma frase e a versão EmDash suportada
  • o comando de instalação e o registro completo em astro.config.mjs
  • o limite de confiança nativo e por que o plugin precisa de execução nativa
  • cada capability declarada e host permitido, com o recurso que a usa
  • configurações e seus padrões
  • componentes de layout necessários, como EmDashBodyEnd para um fragmento body-end
  • passos de upgrade para mudanças que exigem ação do operador

Não descreva declarações de capability como um limite de isolamento. Elas limitam APIs de ctx, mas o código nativo ainda pode usar imports, variáveis de ambiente e chamadas de rede diretas disponíveis ao processo host.

Publicar no npm

Publique depois que o teste do tarball passar:

npm publish --access public

A primeira publicação pública de um pacote com scope precisa de --access public. Use versionamento semântico para releases posteriores. Trate mudanças em opções do construtor, dados armazenados, mudanças de host necessárias, exportações do pacote ou requisitos de confiança do plugin como decisões de compatibilidade. Se um upgrade exigir uma nova capability ou host permitido, destaque nas notas da release mesmo que instalações nativas não tenham um prompt de consentimento de capabilities.

Instalar a partir do npm

Um operador instala o pacote publicado no site EmDash:

pnpm add @example/plugin-activity

Em seguida importe e registre sua factory do descriptor em astro.config.mjs como mostrado em Criar e registrar o pacote. Instalar a dependência sozinha não ativa o plugin; alterar a configuração Astro e implantar o site completa a instalação.

Desenvolver contra um site host

Construa o plugin em modo watch:

pnpm dev

Instale o diretório local a partir do site host:

pnpm add ../plugin-activity

Registre a factory do descriptor do plugin em astro.config.mjs e então inicie o servidor de desenvolvimento do host. Reinicie o servidor após alterar metadados do descriptor ou exportações do pacote. Se uma dependência de arquivo do gerenciador de pacotes copiar arquivos em vez de vinculá-los na sua configuração, reinstale-a após reconstruir; uma dependência de workspace ou pnpm link mantém o pacote local conectado durante o desenvolvimento.

Limite do registry

Pacotes nativos não podem ser publicados no registry EmDash. Plugins do registry usam o formato de pacote sandboxed, o fluxo de release assinado e o fluxo de consentimento de instalação. Se o plugin não precisar mais de código de administração React, renderizadores Astro, fragmentos confiáveis ou outra dependência in-process, converta-o para o formato sandboxed antes de publicar pelo registry.