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 um ponto de entrada de servidor compilado para o seu descritor e para createPlugin(). Se ele também incluir componentes React ou Astro, exporte-os como pontos de entrada de código-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 do Vite e do Astro do host precisa processar esses pontos de entrada.

Exportações do pacote

O package.json a seguir compila o ponto de entrada do servidor e publica os três pontos 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"
}

Remova ./admin, src/admin e as dependências peer exclusivas da administração quando o plugin não tiver uma interface React confiável. Remova ./astro, src/astro e o peer astro quando ele não tiver um renderizador de Portable Text. Adicione uma dependência peer para cada biblioteca pertencente ao host que um ponto de entrada de código-fonte exportado importe; isso evita que uma segunda instância de React, Kumo, Lingui ou React Query entre no bundle de administração.

Os pontos de entrada têm consumidores diferentes:

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

Os especificadores de módulo no descritor e no runtime devem corresponder a essas 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 descritor e a versão de definePlugin(). A versão exibida ao administrador do site vem da definição do plugin, e não automaticamente do package.json.

Identidade e versão do plugin

definePlugin() aceita um ID sem escopo, contendo letras minúsculas, dígitos e hifens, ou um ID com escopo no formato @scope/name. Use um ID sem escopo, 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"; // 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

As versões devem começar com uma sequência semântica major.minor.patch. Use uma versão semântica completa tanto no descritor quanto no runtime:

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

Configuração TypeScript

O tsconfig.json a seguir cobre um plugin nativo com código-fonte React e 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"]
}

Execute pnpm typecheck nos pontos de entrada de código-fonte antes de empacotar. O script build compila apenas src/index.ts; o host compila o código-fonte exportado de administração e do Astro quando consome o pacote.

Inspecionar o pacote

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

  1. Compile o pacote e verifique os tipos.

    pnpm typecheck
    pnpm build
  2. Crie o tarball do 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 todo arquivo de código-fonte alcançável a partir dos módulos exportados ./admin e ./astro.

  4. Instale o tarball gerado 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 descritor no astro.config.mjs do site descartável, seguindo Criar e registrar o pacote. Em seguida, compile o site host.

    pnpm build

    Abra todas as superfícies de administração do plugin e renderize todos os blocos de Portable Text fornecidos. Registrar o plugin antes do build faz o Astro resolver as exportações ./admin e ./astro do tarball; um teste do pacote apenas no servidor não consegue detectar um arquivo de código-fonte de navegador ou .astro ausente.

Conteúdo do README

Forneça a um operador informações suficientes para instalar e avaliar o pacote sem ler o código-fonte. Inclua:

  • uma descrição de uma frase e a versão do EmDash com suporte
  • 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 cada host permitido, com o recurso que a utiliza
  • as configurações e seus valores padrão
  • os componentes de layout necessários, como EmDashBodyEnd para um fragmento de fim de body
  • as etapas de atualização para mudanças que exigem ação do operador

Não descreva as declarações de capabilities como um limite de isolamento. Elas controlam o acesso às APIs de ctx, mas o código nativo ainda pode usar as importações, as variáveis de ambiente e as chamadas de rede diretas disponíveis para o processo do 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 escopo precisa de --access public. Use versionamento semântico nas versões seguintes. Trate mudanças nas opções do construtor, nos dados armazenados, nas alterações necessárias no host, nas exportações do pacote ou nos requisitos de confiança do plugin como decisões de compatibilidade. Se uma atualização exigir uma nova capability ou um novo host permitido, destaque isso nas notas da versão, mesmo que as 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 a factory do descritor em astro.config.mjs, como mostrado em Criar e registrar o pacote. Instalar apenas a dependência não ativa o plugin; alterar a configuração do Astro e implantar o site conclui a instalação.

Desenvolver contra um site host

Compile 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 descritor do plugin em astro.config.mjs e, em seguida, inicie o servidor de desenvolvimento do host. Reinicie o servidor depois de alterar os metadados do descritor ou as exportações do pacote. Se, na sua configuração, uma dependência de arquivo do gerenciador de pacotes copiar os arquivos em vez de vinculá-los, reinstale-a depois de recompilar; 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 do EmDash. Os plugins do registry usam o formato de pacote em sandbox, o fluxo de publicação assinado e o fluxo de consentimento de instalação. Se o plugin não precisar mais de código de administração React, renderizadores do Astro, fragmentos confiáveis ou outra dependência no mesmo processo, converta-o para o formato em sandbox antes de publicá-lo pelo registry.