create-hr-plugin
v0.4.4
Published
Scaffold a HomeRunner widget plugin (vm.Script SSR + IIFE client) on @homerunner-next/widget-core
Maintainers
Readme
create-hr-plugin
Scaffold a HomeRunner widget plugin in seconds. Produces a working project (vm.Script SSR + IIFE client) wired against @homerunner-next/widget-core — the same SDK that backs first-party HomeRunner widgets.
Usage
npx create-hr-plugin my-widgetThen:
cd my-widget
npm run dev # http://localhost:3001 — live-reload dev preview
npm run build # produces dist/ + manifest.json (path-only asset URLs)Options
npx create-hr-plugin <plugin-slug> [options]| Option | Default | Notes |
| --- | --- | --- |
| --author <name> | git config user.name | Author baked into package.json and manifest.json |
| --no-install | (off) | Skip npm install — useful in CI / sandboxes |
| --help, -h | | Print usage |
The slug becomes the plugin id, the manifest widgetType, and the data attribute the IIFE binds against (data-hr-widget="plugin:<slug>").
What you get
my-widget/
├── manifest.json # Plugin manifest (register with HomeRunner)
├── package.json
├── vite.config.ts # viteHomerunnerWidget({ slug }) — externals, manifest, /w/ proxy
├── index.html # Dev preview shell
├── serve.js # Production-style preview (npm run preview)
├── scripts/
│ └── inject-schema.mjs # Pre-build: zod → JSON Schema into manifest.json
└── src/
├── index.tsx # Client IIFE — registerPlugin() + mount()
├── widget.tsx # Your React component + getInitialData()
├── ssr.ts # dehydrateState + getStaticAssets (loaded server-side via vm.Script)
├── ssr-entry.ts # SSR UMD entry barrel
├── config.ts # widgetSchema.extend() + zodToManifestSchema()
├── widget.css
└── components/ui/ # shadcn-style UI (Dialog with elevateDom, Button, Tooltip,
# Carousel, WidgetSection, WebFont, ClientOnly, ResponsiveDialogContent)The UI components live in your plugin source — they're shadcn-style (you own them, edit / restyle / replace freely). Runtime hooks (useTopLevelPortal, usePortalContainer, useShadowHost) come from @homerunner-next/widget-core/runtime and shared utils (WidgetProvider, useWidget, useTranslation, useLocaleDetection, getProxiedImageUrl, getFeedQuery, getWidgetQuery) come from @homerunner-next/widget-core/utils — both are re-exported through src/components/ui/index.ts so you only have one import path.
Registering with HomeRunner
- Host your built
dist/+manifest.jsonon a CDN, Vercel, or any static host. - Register via the HomeRunner dashboard or:
POST /api/v3/plugins { "manifest_url": "https://your-host/manifest.json" }
manifest.json ships path-only URLs (e.g. dist/<slug>.iife.js). HomeRunner resolves them against the origin of your manifest_url, so the same build works on any host.
SDK reference
See @homerunner-next/widget-core for the full SDK surface — subpath exports for runtime, utils, schema, plugin-schema, vite, urls, globals, manifest, contracts.
License
MIT
