Skip to main content

cvkg_cli/
webkit_server.rs

1//!
2//! WebKit Preview Server
3//! Serves the host shell and WASM bundle for app preview
4//!
5
6use axum::{Router, routing::get};
7use std::net::SocketAddr;
8use tower_http::{
9    cors::CorsLayer,
10    services::{ServeDir, ServeFile},
11};
12
13/// Configuration for the WebKit preview server.
14pub struct WebKitConfig {
15    /// Path to the WASM file to serve.
16    pub wasm_path: String,
17    /// Path to the JS glue file to serve.
18    pub js_path: String,
19    /// Directory for assets.
20    pub assets_dir: String,
21    /// Directory for static files.
22    pub static_dir: String,
23}
24
25impl Default for WebKitConfig {
26    fn default() -> Self {
27        Self {
28            wasm_path: "dist/pkg/app_bg.wasm".to_string(),
29            js_path: "dist/pkg/app.js".to_string(),
30            assets_dir: "dist/assets".to_string(),
31            static_dir: "dist/static".to_string(),
32        }
33    }
34}
35
36/// Start the WebKit preview server.
37///
38/// # Arguments
39/// * `addr` -- Socket address to bind to.
40/// * `config` -- Server configuration with paths to WASM, JS, assets, and static files.
41pub async fn start_server_with_config(
42    addr: SocketAddr,
43    config: WebKitConfig,
44) -> Result<(), Box<dyn std::error::Error>> {
45    let app = Router::new()
46        .route("/", get(serve_shell))
47        .nest_service("/app.wasm", ServeFile::new(config.wasm_path))
48        .nest_service("/app.js", ServeFile::new(config.js_path))
49        .nest_service("/assets", ServeDir::new(config.assets_dir))
50        .nest_service("/static", ServeDir::new(config.static_dir))
51        .layer(CorsLayer::permissive());
52
53    log::info!("Starting WebKit preview server on http://{}", addr);
54    let listener = tokio::net::TcpListener::bind(addr).await?;
55    axum::serve(listener, app).await?;
56
57    Ok(())
58}
59
60/// Start the WebKit preview server with default paths.
61///
62/// Uses default paths: `dist/pkg/app_bg.wasm`, `dist/pkg/app.js`, etc.
63pub async fn start_server(addr: SocketAddr) -> Result<(), Box<dyn std::error::Error>> {
64    start_server_with_config(addr, WebKitConfig::default()).await
65}
66
67async fn serve_shell() -> &'static str {
68    "<!DOCTYPE html><html><head><meta charset='utf-8'><title>CVKG Preview</title></head><body><div id='app'></div><script type='module'>import init from './app.js'; init();</script></body></html>"
69}