docs: book restructuring and updates (#2052)

* move DX page under "Getting Started" section; add leptosfmt to DX page

* add a "community and leptos-* crates" page

* create folder for "getting_started"

* updates to 'getting started' chapter (feedback-based)

* clarify book structure + add necessary explanations

* address PR comments by @reedwoodruff

* update "getting started"

* address gbj's comments

* remove the term "universal" from book

* minor update

* formatting

* address reedwoodruff comment
This commit is contained in:
Daniel Mantei 2023-11-30 16:24:18 -08:00 committed by GitHub
parent 19711e16b6
commit e8025705a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 289 additions and 181 deletions

View file

@ -1,97 +0,0 @@
# Getting Started
There are two basic paths to getting started with Leptos:
1. Client-side rendering with [Trunk](https://trunkrs.dev/)
2. Full-stack rendering with [`cargo-leptos`](https://github.com/leptos-rs/cargo-leptos)
For the early examples, it will be easiest to begin with Trunk. Well introduce
`cargo-leptos` a little later in this series.
If you dont already have it installed, you can install Trunk by running
```bash
cargo install trunk
```
Create a basic Rust project
```bash
cargo init leptos-tutorial
```
`cd` into your new `leptos-tutorial` project and add `leptos` as a dependency
```bash
cargo add leptos --features=csr,nightly
```
> **Note**: This version of the book reflects the Leptos 0.5 release. The CodeSandbox examples have not yet been updated from 0.4 and earlier versions.
Or you can leave off `nightly` if you're using stable Rust
```bash
cargo add leptos --features=csr
```
> Using `nightly` Rust, and the `nightly` feature in Leptos enables the function-call syntax for signal getters and setters that is used in most of this book.
>
> To use nightly Rust, you can either opt into nightly for all your Rust projects by running
>
> ```bash
> rustup toolchain install nightly
> rustup default nightly
> ```
>
> or only for this project
>
> ```bash
> rustup toolchain install nightly
> cd <into your project>
> rustup override set nightly
> ```
>
> [See here for more details.](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html)
>
> If youd rather use stable Rust with Leptos, you can do that too. In the guide and examples, youll just use the [`ReadSignal::get()`](https://docs.rs/leptos/latest/leptos/struct.ReadSignal.html#impl-SignalGet%3CT%3E-for-ReadSignal%3CT%3E) and [`WriteSignal::set()`](https://docs.rs/leptos/latest/leptos/struct.WriteSignal.html#impl-SignalGet%3CT%3E-for-ReadSignal%3CT%3E) methods instead of calling signal getters and setters as functions.
Make sure you've added the `wasm32-unknown-unknown` target so that Rust can compile your code to WebAssembly to run in the browser.
```bash
rustup target add wasm32-unknown-unknown
```
Create a simple `index.html` in the root of the `leptos-tutorial` directory
```html
<!DOCTYPE html>
<html>
<head></head>
<body></body>
</html>
```
And add a simple “Hello, world!” to your `main.rs`
```rust
use leptos::*;
fn main() {
mount_to_body(|| view! { <p>"Hello, world!"</p> })
}
```
Your directory structure should now look something like this
```
leptos_tutorial
├── src
│ └── main.rs
├── Cargo.toml
├── index.html
```
Now run `trunk serve --open` from the root of the `leptos-tutorial` directory.
Trunk should automatically compile your app and open it in your default browser.
If you make edits to `main.rs`, Trunk will recompile your source code and
live-reload the page.

View file

@ -1,8 +1,10 @@
# Summary
- [Introduction](./01_introduction.md)
- [Getting Started](./02_getting_started.md)
- [Building User Interfaces](./view/README.md)
- [Getting Started](./getting_started/README.md)
- [Leptos DX](./getting_started/leptos_dx.md)
- [The Leptos Community and leptos-* Crates](./getting_started/community_crates.md)
- [Part 1: Building User Interfaces](./view/README.md)
- [A Basic Component](./view/01_basic_component.md)
- [Dynamic Attributes](./view/02_dynamic_attributes.md)
- [Components and Props](./view/03_components.md)
@ -34,7 +36,8 @@
- [`<Form/>`](./router/20_form.md)
- [Interlude: Styling](./interlude_styling.md)
- [Metadata](./metadata.md)
- [Server Side Rendering](./ssr/README.md)
- [Client-Side Rendering: Wrapping Up](./csr_wrapping_up.md)
- [Part 2: Server Side Rendering](./ssr/README.md)
- [`cargo-leptos`](./ssr/21_cargo_leptos.md)
- [The Life of a Page Load](./ssr/22_life_cycle.md)
- [Async Rendering and SSR “Modes”](./ssr/23_ssr_modes.md)
@ -48,5 +51,6 @@
- [Deployment](./deployment/README.md)
- [Optimizing WASM Binary Size](./deployment/binary_size.md)
- [Guide: Islands](./islands.md)
- [Appendix: How Does the Reactive System Work?](./appendix_reactive_graph.md)
- [Appendix: Some Small DX Improvements](./appendix_dx.md)

View file

@ -1,62 +0,0 @@
# A Running List of Small Developer Experience Improvements
## Autocompletion inside `#[component]` and `#[server]`
Because of the nature of macros (they can expand from anything to anything, but only if the input is exactly correct at that instant) it can be hard for rust-analyzer to do proper autocompletion and other support.
But you can tell rust-analyzer to ignore certain proc macros. For `#[component]` and `#[server]` especially, which annotate function bodies but don't actually transform anything inside the body of your function, this can be really helpful.
Note that this means that rust-analyzer doesn't know about your component props, which may generate its own set of errors or warnings in the IDE.
VSCode `settings.json`:
```json
"rust-analyzer.procMacro.ignored": {
"leptos_macro": [
"component",
"server"
],
}
```
neovim with lspconfig:
```lua
require('lspconfig').rust_analyzer.setup {
-- Other Configs ...
settings = {
["rust-analyzer"] = {
-- Other Settings ...
procMacro = {
ignored = {
leptos_macro = {
"component",
"server",
},
},
},
},
}
}
```
Helix, in `.helix/languages.toml`:
```toml
[[language]]
name = "rust"
[language-server.rust-analyzer]
config = { procMacro = { ignored = { leptos_macro = ["component", "server"] } } }
```
```admonish info
The Jetbrains `intellij-rust` plugin (RustRover as well) currently does not support dynamic config for macro exclusion.
However, the project currently maintains a hardcoded list of excluded macros.
As soon as [this open PR](https://github.com/intellij-rust/intellij-rust/pull/10873) is merged, the `component` and
`server` macro will be excluded automatically without additional configuration needed.
Update (2023/10/02):
The `intellij-rust` plugin got deprecated in favor of RustRover at the same time the PR was opened, but an official
support request was made to integrate the contents of this PR.
```

View file

@ -0,0 +1,26 @@
# Wrapping Up Part 1: Client-Side Rendering
So far, everything weve written has been rendered almost entirely in the browser. When we create an app using Trunk, its served using a local development server. If you build it for production and deploy it, its served by whatever server or CDN youre using. In either case, whats served is an HTML page with
1. the URL of your Leptos app, which has been compiled to WebAssembly (WASM)
2. the URL of the JavaScript used to initialize this WASM blob
3. an empty `<body>` element
When the JS and WASM have loaded, Leptos will render your app into the `<body>`. This means that nothing appears on the screen until JS/WASM have loaded and run. This has some drawbacks:
1. It increases load time, as your users screen is blank until additional resources have been downloaded.
2. Its bad for SEO, as load times are longer and the HTML you serve has no meaningful content.
3. Its broken for users for whom JS/WASM dont load for some reason (e.g., theyre on a train and just went into a tunnel before WASM finished loading; theyre using an older device that doesnt support WASM; they have JavaScript or WASM turned off for some reason; etc.)
These downsides apply across the web ecosystem, but especially to WASM apps.
However, depending the on the requirements of your project, you may be fine with these limitations.
If you just want to deploy your Client-Side Rendered website, skip ahead to the chapter on ["Deployment"](https://leptos-rs.github.io/leptos/deployment/index.html) - there, you'll find directions on how best to deploy your Leptos CSR site.
But what do you do if you want to return more than just an empty `<body>` tag in your `index.html` page? Use “Server-Side Rendering”!
Whole books could be (and probably have been) written about this topic, but at its core, its really simple: rather than returning an empty `<body>` tag, with SSR, you'll return an initial HTML page that reflects the actual starting state of your app or site, so that while JS/WASM are loading, and until they load, the user can access the plain HTML version.
Part 2 of this book, on Leptos SSR, will cover this topic in some detail!

View file

@ -0,0 +1,125 @@
# Getting Started
There are two basic paths to getting started with Leptos:
1. **Client-side rendering (CSR) with [Trunk](https://trunkrs.dev/)** - a great option if you just want to make a snappy website with Leptos, or work with a pre-existing server or API.
In CSR mode, Trunk compiles your Leptos app to WebAssembly (WASM) and runs it in the browser like a typical Javascript single-page app (SPA). The advantages of Leptos CSR include faster build times and a quicker iterative development cycle, as well as a simpler mental model and more options for deploying your app. CSR apps do come with some disadvantages: initial load times for your end users are slower compared to a server-side rendering approach, and the usual SEO challenges that come along with using a JS single-page app model apply to Leptos CSR apps as well. Also note that, under the hood, an auto-generated snippet of JS is used to load the Leptos WASM bundle, so JS *must* be enabled on the client device for your CSR app to display properly. As with all software engineering, there are trade-offs here you'll need to consider.
2. **Full-stack, server-side rendering (SSR) with [`cargo-leptos`](https://github.com/leptos-rs/cargo-leptos)** - SSR is a great option for building CRUD-style websites and custom web apps if you want Rust powering both your frontend and backend.
With the Leptos SSR option, your app is rendered to HTML on the server and sent down to the browser; then, WebAssembly is used to instrument the HTML so your app becomes interactive - this process is called 'hydration'. On the server side, Leptos SSR apps integrate closely with your choice of either [Actix-web](https://docs.rs/leptos_actix/latest/leptos_actix/index.html) or [Axum](https://docs.rs/leptos_axum/latest/leptos_axum/index.html) server libraries, so you can leverage those communities' crates to help build out your Leptos server.
The advantages of taking the SSR route with Leptos include helping you get the best initial load times and optimal SEO scores for your web app. SSR apps can also dramatically simplify working across the server/client boundary via a Leptos feature called "server functions", which lets you transparently call functions on the server from your client code (more on this feature later). Full-stack SSR isn't all rainbows and butterflies, though - disadvantages include a slower developer iteration loop (because you need to recompile both the server and client when making Rust code changes), as well as some added complexity that comes along with hydration.
By the end of the book, you should have a good idea of which trade-offs to make and which route to take - CSR or SSR - depending on your project's requirements.
In Part 1 of this book, we'll start with client-side rendering Leptos sites and building reactive UI's using `Trunk` to serve our JS and WASM bundle to the browser.
Well introduce `cargo-leptos` in Part 2 of this book, which is all about working with the full power of Leptos in its full-stack, SSR mode.
```admonish note
If you're coming from the Javascript world and terms like client-side rendering (CSR) and server-side rendering (SSR) are unfamiliar to you, the easiest way to understand the difference is by analogy:
Leptos' CSR mode is similar to working with React (or a 'signals'-based framework like SolidJS), and focuses on producing a client-side UI which you can use with any tech stack on the server.
Using Leptos' SSR mode is similar to working with a full-stack framework like Next.js in the React world (or Solid's "SolidStart" framework) - SSR helps you build sites and apps that are rendered on the server then sent down to the client. SSR can help to improve your site's loading performance and accessibility as well as make it easier for one person to work on *both* client- and server-side without needing to context-switch between different languages for frontend and backend.
The Leptos framework can be used either in CSR mode to just make a UI (like React), or you can use Leptos in full-stack SSR mode (like Next.js) so that you can build both your UI and your server with one language: Rust.
```
## Hello World! Getting Set up for Leptos CSR Development
First up, make sure Rust is installed and up-to-date ([see here if you need instructions](https://www.rust-lang.org/tools/install)).
If you dont have it installed already, you can install the "Trunk" tool for running Leptos CSR sites by running the following on the command-line:
```bash
cargo install trunk
```
And then create a basic Rust project
```bash
cargo init leptos-tutorial
```
`cd` into your new `leptos-tutorial` project and add `leptos` as a dependency
```bash
cargo add leptos --features=csr,nightly
```
Or you can leave off `nightly` if you're using stable Rust
```bash
cargo add leptos --features=csr
```
> Using `nightly` Rust, and the `nightly` feature in Leptos enables the function-call syntax for signal getters and setters that is used in most of this book.
>
> To use nightly Rust, you can either opt into nightly for all your Rust projects by running
>
> ```bash
> rustup toolchain install nightly
> rustup default nightly
> ```
>
> or only for this project
>
> ```bash
> rustup toolchain install nightly
> cd <into your project>
> rustup override set nightly
> ```
>
> [See here for more details.](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html)
>
> If youd rather use stable Rust with Leptos, you can do that too. In the guide and examples, youll just use the [`ReadSignal::get()`](https://docs.rs/leptos/latest/leptos/struct.ReadSignal.html#impl-SignalGet%3CT%3E-for-ReadSignal%3CT%3E) and [`WriteSignal::set()`](https://docs.rs/leptos/latest/leptos/struct.WriteSignal.html#impl-SignalGet%3CT%3E-for-ReadSignal%3CT%3E) methods instead of calling signal getters and setters as functions.
Make sure you've added the `wasm32-unknown-unknown` target so that Rust can compile your code to WebAssembly to run in the browser.
```bash
rustup target add wasm32-unknown-unknown
```
Create a simple `index.html` in the root of the `leptos-tutorial` directory
```html
<!DOCTYPE html>
<html>
<head></head>
<body></body>
</html>
```
And add a simple “Hello, world!” to your `main.rs`
```rust
use leptos::*;
fn main() {
mount_to_body(|| view! { <p>"Hello, world!"</p> })
}
```
Your directory structure should now look something like this
```
leptos_tutorial
├── src
│ └── main.rs
├── Cargo.toml
├── index.html
```
Now run `trunk serve --open` from the root of the `leptos-tutorial` directory.
Trunk should automatically compile your app and open it in your default browser.
If you make edits to `main.rs`, Trunk will recompile your source code and
live-reload the page.
Welcome to the world of UI development with Rust and WebAssembly (WASM), powered by Leptos and Trunk!
---
Now before we get started building your first real UI's with Leptos, there are a couple of things you might want to know to help make your experience with Leptos just a little bit easier.

View file

@ -0,0 +1,23 @@
# The Leptos Community and `leptos-*` Crates
## The Community
One final note before we get to building with Leptos: if you haven't already, feel free to join the growing community on the Leptos [Discord](https://discord.gg/YdRAhS7eQB) and on [Github](https://github.com/leptos-rs/leptos). Our Discord channel in particular is very active and friendly - we'd love to have you there!
```admonish note
If you find a chapter or an explanation that isn't clear while you're working your way through the Leptos book, just mention it in the "docs-and-education" channel or ask a question in "help" so we can clear things up and update the book for others.
```
As you get further along in your Leptos journey and find that you have questions about "how to do 'x' with Leptos", then search the Discord "help" channel to see if a similar question has been asked before, or feel free to post your own question - the community is quite helpful and very responsive.
The "[Discussions](https://github.com/leptos-rs/leptos/discussions)" on Github are also a great place for asking questions and keeping up with Leptos announcements.
And of course, if you run into any bugs while developing with Leptos or would like to make a feature request (or contribute a bug fix / new feature), open up an issue on the [Github issue tracker](https://github.com/leptos-rs/leptos/issues).
## Leptos-* Crates
The community has built a growing number of Leptos-related crates that will help you get productive with Leptos projects more quickly - check out the list of crates built on top of Leptos and contributed by the community on the [Awesome Leptos](https://github.com/leptos-rs/awesome-leptos) repo on Github.
If you want to find the newest, up-and-coming Leptos-related crates, check out the "Tools and Libraries" section of the Leptos Discord. In that section, there are channels for the Leptos `view!` macro formatter (in the "leptosfmt" channel); there's a channel for the utility library "leptos-use"; another channel for the UI component libary "leptonic"; and a "libraries" channel where new `leptos-*` crates are discussed before making their way into the growing list of crates and resources available on [Awesome Leptos](https://github.com/leptos-rs/awesome-leptos).

View file

@ -0,0 +1,92 @@
# Leptos Developer Experience Improvements
There are a couple of things you can do to improve your experience of developing websites and apps with Leptos. You may want to take a few minutes and set up your environment to optimize your development experience, especially if you want to code along with the examples in this book.
## 1) Editor Autocompletion inside `#[component]` and `#[server]`
Because of the nature of macros (they can expand from anything to anything, but only if the input is exactly correct at that instant) it can be hard for rust-analyzer to do proper autocompletion and other support.
If you run into issues using these macros in your editor, you can explicitly tell rust-analyzer to ignore certain proc macros. For the `#[server]` macro especially, which annotates function bodies but doesn't actually transform anything inside the body of your function, this can be really helpful.
Starting in Leptos version 0.5.3, rust-analyzer support was added for the `#[component]` macro, but if you run into issues, you may want to add `#[component]` to the macro ignore list as well (see below).
Note that this means that rust-analyzer doesn't know about your component props, which may generate its own set of errors or warnings in the IDE.
VSCode `settings.json`:
```json
"rust-analyzer.procMacro.ignored": {
"leptos_macro": [
// optional:
// "component",
"server"
],
}
```
neovim with lspconfig:
```lua
require('lspconfig').rust_analyzer.setup {
-- Other Configs ...
settings = {
["rust-analyzer"] = {
-- Other Settings ...
procMacro = {
ignored = {
leptos_macro = {
-- optional: --
-- "component",
"server",
},
},
},
},
}
}
```
Helix, in `.helix/languages.toml`:
```toml
[[language]]
name = "rust"
[language-server.rust-analyzer]
config = { procMacro = { ignored =
{ leptos_macro =
[
# Optional:
# "component",
"server"
]
}
} }
```
```admonish info
The Jetbrains `intellij-rust` plugin (RustRover as well) currently does not support dynamic config for macro exclusion.
However, the project currently maintains a hardcoded list of excluded macros.
As soon as [this open PR](https://github.com/intellij-rust/intellij-rust/pull/10873) is merged, the `component` and
`server` macro will be excluded automatically without additional configuration needed.
Update (2023/10/02):
The `intellij-rust` plugin got deprecated in favor of RustRover at the same time the PR was opened, but an official
support request was made to integrate the contents of this PR.
```
## 2) Set up `leptosfmt` With Rust Analyzer (optional)
"leptosfmt" is a formatter for the Leptos `view!` macro (inside of which you'll typically write your UI code). Because the view! macro enables an 'RSX' (like JSX) style of writing your UI's, cargo-fmt has a harder time auto-formatting your code that's inside the view! macro. leptosfmt is a crate that solves your formattting issues and keeps your RSX-style UI code looking nice and tidy!
leptosfmt can be installed and used via the commandline or from within your code editor:
First, install the tool with `cargo install leptosfmt`.
If you just want to use the default options from the command line, just run `leptosfmt ./**/*.rs` from the root of your project to format all the rust files using leptosfmt.
If you wish to set up your editor to work with leptosfmt, or if you wish to customize your leptosfmt experience, please see the instructions available on the [leptosfmt github repo's README.md page](https://github.com/bram209/leptosfmt).
Just note that it's recommended to set up your editor with `leptosfmt` on a per-workspace basis for best results.

View file

@ -1,6 +1,6 @@
# Working with the Server
The previous section described the process of server-side rendering, using the server to generate an HTML version of the page that will become interactive in the browser. So far, everything has been “isomorphic” or “universal”; in other words, your app has had the “same (_iso_) shape (_morphe_)” on the client and the server.
The previous section described the process of server-side rendering, using the server to generate an HTML version of the page that will become interactive in the browser. So far, everything has been “isomorphic”; in other words, your app has had the “same (_iso_) shape (_morphe_)” on the client and the server.
But a server can do a lot more than just render HTML! In fact, a server can do a whole bunch of things your browser _cant,_ like reading from and writing to a SQL database.

View file

@ -1,21 +1,17 @@
# Server Side Rendering
# Part 2: Server Side Rendering
So far, everything weve written has been rendered almost entirely in the browser. When we create an app using Trunk, its served using a local development server. If you build it for production and deploy it, its served by whatever server or CDN youre using. In either case, whats served is an HTML page with
The second part of the book is all about how to turn your beautiful UIs into full-stack Rust + Leptos powered websites and applications.
1. the URL of your Leptos app, which has been compiled to WebAssembly (WASM)
2. the URL of the JavaScript used to initialized this WASM blob
3. an empty `<body>` element
As you read in the last chapter, there are some limitations to using client-side rendered Leptos apps - over the next few chapters, you'll see how we can overcome those limitations
and get the best performance and SEO out of your Leptos apps.
When the JS and WASM have loaded, Leptos will render your app into the `<body>`. This means that nothing appears on the screen until JS/WASM have loaded and run. This has some drawbacks:
1. It increases load time, as your users screen is blank until additional resources have been downloaded.
2. Its bad for SEO, as load times are longer and the HTML you serve has no meaningful content.
3. Its broken for users for whom JS/WASM dont load for some reason (e.g., theyre on a train and just went into a tunnel before WASM finished loading; theyre using an older device that doesnt support WASM; they have JavaScript or WASM turned off for some reason; etc.)
```admonish info
These downsides apply across the web ecosystem, but especially to WASM apps.
When working with Leptos on the server side, you're free to choose either the Actix-web or the Axum integrations - the full feature set of Leptos is available with either option.
So what do you do if you want to return more than just an empty `<body>` tag? Use “server-side rendering.”
If, however, you need deploy to a WinterCG-compatible runtime like Deno, Cloudflare, etc., then choose the Axum integration as this deployment option is only available with Axum on the server. Lastly, if you'd like to go full-stack WASM/WASI and deploy to WASM-based serverless runtimes, then Axum is your go-to choice here too.
Whole books could be (and probably have been) written about this topic, but at its core, its really simple: rather than returning an empty `<body>` tag, return an initial HTML page that reflects the actual starting state of your app or site, so that while JS/WASM are loading, and until they load, the user can access the plain HTML version.
NB: this is a limitation of the web frameworks themselves, not Leptos.
The rest of this section will cover this topic in some detail!
```

View file

@ -1,5 +1,6 @@
# Building User Interfaces
# Part 1: Building User Interfaces
This first section will introduce you to the basic tools you need to build a reactive
user interface using Leptos. By the end of this section, you should be able to
build a simple, synchronous application that is rendered in the browser.
In the first part of the book, we're going to look at building user interfaces on the client-side using Leptos. Under the hood, Leptos and Trunk are bundling up a snippet of Javascript which will load up the Leptos UI, which has been compiled to WebAssembly to drive the interactivity in your CSR (client-side rendered) website.
Part 1 will introduce you to the basic tools you need to build a reactive user interface powered by Leptos and Rust. By the end of Part 1, you should be able to
build a snappy synchronous website that's rendered in the browser and which you can deploy on any static-site hosting service, like Github Pages or Vercel.