Skip to content
This repository was archived by the owner on Apr 3, 2026. It is now read-only.
This repository was archived by the owner on Apr 3, 2026. It is now read-only.

chore: decouple VTZ-specific code from runtime via plugin hooks #66

@viniciusdacal

Description

@viniciusdacal

Description

The runtime crate has a well-designed plugin trait (plugin/mod.rs) that controls compilation, HMR strategy, root element ID, and more. However, ~5,000 LOC of VTZ-framework-specific code bypasses the plugin architecture and is hardcoded directly into the server and SSR modules.

This coupling means:

  • The runtime can't cleanly serve other frameworks (React plugin exists but SSR/server assume VTZ patterns)
  • Testing is harder — you can't test SSR or server behavior without VTZ-specific globals
  • Adding new framework plugins requires working around hardcoded VTZ assumptions

What's Already Pluggable

  • Compilation (plugin.compile())
  • Post-processing (plugin.post_process())
  • Import resolution (plugin.resolve_import())
  • HMR strategy (plugin.hmr_strategy())
  • Root element ID (plugin.root_element_id())
  • Watch extensions, restart triggers, env prefixes
  • Fast Refresh support (plugin.supports_fast_refresh())

What's Hardcoded to VTZ

SSR (src/ssr/)

  • SSR entry point: render.rs looks for globalThis.__vertz_ssr_render(url) — should be a plugin hook like fn get_ssr_content(runtime) -> Result<String>
  • CSS collection: dom_shim.rs injects __vertz_inject_css / __vertz_get_collected_css — should be a plugin hook for CSS injection mechanism
  • Session injection: session.rs injects globalThis.__vertz_ssr_session — should be plugin-controlled
  • HTML attributes: html_document.rs uses data-vertz-ssr, data-vertz-theme — should come from plugin

Server (src/server/)

  • HTTP routes: http.rs hardcodes 9+ /__vertz_* route prefixes (/__vertz_hmr, /__vertz_errors, /__vertz_diagnostics, /__vertz_ai/*, /__vertz_mcp/*) — should be fn additional_routes() -> Vec<Route>
  • MCP/AI endpoints: mcp.rs (1,441 LOC) + mcp_events.rs (1,271 LOC) are VTZ-specific AI/editor features baked into core — should be an optional plugin subsystem
  • Console capture: console_log.rs exists for /__vertz_ai/console — should be opt-in

Persistent Isolate (src/runtime/persistent_isolate.rs)

  • API handler extraction: Looks for globalThis.__vertz_server_module.handler / globalThis.__vertz_api_handler — should be fn extract_api_handler(module) -> Result<Handler>
  • Fetch interceptor: Hardcoded to intercept /api/ paths — path patterns should be configurable via plugin

Proposed Plugin Hooks

trait FrameworkPlugin {
    // Existing hooks (keep as-is)...

    // New hooks to replace hardcoded VTZ logic:
    fn get_ssr_content(&self, runtime: &mut JsRuntime) -> Result<String>;
    fn css_collector_js(&self) -> Option<&str>; // JS to inject for CSS collection
    fn session_globals_js(&self, session: &Session) -> Option<String>;
    fn additional_routes(&self) -> Vec<Route>;
    fn extract_api_handler_js(&self) -> Option<&str>;
    fn fetch_intercept_patterns(&self) -> Vec<String>; // e.g., ["/api/"]
    fn html_attributes(&self) -> HtmlAttributes; // CSS tag attrs, etc.
}

Acceptance Criteria

  • SSR render function discovery goes through plugin hook
  • CSS collection mechanism is plugin-provided (not hardcoded __vertz_inject_css)
  • HTTP route registration is plugin-driven (no hardcoded /__vertz_* in core)
  • MCP/AI endpoints are opt-in via plugin, not baked into core server
  • API handler extraction pattern is plugin-defined
  • Fetch interceptor path patterns are configurable
  • HTML document attributes (data-vertz-*) come from plugin
  • Existing Vertz and React plugins updated to use new hooks
  • All existing tests continue to pass
  • Quality gates pass

Notes

This is a large refactor that should probably be broken into phases (SSR hooks first, then server routes, then MCP extraction). Each phase should be a vertical slice that keeps everything working end-to-end.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions