MCPcopy Index your code
hub / github.com/davidpdrsn/axum-live-view

github.com/davidpdrsn/axum-live-view @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
367 symbols 635 edges 29 files 51 documented · 14%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

axum-live-view

axum-live-view allows you to build rich, real-time experiences with server-rendered HTML. This is done entirely in Rust - no JavaScript or WASM needed.

Basically Phoenix LiveView but for axum.

🚨 BIG SCARY WARNING 🚨

This project is still very much work in progress. Everything is subject to change and you shouldn't use this for anything serious.

Example usage

This is what using axum-live-view looks like.

use axum::{response::IntoResponse, routing::get, Router};
use axum_live_view::{
    event_data::EventData, html, live_view::Updated, Html, LiveView, LiveViewUpgrade,
};
use serde::{Deserialize, Serialize};
use std::convert::Infallible;

#[tokio::main]
async fn main() {
    // A normal axum router...
    let app = Router::new()
        .route("/", get(root))
        // Use a precompiled and minified build of axum-live-view's JavaScript.
        // This is the easiest way to get started. Integration with bundlers
        // is of course also possible.
        .route("/assets/live-view.js", axum_live_view::precompiled_js());

    // ...that we run like any other axum app
    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

// Our handler function for `GET /`
async fn root(
    // `LiveViewUpgrade` is an extractor that accepts both regular requests and
    // WebSocket upgrade requests. If it receives a regular request it will
    // render your live view's HTML and return a regular static response. This
    // leads to good SEO and fast first paint.
    //
    // axum-live-view's JavaScript client will then call this endpoint a second
    // time to establish a WebSocket connection at which point your view will be
    // spawned in an async task. Events from the browser and HTML diffs from
    // your view will then be sent over the WebSocket connection.
    //
    // If the WebSocket connection breaks (or your view crashes) the JavaScript
    // client will call this endpoint again to establish a new connection and
    // a new instance of your view is created.
    //
    // The task running the old view automatically stops when the WebSocket is
    // closed.
    live: LiveViewUpgrade,
) -> impl IntoResponse {
    // `Counter` is our live view and we initialize it with the default values.
    let counter = Counter::default();

    live.response(|embed_live_view| {
        html! {
            <!DOCTYPE html>
            <html>
                <head>
                </head>
                <body>
                    // Embed our live view into the HTML template. This will render the
                    // view and include the HTML in the response, leading to good SEO
                    // and fast first paint.
                    { embed_live_view.embed(counter) }

                    // Load the JavaScript. This will automatically initialize live view
                    // connections.
                    <script src="https://github.com/davidpdrsn/axum-live-view/raw/main/assets/live-view.js"></script>
                </body>
            </html>
        }
    })
}

// Our live view is just a regular Rust struct...
#[derive(Default)]
struct Counter {
    count: u64,
}

// ...that implements the `LiveView` trait.
impl LiveView for Counter {
    // This is the type of update messages our HTML contains. They will be sent
    // to the view in the `update` method
    type Message = Msg;

    // Update the view based on which message it receives.
    //
    // `EventData` contains data from the event that happened in the
    // browser. This might be values of input fields or which key was pressed in
    // a keyboard event.
    fn update(
        mut self,
        msg: Msg,
        data: Option<EventData>,
    ) -> Updated<Self> {
        match msg {
            Msg::Increment => {
                self.count += 1;
            }
            Msg::Decrement => {
                if self.count > 0 {
                    self.count -= 1;
                }
            }
        }

        Updated::new(self)
    }

    // Render the live view into an HTML template. This function is called during
    // the initial render in `LiveViewManager::embed` and for each subsequent
    // update.
    //
    // The HTML is diff'ed on the server and only minimal deltas are sent over
    // the wire. The browser then builds the full HTML template and efficiently
    // updates the DOM.
    fn render(&self) -> Html<Self::Message> {
        html! {



                "Counter value: "
                // Embed dynamic Rust values into the HTML.
                //
                // `if`, `for`, and `match` are also supported.
                { self.count }







                // Elements with the `axm-click` attribute will send an update message
                // to the view which calls `update` after which the view is
                // re-rendered.
                <button axm-click={ Msg::Increment }>"+"</button>
                <button axm-click={ Msg::Decrement }>"-"</button>



        }
    }

    // The `LiveView` trait also has a `mount` method that is called when a new
    // WebSocket connects. This can be used to perform auth, load data that
    // isn't needed for the first response, and spawn a task that can send
    // messages to the view itself from other parts of the application.
}

#[derive(Serialize, Deserialize, Debug, PartialEq)]
enum Msg {
    Increment,
    Decrement,
}

Extension points exported contracts — how you extend this code

LiveView (Interface)
A server-rendered live view. This is the trait you implement to create live views. # Example ``` use axum_live_view:: [9 …
axum-live-view/src/live_view/mod.rs
NodeToTokens (Interface)
(no doc) [15 implementers]
axum-live-view-macros/src/lib.rs
LiveViewOptions (Interface)
(no doc)
assets/src/live_view.ts
DynamicFragmentVecExt (Interface)
(no doc) [1 implementers]
axum-live-view/src/html/private.rs
State (Interface)
(no doc)
assets/src/live_view.ts
StreamExt (Interface)
(no doc) [1 implementers]
axum-live-view/src/util/stream_ext.rs
Template (Interface)
(no doc)
assets/src/live_view.ts
TemplateLoop (Interface)
(no doc)
assets/src/live_view.ts

Core symbols most depended-on inside this repo

map
called by 102
axum-live-view/src/html/mod.rs
clone
called by 72
axum-live-view/src/live_view/mod.rs
with
called by 37
axum-live-view/src/live_view/mod.rs
map
called by 17
axum-live-view-macros/src/lib.rs
append
called by 15
axum-live-view-macros/src/lib.rs
on
called by 13
assets/src/live_view.ts
clone
called by 11
axum-live-view/src/life_cycle.rs
extend
called by 11
axum-live-view/src/live_view/mod.rs

Shape

Function 138
Method 114
Class 51
Enum 41
Interface 23

Languages

Rust81%
TypeScript19%

Modules by API surface

axum-live-view/src/html/tests.rs49 symbols
assets/src/live_view.ts47 symbols
axum-live-view/src/event_data.rs40 symbols
axum-live-view/src/life_cycle.rs34 symbols
axum-live-view-macros/src/lib.rs27 symbols
assets-precompiled/axum_live_view.min.js23 symbols
xtask/src/main.rs16 symbols
axum-live-view/src/live_view/mod.rs15 symbols
axum-live-view/src/test.rs13 symbols
axum-live-view/src/live_view/combine.rs12 symbols
examples/form/src/main.rs11 symbols
axum-live-view/src/js_command.rs11 symbols

For agents

$ claude mcp add axum-live-view \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact