Guides creation of Zhin plugins with lifecycle hooks, auto-loading, and hot-reload behavior. Use when developers need plugin structure, lifecycle events, or reloading details.
Use this skill to help developers scaffold and reason about Zhin plugins, including lifecycle hooks, auto-loading behavior, and hot-reload interactions.
Start with the minimal plugin entry file that uses usePlugin() so Zhin can create a plugin instance for the file:
import { usePlugin } from '@zhin.js/core'
const plugin = usePlugin()
plugin.onMounted(() => {
plugin.logger.info(`Plugin ${plugin.name} mounted`)
})
plugin.onDispose(() => {
plugin.logger.info(`Plugin ${plugin.name} disposed`)
})
usePlugin() creates (and registers) the plugin instance based on the current file path.plugin.onMounted runs after contexts are mounted and child plugins start.plugin.onDispose runs when the plugin is stopped or reloaded.In development mode (NODE_ENV=development), the core will watch plugin files and trigger reloads when they change.
plugin.onMounted(() => {
plugin.logger.debug('Plugin ready for HMR')
})
plugin.reload().plugin.stop().mounted lifecycle events fire again.If the plugin is the root plugin, reload exits the process (exit code 51) so the CLI can restart it.
Use plugin.import() to load child plugins relative to the current file:
await plugin.import('./sub-plugin/index.ts')
Notes:
plugin.features returns registered commands, components, crons, and middleware names.plugin.info() returns a nested tree of features for the plugin and its children.Use this to build "health" commands for debugging plugin loads.
usePlugin() once.onDispose to clean up timers or external connections.plugin.import() for dependent plugins.plugin.onMounted for deferred setup once contexts are ready.