Skip to content

Commit

Permalink
docs: fixed typos and broken example inclusions (#308)
Browse files Browse the repository at this point in the history
* fix typos

* fix some grammar

* fix broken include tags

* fix one more typo (dftl -> dflt)

* Apply suggestions from code review

Co-authored-by: Sam Brew <[email protected]>

---------

Co-authored-by: Sam Brew <[email protected]>
  • Loading branch information
iiiii7d and arctic-hen7 authored Sep 27, 2023
1 parent 800003c commit 9b8fcb5
Show file tree
Hide file tree
Showing 25 changed files with 52 additions and 52 deletions.
2 changes: 1 addition & 1 deletion docs/next/en-US/capsules/capsules-vs-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The main thing to take away from all this rendering complexity is that **the mor

## State and properties

The second big difference between capsules and components is how flexible they are. A capsule is a full-on template that can be filled in with the Perseus state platform, and then modified by some properties the calling page/widget provides, while a component just has those properties. This doesn't mean widgets are always better, it means they're a great tool *when you need state*. For example, there is absolutely no point whatsoever in making a button an independent capsule, because it doesn't need state. Any customization of it can (and should) be performed using the properties system, and therefore it shoudl be a component, not a capsule.
The second big difference between capsules and components is how flexible they are. A capsule is a full-on template that can be filled in with the Perseus state platform, and then modified by some properties the calling page/widget provides, while a component just has those properties. This doesn't mean widgets are always better, it means they're a great tool *when you need state*. For example, there is absolutely no point whatsoever in making a button an independent capsule, because it doesn't need state. Any customization of it can (and should) be performed using the properties system, and therefore it should be a component, not a capsule.

This is the reason why Perseus deliberately does not support adding Sycamore's `Children<'_>` type to the properties of a capsule, or passing through HTML properties like `class` or `style` through, since capsules are intended to be *sections of pages*, not atomic units. Despite the next version of Sycamore supporting this kind of property passthrough, Perseus *will not* support this with capsules to remove ambiguity about their purpose.

Expand Down
6 changes: 3 additions & 3 deletions docs/next/en-US/capsules/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ Capsules are one of the most powerful features of Perseus, and, if you learn to

Remember how **template + page = state**? 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 are useful 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 page, 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* (wehn 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.
Templates create page, 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](:state/helper)). 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](:fundamentals/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 duty it was to simply display one widget for the main item, plus 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.
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 instead of pages, and then creates pages whose duty it was to simply display one widget for the main item, plus 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, thereby 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.
2 changes: 1 addition & 1 deletion docs/next/en-US/capsules/using.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Using capsules in your own code involves a few steps. First, you'll want to crea

## `Capsule` vs. `Template`

When you're creating a capsule, there's a new type to get familiar with, called [`Capsule`](=prelude/struct.Capsule@perseus), which works similarly to the templates you're used to, but it's also slightly different. Basically, you want to start with a `Template`, define all your state generation stuff on there (but not your views), then pass that to `Capsule::build()` *without* alling `.build()` on it, and then specify your capsule-specific properties on `Capsule`. It's best to give an example:
When you're creating a capsule, there's a new type to get familiar with, called [`Capsule`](=prelude/struct.Capsule@perseus), which works similarly to the templates you're used to, but it's also slightly different. Basically, you want to start with a `Template`, define all your state generation stuff on there (but not your views), then pass that to `Capsule::build()` *without* calling `.build()` on it, and then specify your capsule-specific properties on `Capsule`. It's best to give an example:

```rust
{{#include ../../../examples/core/capsules/src/capsules/greeting.rs}}
Expand Down
2 changes: 1 addition & 1 deletion docs/next/en-US/first-app/defining.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn main() {

Now, this actually isn't too far off, except that running WebAssembly is a little different than you might think. Currently, there isn't really a good concept of a 'binary' Wasm program, you'll always be coding a library that some JavaScript imports and runs. In the case of Perseus apps, we use a `main.rs` file because it makes more logical sense, since Perseus handles all that nasty JS stuff behind the scenes. From your point of view, you're just writing a normal binary. However, there is something special that the client-side function has to do: it has to return a `Result<(), JsValue>`, where `JsValue` is a special type that represents *stuff* in JS-land. You can use Perseus' [`ClientReturn`](=type.ClientReturn@perseus) type alias for this, but note that Perseus actually *can't* return an error from its invocation: all errors are gracefully handled, even panics (although they will eventually propagate up as an unhandled exception in the calling JS, which is why any panics in Perseus will appear as two messages in your browser console rather than one).

Further, Perseus makes the engine and client code pretty convenient with two features (which are enabled by default): `dflt-engine`, and `client-helpers`. The first of these gives us the [`run_dftl_engine()`](=engine/fn.run_dflt_engine@perseus) function, which takes an [`EngineOperation`](=engine/enum.EngineOperation@perseus) derived from the [`get_op()`](=engine/fn.get_op@perseus) function (which just parses environment variables passed through by the CLI), a function that returns a [`PerseusApp`](=prelude/struct.PerseusAppBase) (which we'll get to), and some function to run your server.
Further, Perseus makes the engine and client code pretty convenient with two features (which are enabled by default): `dflt-engine`, and `client-helpers`. The first of these gives us the [`run_dflt_engine()`](=engine/fn.run_dflt_engine@perseus) function, which takes an [`EngineOperation`](=engine/enum.EngineOperation@perseus) derived from the [`get_op()`](=engine/fn.get_op@perseus) function (which just parses environment variables passed through by the CLI), a function that returns a [`PerseusApp`](=prelude/struct.PerseusAppBase) (which we'll get to), and some function to run your server.

As for the client-side, Perseus provides `run_client()`, which just takes a function that returns a `PerseusApp`.

Expand Down
8 changes: 4 additions & 4 deletions docs/next/en-US/first-app/deploying.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# Deploying!

Congratulations on making it through the tutorial, it's time to deploy your app! First, though, we haven't actually run it yet, so we may as well make sure it all compiles. Remember, you an always do this quickly with `perseus check`, which should give all ticks if everything's working. If not, you've probably just mistyped a variable name or something, which happens to us all. If you're having trouble, let us know [in a GitHub discussion](https://github.com/framesurge/perseus/discussions/new/choose), or [on Discord](https://discord.com/invite/GNqWYWNTdp), and we'll be happy to help! (And remember, there are no stupid questions or dumb bugs.)
Congratulations on making it through the tutorial, it's time to deploy your app! First, though, we haven't actually run it yet, so we may as well make sure it all compiles. Remember, you can always do this quickly with `perseus check`, which should give all ticks if everything's working. If not, you've probably just mistyped a variable name or something, which happens to us all. If you're having trouble, let us know [in a GitHub discussion](https://github.com/framesurge/perseus/discussions/new/choose), or [on Discord](https://discord.com/invite/GNqWYWNTdp), and we'll be happy to help! (And remember, there are no stupid questions or dumb bugs.)

When you're ready to actually run your app, you can run `perseus serve`, which will prepare everything to be run for development. When it's ready, you'll be able to see your brand-new app at <http://localhost:8080>, in all its *Hello World!* glory! If you try clicking on the link to the *About* page, you should find that the page doesn't seem to change from the browser's perspective, it just instantly updates: this is Perseus' router in action. Press the back button in your browser to pop back to the landing page, and, again, it should be near-instant (Perseus has *cached* the index page, and can return to it with no network requests needed).

<details>

<summary>I'm throttling my network connection, and Perseus seems extremely slow...</summary>

A lot of DevTools in browsers have the option to throttle your network connection, to emulate how long it would take to load a real app. If you do this with Perseus, however, it will probably take around a full minute to even load your app. You'll see content very quickly because of Perseus' preloading system, but the `bundle.wasm` file will take forever. This is because, in development, Wasm bundles are *huge*. What will optimize and compress down to the size of a small cat photo can start as a muilti-megabyte behemoth, and this is why it's usually not a good idea to throttle Perseus apps to test their load-speed. If you wait for the Wasm bundle to load though, and *then* throttle, you'll get a better idea of real-world performance (if your browser supports this).
A lot of DevTools in browsers have the option to throttle your network connection, to emulate how long it would take to load a real app. If you do this with Perseus, however, it will probably take around a full minute to even load your app. You'll see content very quickly because of Perseus' preloading system, but the `bundle.wasm` file will take forever. This is because, in development, Wasm bundles are *huge*. What will optimize and compress down to the size of a small cat photo can start as a multi-megabyte behemoth, and this is why it's usually not a good idea to throttle Perseus apps to test their load-speed. If you wait for the Wasm bundle to load though, and *then* throttle, you'll get a better idea of real-world performance (if your browser supports this).

</details>

Expand All @@ -34,7 +34,7 @@ Obviously, you probably want to host your app in production on a different addre

### Optimizations

When you deploy your Perseus app, there are two separate main binaries that are produced: the Wasm bundle, and the engine binary (the latter won't exist if you use export deployment though). What you want to do is optimize the engine binary for speed, since it's running your server, and the Wasm bundle for *size*: the reason is because Wasm is already extremely fast, and the main impediment to speed in the browser is how long it takes to load the Wasm bundle from the server. *Smaller bundle = faster load.* (But remember that this is only for making your pages interactive, the user will see content straight away!)
When you deploy your Perseus app, there are two separate main binaries that are produced: the Wasm bundle, and the engine binary (the latter won't exist if you use export deployment though). What you want to do is optimize the engine binary for speed, since it's running your server, and the Wasm bundle for *size*: the reason is that Wasm is already extremely fast, and the main impediment to speed in the browser is how long it takes to load the Wasm bundle from the server. *Smaller bundle = faster load.* (But remember that this is only for making your pages interactive, the user will see content straight away!)

Most of these optimizations are all applied automatically in `perseus deploy`, but they can be tweaked if you like by setting some of the flags on the CLI (which you can see with `perseus deploy --help`). These will allow you to apply different optimization settings to suit your needs.

Expand All @@ -48,6 +48,6 @@ However, there's actually a simpler way of deploying this app in particular. Bec

## Closing words

With all that, you've successfully built and deployed your first ever Perseus app: well done! If you're liking Perseus so far, you can check out the rest of the documentation to learn about its features in greater detail, and [the examples](https://github.com/framesurge/perseus/tree/main/examples) will be your friends in writing real-world Perseus code: they have examples of every single Perseus feature. If you think you've found a bug, please let us know by [opening an issue](https://github.com/framesurge/perseus/issues/new/choose), or, if you'd like to contribute a feature, you can [open a pull request](https://github.com/framesurge/perseus/compare). If you're having trouble, you can [open a GitHub discussion](https://github.com/framesurge/perseus/discussions/new/choose) or [as on our Discord](https://discord.com/invite/GNqWYWNTdp), and our friendly community will be happy to help yout out! Also, make sure to take a look at [the Sycamore docs](https://https://sycamore-rs.netlify.app/) to learn more about the library that underlies all of Perseus.
With all that, you've successfully built and deployed your first ever Perseus app: well done! If you're liking Perseus so far, you can check out the rest of the documentation to learn about its features in greater detail, and [the examples](https://github.com/framesurge/perseus/tree/main/examples) will be your friends in writing real-world Perseus code: they have examples of every single Perseus feature. If you think you've found a bug, please let us know by [opening an issue](https://github.com/framesurge/perseus/issues/new/choose), or, if you'd like to contribute a feature, you can [open a pull request](https://github.com/framesurge/perseus/compare). If you're having trouble, you can [open a GitHub discussion](https://github.com/framesurge/perseus/discussions/new/choose) or [as on our Discord](https://discord.com/invite/GNqWYWNTdp), and our friendly community will be happy to help you out! Also, make sure to take a look at [the Sycamore docs](https://https://sycamore-rs.netlify.app/) to learn more about the library that underlies all of Perseus.

Best of luck in your journey, and, if you [defeat Medusa](https://en.wikipedia.org/wiki/Perseus), let us know!
Loading

0 comments on commit 9b8fcb5

Please sign in to comment.