入门指南
构建、打包并加载你的第一个 Kunkun 扩展。
这篇指南会带你跑通一个最小扩展。如果你还不确定该做哪种扩展,先读 扩展类型。
前置要求
- Node.js 18+ 或 Bun
- TypeScript 基础;如果要写 worker/node view,需要 React 基础
- 已安装 Kunkun 桌面端
扩展长什么样
每个扩展都是一个 npm 包,并在 package.json 里声明 kunkun manifest:
{
"name": "my-extension",
"version": "0.1.0",
"license": "MIT",
"$schema": "https://schema.kunkun.sh/",
"kunkun": {
"identifier": "com.you.my-extension",
"name": "My Extension",
"permissions": ["clipboard-read"],
"commands": [/* 一个或多个 command,每个 command 都有 mode */]
}
}identifier 是稳定且全局唯一的扩展 ID。每个 command 会声明运行模式(例如 custom-view、worker-view、node-headless)和入口文件 main。
扩展安装的是构建产物
Kunkun 安装扩展 tarball 后不会在安装目录里执行 npm install。你的构建产物必须自包含:把 JS 依赖打进 command/service 输出里。原生 .node addon 不能直接内联,需要把 loader 和平台文件一起打包。
快速开始:Custom-View 扩展
Custom-View 是一个静态 SPA,通过 kunkun-ext:// 协议加载到隔离窗口中。任何能编译成静态前端(SPA 或 SSG)的框架都可以使用。下面用 React 演示,因为它最普及;其他标签页是 Vue、Svelte、原生的相同步骤。
创建项目
bun create vite my-extension --template react-ts
cd my-extension
pnpm add @kunkunsh/sdkbun create vite my-extension --template vue-ts
cd my-extension
pnpm add @kunkunsh/sdkbun create vite my-extension --template svelte-ts
cd my-extension
pnpm add @kunkunsh/sdkbun create vite my-extension --template vanilla-ts
cd my-extension
pnpm add @kunkunsh/sdk如果你更习惯,npm create vite@latest / pnpm create vite 效果相同。
配置静态构建
Kunkun 从扩展自己的源加载构建产物,因此资源路径必须是相对的。在 vite.config.ts 中设置 base: './':
import { defineConfig } from 'vite'
// 框架插件:react() / vue() / svelte()
export default defineConfig({
base: './', // 必需:资源相对 kunkun-ext:// 加载
// plugins: [react()],
})使用 SvelteKit 等元框架?也可以——用 @sveltejs/adapter-static 输出静态 SPA(ssr = false、hash 路由)。详见 Custom UI 扩展。
添加 manifest
Vite 已经生成了 package.json。把 $schema 和 kunkun 字段加进这个已有的 package.json——manifest 就是 kunkun 字段本身,而不是一个单独的文件:
{
"name": "my-extension",
"version": "0.1.0",
// ...Vite 生成的 scripts/dependencies
"$schema": "https://schema.kunkun.sh/",
"kunkun": {
"identifier": "com.you.my-extension",
"name": "My Extension",
"permissions": ["clipboard-read", "clipboard-write", "storage"],
"commands": [
{
"name": "main",
"title": "My Command",
"mode": "custom-view",
"main": "/",
"dist": "dist",
"devMain": "http://localhost:5173"
}
]
}
}接入 SDK
在入口文件中先导入一次 @kunkunsh/sdk/ui/custom(在应用挂载之前),用来接通扩展与宿主的 RPC 通道;其余 API 都从 @kunkunsh/sdk 导入。
// src/main.tsx(React)/ src/main.ts(Vue、Svelte、原生)
import "@kunkunsh/sdk/ui/custom"; // 必须放在最前面
// ...照常启动应用:createRoot(el).render(<App />) / mount(App, ...) 等构建
pnpm build # 输出静态 SPA 到 `dist/`快速开始:Worker-View 扩展
Worker-View 在 Web Worker 里运行一个 React 组件;由宿主根据组件树渲染 UI,从而获得一致的样式和强隔离。
初始化
mkdir my-worker-ext && cd my-worker-ext
pnpm init && pnpm add @kunkunsh/sdk react valibot
pnpm add -D @types/react @types/bun组件 —— src/App.tsx
import { useState } from "react";
import { Button, Div, H2, P } from "@kunkunsh/sdk/ui";
import { Clipboard, showToast, Toast } from "@kunkunsh/sdk";
export default function App() {
const [text, setText] = useState("");
return (
<Div className="p-6">
<H2>My Worker Extension</H2>
<Button title="Read Clipboard" variant="primary" onClick={async () => {
setText(await Clipboard.readText());
await showToast({ title: "Read!", style: Toast.Style.Success });
}} />
<P>Content: {text}</P>
</Div>
);
}构建脚本 —— build.ts
import { dedupeReact, kunkunCommandPlugin } from "@kunkunsh/sdk/build";
import type { BunPlugin } from "bun";
await Bun.build({
entrypoints: ["./src/App.tsx"],
outdir: "./dist",
target: "browser",
format: "esm",
minify: true,
plugins: [kunkunCommandPlugin({ mode: "view" }) as BunPlugin, dedupeReact(import.meta.dir)],
});Manifest + 构建
{
"kunkun": {
"identifier": "com.you.my-worker-ext",
"name": "My Worker Extension",
"permissions": ["clipboard-read", "storage"],
"commands": [{ "name": "main", "title": "My Command", "mode": "worker-view", "main": "dist/App.js" }]
},
"scripts": { "build": "bun build.ts" }
}bun run build载入到 Kunkun
- 打开 Kunkun → Settings → Developer
- Load Extension → 选择你的扩展目录
- 对于自定义视图,运行 dev server(
pnpm dev),Kunkun 会加载devMain并启用 HMR。
发布到 npm(或 jsr),用户即可从内置扩展商店安装。
探索真实示例
仓库的 extensions/ 目录里有从最简单到进阶的可运行示例:
uuid-generator—— 最简单的无界面命令sample-headless-node/sample-headless-worker—— cron 和事件触发的后台任务ffmpeg+video-processing—— 一个服务提供方和它的消费方kkterminal/space-lens—— 完整的 CLI + 插件 案例