Create Plugin
Interactive CLI tool for creating ObjectUI plugins
Create Plugin
The @object-ui/create-plugin package is a small interactive CLI that scaffolds a new
ObjectUI plugin package. It asks a couple of questions, writes a ready-to-build package,
and prints the commands to run next. Writing those files is the whole of what it does: it
installs no dependencies and initialises no git repository.
Installation
npm install -g @object-ui/create-pluginOr use with npx (recommended — nothing to install, and you always get the published version):
npx @object-ui/create-plugin my-pluginQuick Start
Run it from the root of a pnpm workspace. The new package is written to
packages/plugin-<name> relative to the current directory, and what it writes is
built for a workspace: it depends on the @object-ui packages through workspace:*
links, and its tsconfig.json extends the one two directories above it. Run the
generator anywhere else and you get a package whose dependencies and TypeScript config
resolve to nothing.
cd my-workspace
npx @object-ui/create-plugin awesomeThe CLI validates the name you gave it — lowercase letters, digits and hyphens only, no
scopes and no path separators — and then cleans it up: a leading plugin- is stripped, so
awesome and plugin-awesome mean the same thing. From the cleaned name it derives,
without asking:
- the directory it writes into,
packages/plugin-<name>; - the package name,
@object-ui/plugin-<name>; - the
typekey the plugin registers itself under in the Component Registry — the cleaned name itself, soawesomein the example above; - the PascalCase component name, and the name of the file implementing it.
One name decides all four, so pick it with all four in mind. Everything else — a
description and an author — is asked interactively with a default filled in. The
--description and --author options pre-fill those prompts rather than skip them;
run npx @object-ui/create-plugin --help for the options it accepts today.
What It Generates
This page deliberately does not reproduce the generated tree or the generated files.
Run the generator and read what it wrote — and when you need the answer without running
it, read the one function that decides it:
buildPluginFiles() in packages/create-plugin/src/templates.ts.
That map of path to file contents is the single source of truth for what a scaffolded
plugin contains; the CLI in src/index.ts is the loop that writes it to disk.
Two things are worth knowing before you look:
- It scaffolds a library, not an app. The generated Vite config is a
build.libconfig emitting an ES and a UMD bundle intodist/. There is no application to serve, so there is no dev server to start — see Development Workflow. - Its dependency ranges are not listed here on purpose. They live in that one
template literal, and
packages/create-plugin/src/__tests__/templates.test.tsanchors the generateddevDependenciesto this repository's own declarations, so the scaffold cannot drift away from the toolchain it is part of. Reading the literal is the only way to see what your scaffold will actually contain; a range copied onto this page would be the first thing to go stale.
Development Workflow
When the generator finishes it prints the next steps for the package it just wrote —
follow those. Inside the new package, pnpm run lists the scripts it actually has. Two
notes on what to expect from them:
- There is no dev server, and no
devscript to run one. A library build has no app to serve. Iterate either by building the plugin and reloading the app that consumes it, or — the way this repository develops its own plugins — by pointing the consuming app's Viteresolve.aliasat your plugin'ssrc, so your sources become part of that app's dev server. The Runner documents that alias table, including the transitive-closure rule that makes it work. - Tests are green on a fresh scaffold, and are meant to stay that way. The generator
writes an example test together with the Vitest setup file its config points at, and
templates.test.tspins those pieces to each other: the test stack is declared, the environment is a DOM, the setup file exists. If the first test run in a freshly scaffolded plugin is red, that is a bug in the generator rather than in your machine — please file it.
To use the plugin from an app in the same workspace, add it as a workspace:* dependency
and import the package for its side effect: importing it is what registers the component,
which is what makes its type key usable in a schema. See
Plugin Concepts.
To publish it, use pnpm publish. pnpm rewrites the workspace:* links into real ranges
as it packs; a plain npm publish would ship the literal workspace:* and the resulting
tarball is uninstallable.
Configuration
There is none beyond the command line. The generator reads no configuration file — there
is no .create-plugin.config.js and no template directory to point it at. Everything it
can be told, it is told through the plugin-name argument and the options --help lists.
Plugin Naming Conventions
- Package name:
@object-ui/plugin-<name>— the CLI composes it, you only choose<name>. - Schema
typekey:kebab-case, the cleaned plugin name. - Component name:
PascalCase, derived from the same name.
Best Practices
Advice for the plugin you are about to write, beyond whatever the scaffold hands you:
-
Lazy-load heavy dependencies.
@object-ui/plugin-*is the layer where heavy third-party libraries are allowed to live, which makes it the layer that most needs aReact.lazyboundary, so an app that never renders your component never pays for it:const HeavyImpl = React.lazy(() => import('./HeavyImpl')); -
Give that boundary a real fallback. A
Skeletonshaped like the component beats a bare spinner: the layout does not jump when the chunk arrives. -
Export your schema types. The schema interface is the contract between a metadata author and your renderer, so make it importable rather than internal.
-
Treat the registry key as public. The
typeyou register appears in every schema that uses your plugin, so renaming it is a breaking change for metadata already stored.
Example Plugins
See these official plugins for reference:
- @object-ui/plugin-charts - Data visualization
- @object-ui/plugin-kanban - Kanban boards
- @object-ui/plugin-editor - Code editor
Package Information
Package Name: @object-ui/create-plugin — published on npm, see the
npm page for the current version
Binary: create-plugin
License: MIT
Troubleshooting
It stopped because the directory already exists. The generator never writes into an existing directory. Pick another name, or remove the old package first.
The name was rejected. Only lowercase letters, digits and hyphens are accepted; a
scope, a slash or a .. is refused. The validation is at the top of
src/index.ts.
The new package's imports and tsconfig.json resolve to nothing. The generator was
almost certainly run outside a workspace root — see Quick Start. Move the
package into a real workspace's packages/ directory, or re-run the generator from
there.
Permission denied installing globally. Use npx instead of npm install -g; it needs
no write access outside the npm cache.
Next Steps
- Plugin Concepts - Learn how plugins work
- Plugin Development Guide - The full authoring guide
- Component Registry - Register components
- CLI - Test your plugin with the CLI