Section: Plugins Order: 210 # Compiled plugins A quick `.js` plugin (see [Plugin system](/docs/plugins/)) is great for small things. For anything substantial — real components with state and hooks — build the plugin like a normal project and compile it down to **one droppable file**: a compiled, externalized-React plugin model. ## The trick: externalize React The output bundle must **not** carry its own copy of React. Two React instances on one page break hooks ("invalid hook call"). Instead, mark `react`, `react-dom` and `react/jsx-runtime` **external** and map them to Orbit's globals, so your plugin shares the host's single React instance: | Module | Maps to | |---|---| | `react` | `Orbit.React` | | `react-dom` | `Orbit.ReactDOM` | | `react/jsx-runtime` | `Orbit.jsxRuntime` | Because your component is created with Orbit's React and rendered through a slot into Orbit's tree, **hooks, state, context and effects all work**. ## Vite config ```ts import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { lib: { entry: 'src/index.tsx', formats: ['iife'], name: 'MyOrbitPlugin', fileName: () => 'my-plugin.js' }, rollupOptions: { external: ['react', 'react-dom', 'react/jsx-runtime'], output: { globals: { react: 'Orbit.React', 'react-dom': 'Orbit.ReactDOM', 'react/jsx-runtime': 'Orbit.jsxRuntime', } }, }, }, }); ``` ## Write normal TSX ```tsx import { useState } from 'react'; Orbit.plugin('my-plugin', (orbit) => { orbit.addUi('composer_button', () => ); orbit.addSettingsSection({ label: 'My plugin', icon: '🧩', render: () => , }); }); function Panel({ orbit }) { const [count, setCount] = useState(() => orbit.storage.get('count', 0)); const bump = () => { const n = count + 1; setCount(n); orbit.storage.set('count', n); }; return (
Compiled plugin — real React with hooks. You are {orbit.state.nick()}.
); } ``` The compiled bundle is tiny — it contains only your code, calling Orbit's React. ## Starter template A ready-to-copy starter (Vite config with the externals set up, `tsconfig`, ambient types and a working example) lives in the repo at [`plugin-template/`](https://codeberg.org/reversefr/orbit/src/branch/main/plugin-template). ```bash git clone https://codeberg.org/reversefr/orbit.git cd orbit/plugin-template npm install npm run build # → dist/orbit-plugin-template.js ``` ## Deploy 1. Copy the built `.js` to where Orbit can fetch it (e.g. `/app/plugins/`). 2. List it in the deployed `config.json` — no rebuild of Orbit needed: ```json { "plugins": ["/app/plugins/my-plugin.js"] } ``` 3. Reload. Your composer button and Settings section appear.