This version of the documentation is outdated, and features documented here may work differently now. You can see the latest stable version of the docs here.
What is Perseus?
If you're familiar with NextJS, Perseus is that for Wasm. If you're familiar with SvelteKit, it's that for Sycamore.
If none of that makes any sense, this is the section for you! If you're not in the mood for a lecture, there's a TL;DR at the bottom of this page!
Rust web development
Rust is an extremely powerful programming language, but I'll leave the introduction of it to its developers.
WebAssembly (abbreviated Wasm) is like a low-level programming language for your browser. This is revolutionary, because it allows websites and web apps to be built in programming languages other than JavaScript. Also, it's really fast (usually >30% faster than JS).
But developing directly for the web with Rust using something like web-sys
isn't a great experience, it's generally agreed in the web development community that developer experience and productivity are vastly improved by having a reactive framework. Let's approach this from a traditional JavaScript and HTML perspective first.
Imagine you want to create a simple counter. Here's how you might do it in a non-reactive framework (again, JS and HTML here, no Rust yet):
<p id="counter">0</p>
<br />
<button
onclick="document.getElementById('counter').innerHTML = parseInt(document.getElementById('counter').innerHTML) + 1"
>
Increment
</button>
If you're unfamiliar with HTML and JS, don't worry. All this does is create a paragraph with a number inside and then increment it. But the problem is clear in terms of expression: why can't we just put a variable in the paragraph and have that re-render when we increment that variable? Well, that's reactivity!
In JS, there are frameworks like Svelte and ReactJS that solve this problem, but they're all bound significantly by the language itself. JavaScript is slow, dynamically typed, and a bit of a mess. Like all things to do with the web, changing things is really difficult because people have already started using them, and there will always be someone still using Internet Explorer, which supports almost no modern web standards at all.
Wasm solves all these problems by creating a unified format that other programming languages, like Rust, can compile into for the browser environment. This makes websites safer, faster, and development more productive. The equivalent of these reactive frameworks for Rust in particular would be projects like Sycamore, Seed, and Yew. Sycamore is the most extensible and low-level of those options, and it's more performant because it doesn't use a virtual DOM (link about JS rather than Rust), and so it was chosen to be the backbone of Perseus. Here's what that counter might look like in Sycamore (the incrementation has been moved into a new closure for convenience):
use sycamore::prelude::*;
let counter = Signal::new(0);
let increment = cloned!((counter) => move |_| counter.set(*counter.get() + 1));
view! {
p { (counter.get()) }
button(on:click = increment) { "Increment" }
}
You can learn more about Sycamore's amazing systems here.
This sounds good...
But there's a catch to all this: rendering. With all these approaches in Rust so far (except for a few mentioned later), all your pages are rendered in the user's browser. That means your users have to download your Wasm code and run it before they see anything at all on their screens. Not only does that increase your loading time (which can drive away users), it reduces your search engine rankings as well.
This can be solved through server-side rendering (SSR), which means that we render pages on the server and send them to the client, which means your users see something very quickly, and then it becomes interactive (usable) a moment later. This is better for user retention (shorter loading times) and SEO (search engine optimization).
The traditional approach to SSR is to wait for a request for a particular page (say /about
), and then render it on the server and send that to the client. This is what Seed (an alternative to Perseus) does. However, this means that your website's time to first byte (TTFB) is slower, because the user won't even get anything from the server until it has finished rendering. In times of high load, that can drive loading times up worryingly.
The solution to this is static site generation (SSG), whereby your pages are rendered at build time, and they can be served almost instantly on any request. This approach is fantastic, and thus far widely unimplemented in Rust. The downside to this is that you don't get as much flexibility, because you have to render everything at build time. That means you don't have access to any user credentials or anything else like that. Every page you render statically has to be the same for every user.
Perseus supports SSR and SSG out of the box, along with the ability to use both on the same page, rebuild pages after a certain period of time (e.g. to update a list of blog posts every 24 hours) or based on certain conditions (e.g. if the hash of a file has changed), or even to statically build pages on demand (the first request is SSR, all the rest are SSG), meaning you can get the best of every world and faster build times.
To our knowledge, the only other framework in the world right now that supports this feature set is NextJS (with growing competition from GatsbyJS), which only works with JavaScript. Perseus goes above and beyond this for Wasm by supporting whole new combinations of rendering options not previously available, allowing you to create optimized websites and web apps extremely efficiently.
How fast is it?
Benchmarks show that Sycamore is slightly faster than Svelte in places, one of the fastest JS frameworks ever. Perseus uses it and Actix Web or Warp (either is supported), some of the fastest web servers in the world. Essentially, Perseus is built on the fastest tech and is itself made to be fast.
The speed of web frameworks is often measured by Lighthouse scores, which are scores out of 100 (higher is better) that measure a whole host of things, like total blocking time, first contentful paint, and time to interactive. These are then aggregated into a final score and grouped into three brackets: 0-49 (slow), 50-89 (medium), and 90-100 (fast). This website, which is built with Perseus, using static exporting and size optimizations, consistently scores a 100 on desktop and above 90 for mobile. You can see this for yourself here on Google's PageSpeed Insights tool. The only issue that prevents Perseus from achieving a consistent perfect score on mobile is total blocking time, which measures the time between when the first content appears on the page and when that content is interactive. Of course, WebAssembly code is used for this part (compiled from Rust), which isn't completely optimized for yet on many mobile devices. As mobile browsers get better at parsing WebAssembly, TBT will likely decrease further from the medium range to the green range (which we see for more powerful desktop systems).Why not 100 on mobile?
If you're interested in seeing how Perseus compares on speed and a number of other features to other frameworks, check out the comparisons page.
How convenient is it?
Perseus aims to be more convenient than any other Rust web framework by taking an approach similar to that of ReactJS. Perseus itself is an extremely complex system consisting of many moving parts that can all be brought together to create something amazing, but the vast majority of apps don't need all that customizability, so we built a command-line interface (CLI) that handles all that complexity for you, allowing you to focus entirely on your app's code.
Basically, here's your workflow:
- Create a new project.
- Define your app in around 12 lines of code and some listing.
- Code your amazing app.
- Run
perseus serve
.
How stable is it?
Perseus is considered reasonably stable at this point, though it still can't be recommended for production usage just yet. That said, this very website is built entirely with Perseus and Sycamore, and it works pretty well!
For now though, Perseus is perfect for anything that doesn't face the wider internet, like internal tools, personal projects, or the like. Just don't use it to run a nuclear power plant, okay?
Summary
If all that was way too long, here's a quick summary of what Perseus does and why it's useful!
- JS is slow and a bit of a mess, Wasm lets you run most programing languages, like Rust, in the browser, and is really fast
- Doing web development without reactivity is really annoying, so Sycamore is great
- Perseus lets you render your app on the server, making the client's experience really fast, and adds a ton of features to make that possible, convenient, and productive (even for really complicated apps)