Ecosystem ↗

7. Turn a feature into a plugin

Register a small capability against the runtime API and identify its lifecycle owner.

↗ View Markdown
LESSON 7 OF 818 min + practice · Develop
  • Register with the generation-scoped plugin API
  • Identify resource ownership
  • Keep a reusable module independent of site settings

Your goal#

Add a route from a plugin, without starting a background service when a file is imported. Then explain how a reusable module differs from its host application.

Register during application preparation#

plugins/status.ts
import type { ZeruxPluginApi } from 'zeruxjs';

/** Register a small public feature. @param api Generation-scoped runtime API. @returns Nothing. No global state, environment reads, timers or I/O. */
export default function register(api: ZeruxPluginApi): void {
  api.addRoute({
    pattern: '/feature-status', method: 'GET',
    handler: () => ({ feature: 'status', enabled: true }),
  });
}

Use the default plugin directory or configure structure.plugins explicitly. Start the application and inspect /feature-status using the printed server URL. Plugin registration runs while preparing a runtime generation; it is not a request handler called for every visitor.

Expected result: the route returns the named feature. Importing the package should not open a database, start an interval or choose a global user language.

Keep owned resources owned#

A runtime generation is one prepared set of application resources. Development reloads may prepare a replacement generation. Unowned global timers, subscriptions or pools can outlive the code that created them and multiply across reloads.

Use managed startup workers/services for long-lived work, with explicit cleanup. Startup workers may return cleanup; ordinary plugin registration is not a general returned-disposer hook. See workers and service lifecycle before adding a listener or connection.

Share a contract, not a global application#

A module can expose pure message functions or a registration function that receives the plugin API and a host-owned translator. The host chooses settings and request policy. Do not assume a nonexistent i18n managed service or reach into another package's private src files.

Use public export-map imports and document actual TypeScript parameters. A module path is not a permission boundary: plugin code is trusted application code, so review its dependencies and side effects.

Add a small verification habit#

Start with the public status route. Verify its path and response. Reload the application and ensure it does not multiply work. When adding a worker, verify cleanup and failed-startup behavior separately. Do not return an internal config/environment object as a health response.

Try it yourself#

Change the plugin route's response to include a second public field. Verify it survives a reload. List every resource your plugin owns; for this example the list contains only registration, with no timer/connection to clean up. Explain who would own a catalog loader or request-context facade if you added localization.

You are done when: you can distinguish plugin startup from request execution and explain the lifetime of everything you create.

PUT IT INTO PRACTICE

Check your understanding

Try the exercise above, then answer both questions. Each correct answer earns 10 local learning points, once. You can retry; all lessons stay open.

Who should own a long-lived timer started by a feature?

Explain the answer

A generation/worker owner with an explicit cleanup. Managed startup workers can return cleanup. Import-time timers can leak across reloads and application instances.

Who chooses the site’s active language?

Explain the answer

The host application using its validated policy. A module owns its domain/messages/catalogs; the host owns locale choice, persistence and request policy.

Implementation sources

Implementation files for the APIs described on this page.

ZeruxJS · Open source · MIT OR Apache-2.0

Make yourself at home.

Every shortcut has a visible control too. Reading and navigation work without JavaScript.

Ctrl / ⌘ K
Search all documentation
/
Search, outside editable fields
?
This help, outside editable fields
↑ / ↓
Move through search results
Esc
Close a dialog or version menu
Progress, privacy, offline reading and controls →

Reset this learning record?

This removes course answers, exercise confirmations, bookmarks and recent pages for this docs version in this browser. Export a copy first if you want to keep it.

Search documentation

Type at least two characters.