分發原生外掛

本頁內容

原生外掛是安裝在宿主專案中並在 astro.config.mjs 中註冊的 npm 套件。套件需要為其描述子與 createPlugin() 建置的伺服器進入點。若還附帶 React 或 Astro 元件,請將它們匯出為單獨的來源進入點,以便宿主能為正確環境編譯它們。

套件版面

以下版面將伺服器執行階段與瀏覽器和 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/ 是產生的。請在已發佈的 tarball 中保留 src/admin/ 與 src/astro/,因為宿主的 Vite 與 Astro 建置必須處理這些進入點。

套件匯出

以下 package.json 建置伺服器進入點並發佈全部三個進入點:

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

當外掛沒有受信任的 React UI 時,移除 ./admin、src/admin 以及僅管理端的 peerDependencies。當沒有 Portable Text 渲染器時,移除 ./astro、src/astro 與 astro peer。為每個匯出的來源進入點匯入的宿主擁有函式庫新增 peerDependency;這可防止第二個 React、Kumo、Lingui 或 React Query 實例進入管理套件。

進入點有不同的消費者:

匯出何時需要消費者
.始終Astro 設定匯入描述子工廠;EmDash 在執行階段匯入具名 createPlugin()。
./admin設定了 adminEntry宿主的瀏覽器建置匯入 React 元件對應。
./astro設定了 componentsEntry宿主的 Astro 建置匯入 blockComponents。

描述子與執行階段中的模組說明符必須與這些匯出符合:

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

保持 npm 套件版本、描述子版本與 definePlugin() 版本同步。向網站管理員顯示的版本來自外掛定義,而不是自動來自 package.json。

外掛識別與版本

definePlugin() 接受包含小寫字母、數字與連字號的無作用域 ID,或形如 @scope/name 的作用域 ID。對網站外掛使用無作用域、kebab-case 的 ID,因為 ID 也佔用 /_emdash/api/plugins/<plugin-id>/<route> 中的一個路徑區段。

以下值顯示可接受形式以及外掛 ID 與 npm 套件名稱之間的建議分離:

id: "plugin-activity"; // 建議:在外掛路由 URL 中有效
id: "@example/plugin-activity"; // definePlugin() 接受,但不是一個 URL 區段

entrypoint: "@example/plugin-activity"; // npm 套件可以保持作用域

版本必須以語意化 major.minor.patch 序列開頭。對描述子與執行階段都使用完整語意版本:

version: "1.0.0"; // 有效
version: "1.2.3-beta.1"; // 有效的預發佈
version: "1.0"; // 無效:缺少修補版本

TypeScript 設定

原生鷹架會建立合適的 tsconfig.json。若外掛在鷹架之後新增 React 與 Astro 原始碼,請包含兩種 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"]
}

打包前對來源進入點執行 pnpm typecheck。build 指令碼僅編譯 src/index.ts;宿主在消費套件時編譯匯出的管理端與 Astro 原始碼。

檢查套件

發佈前測試確切的 tarball 內容。以下命令假定名為 my-emdash-site 的臨時網站位於外掛目錄旁。

  1. 建置並型別檢查套件。

    pnpm typecheck
    pnpm build
  2. 建立 npm tarball 並查看 npm 列印的檔案清單。

    npm pack

    對於範例套件,npm 會建立 example-plugin-activity-0.1.0.tgz。

  3. 確認輸出包含 dist/index.mjs、dist/index.d.mts,以及從匯出的 ./admin 與 ./astro 模組可達的每個來源檔案。

  4. 將產生的 tarball 安裝到臨時 EmDash 網站。

    cd ../my-emdash-site
    pnpm add ../plugin-activity/example-plugin-activity-0.1.0.tgz
  5. 按照 建立並註冊套件,在臨時網站的 astro.config.mjs 中匯入並註冊描述子工廠。然後建置宿主網站。

    pnpm build

    開啟每個外掛管理表面,並渲染每個貢獻的 Portable Text 區塊。在建置前註冊可使 Astro 解析 tarball 的 ./admin 與 ./astro 匯出;僅伺服器的套件測試無法發現缺失的瀏覽器或 .astro 來源檔案。

README 內容

為營運者提供足夠資訊,使其無需閱讀原始碼即可安裝並評估套件。包括:

  • 一句話描述與支援的 EmDash 版本
  • 安裝命令與完整的 astro.config.mjs 註冊
  • 原生信任邊界以及外掛為何需要原生執行
  • 每個已宣告能力與允許的主機,以及使用它的功能
  • 設定及其預設值
  • 必要的版面元件,例如用於 body-end 片段的 EmDashBodyEnd
  • 需要營運者操作的變更的升級步驟

不要將能力宣告描述為隔離邊界。它們對 ctx API 設門,但原生程式碼仍可使用宿主行程可用的匯入、環境變數與直接網路呼叫。

發佈到 npm

tarball 測試通過後發佈:

npm publish --access public

作用域套件的首次公開發佈需要 --access public。後續發佈使用語意化版本。將建構函式選項、已存資料、必要的宿主變更、套件匯出或外掛信任要求的變更視為相容性決策。若升級需要新能力或允許的主機,即使原生安裝沒有能力同意提示,也請在發佈說明中指出。

從 npm 安裝

營運者將已發佈的套件安裝到 EmDash 網站:

pnpm add @example/plugin-activity

然後按 建立並註冊套件 所示,在 astro.config.mjs 中匯入並註冊其描述子工廠。僅安裝依賴不會啟用外掛;變更 Astro 設定並部署網站才完成安裝。

針對宿主網站開發

以監視模式建置外掛:

pnpm dev

從宿主網站安裝本機目錄:

pnpm add ../plugin-activity

在 astro.config.mjs 中註冊外掛的描述子工廠,然後啟動宿主開發伺服器。變更描述子中繼資料或套件匯出後重新啟動伺服器。若套件管理員檔案依賴在你的設定中複製檔案而不是連結,請在重建後重新安裝;工作區依賴或 pnpm link 可在開發期間保持本機套件連接。

登錄庫邊界

原生套件不能發佈到 EmDash 登錄庫。登錄庫外掛使用沙箱套件格式、簽署發佈工作流程與安裝同意流程。若外掛不再需要 React 管理程式碼、Astro 渲染器、受信任片段或其他行程內依賴,請在透過登錄庫發佈前 轉換為沙箱格式。