Capsules
Capsules are one of the most powerful features of Perseus, and, if you learn to use them, you can build some phenomenal apps extremely efficiently, taking maximum advantage of Perseus' advanced state platform.
Remember how template + state = page? Well, similarly capsule + state = widget. Widgets are very similar to other pages, except they don't have <head>
s, and they don't take up the whole page. Rather, they're embedded by other pages as, well, widgets. As widgets are to pages, capsules are to templates: a single capsule can generate many widgets, and has full access to the Perseus state platform.
The reason capsules are useful is because they can be cached very aggressively: when Perseus loads a new page, it won't re-request capsules it already has, meaning apps that make heavy use of capsules can cut the amount of data transmitted over the network substantially!
Capsules vs. templates
Templates create pages, and capsules create widgets, but the major differences between them are how they handle errors, how they're displayed, and how they're requested. On an initial load (when a user comes to your site from somewhere else on the internet), Perseus will send your page, together with all its capsules, down to the browser as one great big HTML file, containing all the states necessary. When Perseus starts up, it will aggressively cache those widgets and link them to the page, so that, if that page is ever dropped from the internal cache, those widgets will be too (provided they're not being used by any other pages). When a user goes to another page in your app (using the subsequent load system), Perseus will send down only the state of the new page, and the client will then request all the widgets. This can lead to much faster page loads: most of the content of the page is sent down straight away, but the widgets are loaded separately (but all in parallel). While they're loading, you can specify a fallback state for each one, which might be a skeleton (those pulsating bars that indicate "there will be text here soon"), or a simple loading icon, or anything else you can dream up.
Naturally, widgets occupy a much smaller amount of space on the page than pages, because they're embedded in them. To get a feel for when you might use widgets, let's imagine a blog whose posts can be organized into series (the same example was used when explaining helper state). You don't really want to be re-hashing the same series on every page that's in that series, so it might be a better idea to have separate pages for the series, but you really want them to be displayed on the pages that are a part of the series...so make them widgets! If you create a series
capsule, and then embed the widgets from it on the respective pages, you get the best of both worlds.
By now, you're probably thinking capsules are basically Sycamore components, just with access to the Perseus state platform, and you'd be right! (Though internally, they're more similar to pages than components.) In fact, capsule view functions take not only a Sycamore scope and their state, but also their properties, which are static objects provided by the caller that can have an arbitrary effect. Since capsules are only prerendered in the context of pages, this poses no issue for hydration.
Let's take an example of where capsules might be really useful. Let's say you have an e-commerce website with a page for each product, and a carousel on each product page of "similar products", or "people also bought", etc. If you made your products widgets insstead of pages, and then creates pages whose only duty is to display one widget for the main item and a number of other widgets for the carousel, you could do this almost effortlessly. Further, the caching benefits would be extraordinary: going to the page of product A, which has a carousel with products X, Y, and Z, would mean that, if the user later went to the page of product X, Y, or Z, they would load instantly --- literally instantly. And the dimensions of each product widget can be controlled using properties. That is the power of capsules. You could even have capsules show up in search bar suggestions, thereeby implicitly preloading anything the user searches for, while combining this with incremental generation to ensure fast build times.
As you can imagine, combining capsules with other Perseus features leads to some insanely cool development patterns, which have thus far been totally unexplored, because no other framework supports capsules to the extent that Perseus does, and certainly not with our levels of caching.