Lifecycle & Structure
This chapter describes third-party plugin runtime rules and data flow.
1) How Breeze Calls Plugins
- Breeze loads the plugin bundle
- Breeze finds the function by
fnPath - Breeze passes arguments to that function
- Breeze renders the returned data
Core rule: fnPath must match a key on export default.
2) Payload Model
When Breeze calls a plugin, the common input model is:
type PluginPayload<T extends Record<string, unknown>> = T & {
extern?: Record<string, unknown>;
};
Recommended conventions:
- Primary business fields (e.g.
comicId/page/keyword) at the top level - Session / context passthrough in
extern
3) Return Model
Most APIs may return:
type PluginEnvelope = {
source: string;
scheme?: Record<string, unknown>;
data?: Record<string, unknown>;
extern?: Record<string, unknown>;
};
Notes:
source: plugin IDscheme: page render protocol (optional)data: business dataextern: passthrough context. The host stores returnedexternand sends it back on the next request
4) Runtime API
Breeze plugins run in the QuickJS-NG engine — not Node.js and not a browser.
Available globals (fetch, bridge, crypto, Temporal, console, etc.) are documented in Runtime API.
5) Debugging & State
In debug mode, when the bundle file changes the host recreates the QJS instance.
That means:
- In-memory plugin state is not preserved
- Module-level variables reinitialize
Store data by lifetime:
- Short-lived data in
cache(lives with the host process; survives QuickJS rebuilds) - Long-lived data in
config(survives app restarts)
Both are provided by breeze-plugin-kit; see breeze-plugin-kit Toolkit.
6) Compatibility
- Prefer backward-compatible API additions
- Provide defaults for optional fields
7) Common Pitfalls
QJS Instance Rebuild
In debug mode every bundle change rebuilds the QJS instance. That means:
- Top-level module code (other than
export default) re-runs each time initis called again- Do not rely on module-level variables for state
getInfo Changes Require Reinstall
The function entry list from getInfo() is read once when the plugin loads. After changes you need to:
- Restart the app, or
- Uninstall and reinstall the plugin
Hot reload does not re-read getInfo.
Single-File Bundle
Build output is a single .cjs file; all dependencies must be bundled by Rspack. No runtime npm external dependencies.
bridge.callSync Limits
Sync calls block the host thread and are only for very short work. Do not perform network I/O or file I/O inside bridge.callSync.
extern Round-Trip
extern returned by the plugin is stored by the host and sent back on the next request in the same context. Use it for pagination tokens, session state, and similar context.
ImageItem.url Rules
ImageItem has a url field, and fetchImageBytes receives that url, but the host does not download images via url — downloading is entirely handled by the plugin in fetchImageBytes.
That does not mean url can be arbitrary. It must not be a 404 URL or empty string; it must be a valid-format placeholder (e.g. "https://example.com/placeholder.jpg"), or the host will refuse to render.