OWD apps use two different Nuxt plugin layers. Confusing them is a common source of “app never registered” or “launch runs before register” bugs.
| Type | Location | Shipped in npm? | Purpose |
|---|---|---|---|
| Register | src/runtime/plugin.ts | Yes | Calls defineDesktopApp — makes the app exist in useApplicationManager. |
| Launch (dev) | playground/app/plugins/launch-*.client.ts | No | Opens a window automatically in the playground for faster iteration. |
sequenceDiagram
participant Core as @owdproject/core
participant Reg as desktop-app-slug-register
participant Launch as launch-slug.client
participant AM as ApplicationManager
Core->>Reg: Nuxt plugin boot client
Reg->>AM: defineDesktopApp config
Launch->>Reg: dependsOn ordering
Launch->>AM: autoStartPlaygroundApps after app:mounted
src/runtime/plugin.ts)Added via addPlugin in your module’s setup. Rules enforced by desktop validate:
defineDesktopApp.name: 'desktop-<slug>-register' — slug matches your package (e.g. desktop-app-about-register for app-about).if (import.meta.server) return — registration is client-only.export default defineNuxtPlugin({
name: 'desktop-app-about-register',
async setup() {
if (import.meta.server) return
await defineDesktopApp(config)
},
})
Import defineDesktopApp from @owdproject/core/kit/defineDesktopApp.
app:created?Older examples wrapped registration in nuxtApp.hook('app:created', ...). Current reference apps and the validator expect direct client-side registration. The register plugin runs during Nuxt plugin initialization on the client bundle.
Optional but recommended for dev and GitHub Pages. Filename pattern: launch-<slug>.client.ts.
export default defineNuxtPlugin({
name: 'app-about-playground-launch',
dependsOn: ['desktop-app-about-register'],
setup(nuxtApp) {
autoStartPlaygroundApps(nuxtApp, [
{ id: 'org.owdproject.about', entry: 'about', windowModel: 'main' },
])
},
})
dependsOnMust list the exact register plugin name (desktop-app-about-register). Without it, launch may run before defineDesktopApp completes.
autoStartPlaygroundAppsUse the helper from @owdproject/core (auto-imported in playground). It:
execAppCommand with the entry stringThe entry field is the raw command string (e.g. 'about' or 'youtube --new --no-check'), not just the entries map key.
import.meta.devDo not guard launch with if (!import.meta.dev) return. GitHub Pages runs nuxt generate — the same auto-start path must work there.
Reference: app-about launch plugin.
module.tsOnly the register plugin belongs in the published module:
addPlugin(resolve('./runtime/plugin'))
Do not add playground launch plugins from module.ts — keep them in playground/app/plugins/ so Nuxt auto-discovers them in the playground app root.
You can add additional runtime plugins under src/runtime/plugins/ if the app needs shared client setup (rare). Register them the same way:
addPlugin({ src: resolve('./runtime/plugins/10.my-setup.client.ts'), mode: 'client' })
Use numeric prefixes (10., 20.) when order matters relative to other plugins.
desktop validate . on an app repo reports:
| Check | Severity |
|---|---|
Missing src/runtime/plugin.ts | error |
No defineDesktopApp | error |
Wrong plugin name pattern (desktop-*-register) | error |
Legacy owd-*-register name | error |
Duplicate runtime/ + src/runtime/ | error |
| Missing server guard | warning |
import.meta.dev in launch plugin | warning |
Launch without autoStartPlaygroundApps | warning |
Hardcoded position in app.config | warning |
| Missing launch plugin | warning (optional) |
Full list: core PLAYGROUND.md.