The Rust framework for the modern web

fn index_page<G: Html>(cx: Scope, state: &IndexStateRx) -> View<G> {
    view! { cx,
        h1 { (format!(
            "Hello, {}!",
            state.name.get()
        )) }
        input(
            placeholder = "Name",
            bind:value = state.name
        )
        a(href = "about") { "About" }
    }
}

#[derive(Serialize, Deserialize, Clone, ReactiveState)]
#[rx(alias = "IndexStateRx")]
struct IndexState {
    name: String,
}

// This function will be run when you build your app, to generate default state
// ahead-of-time
#[engine_only_fn]
async fn get_build_state(_info: StateGeneratorInfo<()>) -> IndexState {
    IndexState {
        name: "User".to_string(),
    }
}

Generate state, on your terms

Perseus apps can generate state whenever they like and pass it to Sycamore, one of the fastest web frameworks in the world.

fn post_page<G: Html>(cx: Scope, state: &PostRx) -> View<G> {
    view! { cx,
        h1 { (state.title.get()) }
        p { (state.author.get()) }
        div(
            dangerously_set_inner_html = &state.content.get()
        )
    }
}

// ...

// This function will be run for each path under `/post/` to generate its state
#[engine_only_fn]
async fn get_build_state(
    StateGeneratorInfo { path, .. }: StateGeneratorInfo<()>,
) -> Result<Post, BlamedError<MyError>> {
    let raw_post = match get_post_for_path(path) {
        Ok(post) => post,
        // If the user sends us some bogus path with incremental generation,
        // return a 404 appropriately
        Err(err) => {
            return Err(BlamedError {
                blame: ErrorBlame::Client(Some(404)),
                error: MyError(err),
            })
        }
    };
    let html_content = parse_markdown(raw_post.content);
    let post = Post {
        title: raw_post.title,
        author: raw_post.author,
        content: html_content,
    };
    Ok(post)
}
#[engine_only_fn]
async fn get_build_paths() -> BuildPaths {
    BuildPaths {
        // These will all become URLs at `/post/<name>`
        paths: vec![
            "welcome".to_string(),
            "really-popular-post".to_string(),
            "foobar".to_string(),
        ],
        // Perseus supports helper state, but we don't need it here
        extra: ().into(),
    }
}
I18nInternationalization
that just works

Just add translations using Fluent, and your app can be set up in seconds in multiple languages, with automatic user locale detection.

.locales_and_translations_manager(
            "en-US",             // Default locale
            &["fr-FR", "es-ES"], // Other supported locales
        )

// ...

// Our landing page. Going to `/` will cause a redirect to `/en-US`,
// `/es-ES`, or `/fr-FR` based on the user's locale settings in their browser,
// all automatically. If nothing matches, the default locale (`en-US`) will be
// used.
fn index_page<G: Html>(cx: Scope) -> View<G> {
    view! { cx,
        h1 { (t!(cx, "greeting")) }
    }
}

// `translations/en-US.ftl`:
//      greeting = Hello, world!
// `translations/es-ES.ftl`:
//      greeting = Β‘Hola, mundo!
// `translations/fr-FR.ftl`:
//      greeting = Bonjour, le monde!

You want options? We got options.

Perseus comes with a built-in plugins system and full customizability of almost every part of the system. Static exporting? Serverful deployment? Fetch data by carrier pigeon? Easy.

# 🚩 Get ready!
> perseus init my-app

# πŸ“¦ All static?
> perseus export -sw
[1/3] πŸ“¦ Exporting your app's pages...βœ…
[2/3] πŸ—οΈ  Building your app to Wasm...βœ…
[3/3] πŸ›°οΈ  Your exported app is now live at <http://127.0.0.1:8080>!

# πŸ“‘ Using some more advanced features?
> perseus serve -w
[1/4] πŸ”¨ Generating your app...βœ…
[2/4] πŸ—οΈ  Building your app to Wasm...βœ…
[3/4] πŸ“‘ Building server...βœ…
[4/4] πŸ›°οΈ  Your app is now live on <http://127.0.0.1:8080>! To change this, re-run this command with different settings for `--host` and `--port`.

# πŸ§ͺ Testing your app's features?
> perseus test
# πŸ”Ž Investigating some errors?
> perseus snoop wasm-build

# πŸŽ‰ Ready to send it to the world?
> perseus deploy

Fast. Crazy. Fast.

Underlying platform? Rust.
Target platform? WebAssembly.
Lighthouse scores? πŸ’―

100Performance (Desktop)
97Performance (Mobile)
100Best Practices

Get started with Perseus today!

> cargo install perseus-cli
> perseus new my-project
> perseus serve -w

# Ready to deploy?
> perseus deploy
# And send `pkg/` to your server! πŸ₯³