Architecture Overview
Ecopages is designed to be modular, with thin runtime hosts, app-owned core services, and multiple rendering engines. This guide provides a brief overview of how things connect under the hood.
Ownership Model
Ecopages is structured around four main ownership layers:
- Core owns orchestration: config finalization, build manifest assembly, server loading, browser bundling coordination, and development invalidation policy.
- Integrations own framework semantics: rendering, hydration behavior, framework-specific HMR, and cross-integration ownership policy.
- Processors own asset semantics: asset transformation, emitted files, asset-specific caching, and processor-specific watch behavior.
- Adapters own transport: Bun and Node hosts receive requests, wire runtime-specific server details, and delegate into the shared core pipeline.
Packages declare contributions. Core decides lifecycle ordering and assembles the app-owned runtime/build state.
Request Lifecycle
When a request hits your Ecopages application, it follows this simplified flow:
- Runtime Host: the active Bun or Node adapter receives the HTTP request and passes it into the shared core request pipeline.
- Router: The router matching logic identifies if the path corresponds to a static file, an API route, or a page file in
src/pages. - Route Resolver: If it's a page, Ecopages determines which integration handles the file extension (e.g., KitaJS for
.kita.tsx). - Integration Renderer: The specific renderer (React, Lit, etc.) is invoked with the page component and props.
- Template Composition: The page content is wrapped in the specified
HtmlTemplate,Head, andSeoincludes. - Response: The final HTML (or JSON for APIs) is sent back to the client.
Plugin Lifecycle
The integration and processor lifecycle is split into stable framework-owned phases.
- Config finalization:
ConfigBuilder.build()validates registrations, initializes processor context, validates runtime capability declarations, collects build contributions, and seals the app-owned build manifest. - Build contribution preparation: processors run
prepareBuildContributions()before integrations so asset-side contributions are collected before framework-specific additions. - App startup setup: processors run
setup()before integrations, and integrations receive runtime origin and HMR manager context before request handling begins. - Request-time rendering: core selects the route and owning integration, then the integration renderer produces the response body.
- Development invalidation and HMR: core classifies file changes, processors handle owned watch paths, and integrations participate through HMR strategies.
See the dedicated Plugin Lifecycle guide for the exact ordering and boundaries.
Build and bundling
Core uses Rolldown as the default bundled backend. Browser and server artifacts are produced through the build adapter; optional Vite host integration delegates dev-server orchestration to Vite. See Build and Host.
Core Modules
For those wishing to dive deeper, we recommend exploring the source code:
createApp: Recommended runtime entrypoint; selects Bun or Node adapter.SharedServerAdapter: The core server logic shared across environments.BunServerAdapter: Handles the low-level Bun server interface.NodeServerAdapter: Handles the low-level Node server interface.IntegrationPlugin: The base class for all templating integrations.Processor: The asset-processing boundary for file capabilities, transformation, and watch behavior.ConfigBuilder: Validates and constructs your application state.
Server Loading Boundary
Server startup and server-side module execution are owned by core through the ServerLoader boundary, not by individual integrations or runtime hosts. Runtime hosts stay transport-oriented: they hand off startup, while core owns config loading, app loading, and invalidation behavior behind the server loader implementation.
Design Philosophy
- Minimal Configuration: Sensible defaults for structure and asset loading, with a simple config file to override them.
- Explicit Dependencies: Components declare their own scripts and styles, preventing global bloat.
- Hybrid by Choice: Optimization for static builds while maintaining full server capabilities.