-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(book): 📝 added docs for v0.3.x and deprecated v0.2.x
- Loading branch information
1 parent
9f5d05d
commit b2e3c57
Showing
47 changed files
with
1,411 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../common/header_old.hbs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../common/index.hbs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../common/book.toml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
# Summary | ||
|
||
- [Introduction](./intro.md) | ||
- [What is Perseus?](./what-is-perseus.md) | ||
- [Hello World!](./hello-world.md) | ||
- [Your Second App](./second-app.md) | ||
*** | ||
# Reference | ||
|
||
- [`define_app!`](./define-app.md) | ||
- [Writing Views](./views.md) | ||
- [Debugging](./debugging.md) | ||
- [Templates and Routing](./templates/intro.md) | ||
- [Modifying the `<head>`](./templates/metadata-modification.md) | ||
- [Modifying HTTP Headers](./templates/setting-headers.md) | ||
- [Error Pages](./error-pages.md) | ||
- [Static Content](./static-content.md) | ||
- [Internationalization](./i18n/intro.md) | ||
- [Defining Translations](./i18n/defining.md) | ||
- [Using Translations](./i18n/using.md) | ||
- [Translations Managers](./i18n/translations-managers.md) | ||
- [Other Translation Engines](./i18n/other-engines.md) | ||
- [Rendering Strategies](./strategies/intro.md) | ||
- [Build State](./strategies/build-state.md) | ||
- [Build Paths](./strategies/build-paths.md) | ||
- [Request State](./strategies/request-state.md) | ||
- [Revalidation](./strategies/revalidation.md) | ||
- [Incremental Generation](./strategies/incremental.md) | ||
- [State Amalgamation](./strategies/amlagamation.md) | ||
- [CLI](./cli.md) | ||
- [Ejecting](./ejecting.md) | ||
- [Testing](./testing/intro.md) | ||
- [Checkpoints](./testing/checkpoints.md) | ||
- [Fantoccini Basics](./testing/fantoccini-basics.md) | ||
- [Manual Testing](./testing/manual.md) | ||
- [Styling](./styling.md) | ||
- [Stores](./stores.md) | ||
- [Static Exporting](./exporting.md) | ||
- [Deploying](./deploying/intro.md) | ||
- [Server Deployment](./deploying/serverful.md) | ||
- [Serverless Deployment](./deploying/serverless.md) | ||
- [Optimizing Code Size](./deploying/size.md) | ||
- [Migrating from v0.2.x](./updating.md) | ||
*** | ||
# Advanced | ||
|
||
- [Under the Hood](./advanced/intro.md) | ||
- [Architecture](./advanced/arch.md) | ||
- [Initial Loads](./advanced/initial-loads.md) | ||
- [Subsequent Loads](./advanced/subsequent-loads.md) | ||
- [Routing](./advanced/routing.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Architecture | ||
|
||
Perseus has five main components: | ||
|
||
- `perseus` -- the core module that defines everything necessary to build a Perseus app if you try hard enough | ||
- `perseus-actix-web` -- an integration that makes it easy to run Perseus on the [Actix Web](https://actix.rs) framework | ||
- `perseus-cli` -- the command-line interface used to run Perseus apps conveniently | ||
- `perseus-cli-builder` -- an internal crate created by the CLI responsible for building an app | ||
- `perseus-cli-server` -- an internal crate created by the CLI responsible for serving an app and performing runtime logic | ||
|
||
## Core | ||
|
||
At the core of Perseus is the [`perseus`](https://docs.rs/perseus) module, which is used for nearly everything in Perseus. In theory, you could build a fully-functional app based on this crate alone, but you'd be reinventing the wheel at least three times. This crate exposes types for the i18n systems, configuration management, routing, and asset fetching, most of which aren't intended to be used directly by the user. | ||
|
||
What is intended to be used directly is the `Template<G>` `struct`, which is integral to Perseus. This stores closures for every rendering strategy, which are executed as provided and necessary at build and runtime. Note that these are all stored in `Rc`s, and `Template<G>`s are cloned. | ||
|
||
The other commonly used system from this crate is the `Translator` system, explained in detail in [the i18n section](../i18n/intro.md). `Translator`s are passed around in `Rc`s, and `TranslationsManager` on the server caches all translations by default in memory on the server. | ||
|
||
## Actix Web Integration | ||
|
||
The core of Perseus provides very few systems to set up a functional Perseus server though, which requires a significant amount of additional work. To this end, [`perseus-actix-web`](https://docs.rs/perseus-actix-web) is used to make this process easy. If you've ejected, you'll be working with this directly, which should be relatively simple, as it just accepts configuration options and then should simply work. | ||
|
||
Note that this module provides a `configurer` function, which allows it to be modularly added to any existing Actix Web server, which is particularly useful if you want to run other endpoint on your server, or a system like [Diana](https://github.com/arctic-hen7/diana). | ||
|
||
## CLI | ||
|
||
As documented in [this section](../cli.md), the CLI simply runs commands to execute the last two components of the Perseus system, acting as a convenience. It also contains these two components inside its binary (using [`include_dir!`](https://github.com/Michael-F-Bryan/include_dir)) | ||
|
||
## CLI Builder | ||
|
||
This system can be further broken down into two parts. | ||
|
||
### Static Generator | ||
|
||
This is a single binary that just imports the user's templates and some other information (like locales) and then calls `build_app`. This will result in generating a number of files to `.perseus/dist`, which will be served by the server to any clients, which will then hydrate those static pages into fully-fledged Sycamore templates. | ||
|
||
### App Shell | ||
|
||
This is encapsulated in `.perseus/src/lib.rs`, and it performs a number of integral functions: | ||
|
||
- Ensures that any `panic!`s or the like ar printed properly in the browser console | ||
- Creates and manages the internal router | ||
- Renders your actual app | ||
- Handles locale detection | ||
- Invokes the core app shell to manage initial/subsequent loads and translations | ||
- Handles error page displaying | ||
|
||
## CLI Server | ||
|
||
This is just an invocation of the `perseus-actix-web` module's systems with the data provided by the user through the `define_app!` macro. This also sets the default location for static content and the `index.html` file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Initial Loads | ||
|
||
Perseus handles _initial loads_ very differently from _subsequent loads_. The former refers to what's done when a user visits a page on a Perseus app from an external source (e.g. visiting from a search engine, redirected from another site), and this requires a full HTMl page to be sent that can be interpreted by the browser. By contrast, subsequent loads are loads between pages within the same Perseus app, which can be performed by the app shell (described in the next section). | ||
|
||
The process of initial loads is slightly complex, and occurs like so (this example is for a page called `/posts/test`, rendered with incremental generation): | ||
|
||
1. Browser requests `/posts/test` from the server. | ||
2. Server matches requested URL to wildcard (`*`) and handles it with the server-side inferred router, determining which `Template<G>` to use. | ||
3. Server calls internal core methods to render the page (using incremental generation strategy, but it doesn't need to know that), producing an HTML snippet and a set of JSON properties. | ||
4. Server calls `template.render_head_str()` and injects the result into the document's `<head>` (avoiding `<title>` flashes and improving SEO) after a delimiter comment that separates it from the metadata on every page (which is hardcoded into `index.html`). | ||
5. Server interpolates JSON state into `index.html` as a global variable in a `<script>`. | ||
6. Server interpolates HTML snippet directly into the user's `index.html` file. | ||
7. Server sends final HTML package to client, including Wasm (injected at build-time). | ||
8. Browser renders HTML package, user sees content immediately. | ||
9. Browser invokes Wasm, hands control to the app shell. | ||
10. App shell checks if initial state declaration global variable is present, finds that it is and unsets it (so that it doesn't interfere with subsequent loads). | ||
11. App shell moves server-rendered content out of `__perseus_content_initial` and into `__perseus_content_rx`, which Sycamore's router had control over (allowing it to catch links and use the subsequent loads system). | ||
12. App shell gets a translator if the app uses i18n. | ||
13. App shell hydrates content at `__perseus_content_rx` with Sycamore and returns, the page is now interactive and has a translator context. | ||
|
||
Note: if this app had used i18n, the server would've returned the app shell with no content, and the app shell, when invoked, would've immediately redirected the user to their preferred locale (or the closest equivalent). | ||
|
||
The two files integral to this process are [`initial_load.rs`](https://github.com/arctic-hen7/perseus/blob/main/packages/perseus-actix-web/src/initial_load.rs) and [`shell.rs`](https://github.com/arctic-hen7/perseus/blob/main/packages/perseus/src/shell.rs). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Under the Hood | ||
|
||
This section of the documentation is devoted to explaining the inner workings of Perseus, which will be particularly useful if you choose to eject from the CLI's harness or if you want to contribute to Perseus! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Routing | ||
|
||
Perseus' routing system is quite unique in that it's almost entirely *inferred*, meaning that you don't ever have to define a router or explain to the system which paths go where. Instead, they're inferred from templates in a system that's explained in detail in the [templates section](../templates/intro.md). | ||
|
||
## Template Selection Algorithm | ||
|
||
Perseus has a very specific algorithm that it uses to determine which template to use for a given route, which is greatly dependent on `.perseus/dist/render_conf.json`. This is executed on the client-side for *subsequent loads* and on the server-side for *initial loads*. | ||
|
||
Here's an example render configuration (for the [showcase example](https://github.com/arctic-hen7/perseus/blob/main/examples/showcase)), which maps path to template root path. | ||
|
||
```json | ||
{ | ||
"about": "about", | ||
"index": "index", | ||
"post/new": "post/new", | ||
"ip": "ip", | ||
"post/*": "post", | ||
"timeisr/test": "timeisr", | ||
"timeisr/*": "timeisr", | ||
"time": "time", | ||
"amalgamation": "amalgamation", | ||
"post/blah/test/blah": "post", | ||
"post/test": "post" | ||
} | ||
``` | ||
|
||
Here are the algorithm's steps (see [`router.rs`](https://github.com/arctic-hen7/perseus/blob/main/packages/perseus/src/router.rs)): | ||
|
||
1. If the path is empty, set it to `index` (which is used for the landing page). | ||
2. Try to directly get the template name by trying the path as a key. This would work for anything not using incremental generation (in the above example, anything other than `post/*`). | ||
3. Split the path into sections by `/` and iterate through them, performing the following on each section (iterating forwards from the beginning of the path, becoming more and more specific): | ||
1. Make a path out of all segments up to the current point, adding `/*` at the end (indicative of incremental generation in the render configuration). | ||
2. Try that as a key, return if it works. | ||
3. Even if we have something, continue iterating until we have nothing. This way, we get the most specific path possible (and we can have incremental generation in incremental generation). | ||
|
||
## Relationship with Sycamore's Router | ||
|
||
Sycamore has its own [routing system](https://sycamore-rs.netlify.app/docs/v0.6/advanced/routing), which Perseus depends on extensively under the hood. This is evident in `.perseus/src/lib.rs`, which invokes the router. However, rather than using the traditional Sycamore approach of having an `enum` with variants for each possible route (which was the approach in Perseus v0.1.x), Perseus provides the router with a `struct` that performs routing logic and returns either `RouteVerdict::Found`, `RouteVerdict::LocaleDetection`, or `RouteVerdict::NotFound`. The render configuration is accessed through a global variable implanted in the user's HTML shell when the server initializes. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Subsequent Loads | ||
|
||
if the user follows a link inside a Perseus app to another page within that same app, the Sycamore router will catch it and prevent the browser from requesting the new file from the server. The following will then occur (for an `/about` page rendered simply): | ||
|
||
1. Sycamore router calls Perseus inferred router logic. | ||
2. Perseus inferred router determines from new URL that template `about` should be used, returns to Sycamore router. | ||
3. Sycamore router passes that to closure in `perseus-cli-builder` shell, which executes core app shell. | ||
4. App shell checks if an initial load declaration global variable is present and finds none, hence it will proceed with the subsequent load system. | ||
5. App shell fetches page data from `/.perseus/page/<locale>/about?template_name=about` (if the app isn't using i18n, `<locale>` will verbatim be `xx-XX`). | ||
6. Server checks to ensure that locale is supported. | ||
7. Server renders page using internal systems (in this case that will just return the static HTML file from `.perseus/dist/static/`). | ||
8. Server renders document `<head>`. | ||
9. Server returns JSON of HTML snippet (not complete file), stringified properties, and head. | ||
10. App shell deserializes page data into state and HTML snippet. | ||
11. App shell interpolates HTML snippet directly into `__perseus_content_rx` (which Sycamore router controls), user can now see new page. | ||
12. App shell interpolates new document `<head>`. | ||
13. App shell initializes translator if the app is using i18n. | ||
14. App shell hydrates content at `__perseus_content_rx`, page is now interactive. | ||
|
||
The two files integral to this process are [`page_data.rs`](https://github.com/arctic-hen7/perseus/blob/main/packages/perseus-actix-web/src/page_data.rs) and [`shell.rs`](https://github.com/arctic-hen7/perseus/blob/main/packages/perseus/src/shell.rs). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# CLI | ||
|
||
One of the things that makes Perseus so different from most Rust frameworks is that it has its own CLI for development. The reason for this is to make using Perseus as simple as possible, and also because, if you have a look at what's in `.perseus/`, building without the CLI is really hard! | ||
|
||
## Commands | ||
|
||
### `build` | ||
|
||
Builds your app, performing static generation and preparing a Wasm package in `.perseus/dist/`. | ||
|
||
### `serve` | ||
|
||
Builds your app in the same way as `build`, and then builds the Perseus server (which has dependencies on your code, and so needs to rebuilt on any changes just like the stuff in `.perseus/dist/`), finally serving your app at <http://localhost:8080>. You can change the default host and port this serves on with the `HOST` and `PORT` environment variables. | ||
|
||
You can also provide `--no-build` to this command to make it skip building your app to Wasm and performing static generation. In this case, it will just build the serve rand run it (ideal for restarting the server if you've made no changes). | ||
|
||
### `test` | ||
|
||
Exactly the same as `serve`, but runs your app in testing mode, which you can read more about [here](./testing/intro.md). | ||
|
||
### `export` | ||
|
||
Builds and exports your app to a series of purely static files at `.perseus/dist/exported/`. This will only work if your app doesn't use any strategies that can't be run at build time, but if that's the case, then you can easily use Perseus without a server after running this command! You can read more about static exporting [here](./exporting.md). | ||
|
||
### `deploy` | ||
|
||
Builds your app for production and places it in `pkg/`. You can then upload that folder to a server of your choosing to deploy your app live! You can (and really should) read more about deployment and the potential problems you may encounter [here](./deploying/intro.md). | ||
|
||
### `clean` | ||
|
||
This command is the solution to just about any problem in your app that doesn't make sense, it deletes the `.perseus/` directory entirely, which should remove any corruptions! If this doesn't work, then the problem is in your code (unless you just updated to a new version and now something doesn't work, then it's probably on us, please [open an issue](https://github.com/arctic-hen7/perseus)!). | ||
|
||
Note that this command will force Perseus to rebuild `.perseus/` the next time you run `perseus build` or `perseus serve`, which can be annoying in terms of build times. It's almost always sufficient to run this command with the `--dist` flag, which will only delete some content in `.perseus/dist/` that's likely to be problematic. | ||
|
||
### `eject` | ||
|
||
See the next section for the details of this command. | ||
|
||
## Watching | ||
|
||
Right now, the Perseus CLI doesn't support watching files for changes and rebuilding, but it soon will. Until then, you can replicate this behavior with a tool like [`entr`](https://github.com/eradman/entr) or the equivalent. Anything that watches file and reruns commands when they change will work for this. | ||
|
||
Here's an example of watching files with `entr`: | ||
|
||
``` | ||
find . -not -path "./.perseus/*" -not -path "./target/*" | entr -s "perseus serve" | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Debugging | ||
|
||
If you're used to Rust, you might be expecting to be able to call `println!` or `dbg!` to easily print a value to the browser console while working on an app, however this is unfortunately not yet the case (this is an issue in the lower-level libraries that Perseus depends on). | ||
|
||
However, Perseus exports a macro called `web_log!` that can be used to print to the console. It accepts syntax identical to `format!`, `println!`, and the like and behaves in the same way, but it will print to the browser console instead of the terminal. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# `define_app!` | ||
|
||
The core of Perseus is how it interacts with the CLI, which acts as the engine that runs your code. The bridge between these two systems is the `define_app!` macro, which accepts a number of options that define your app. | ||
|
||
The smallest this can reasonably get is a fully self-contained app (taken from [here](https://github.com/arctic-hen7/perseus/tree/main/examples/tiny/src/lib.rs)): | ||
|
||
```rust,no_run,no_playground | ||
{{#include ../../../examples/tiny/src/lib.rs}} | ||
``` | ||
|
||
In a more complex app though, this macro still remains very manageable (taken from [here](https://github.com/arctic-hen7/perseus/tree/main/examples/showcase/src/lib.rs)): | ||
|
||
```rust,no_run,no_playground | ||
{{#include ../../../examples/showcase/src/lib.rs}} | ||
``` | ||
|
||
## Parameters | ||
|
||
Here's a list of everything you can provide to the macro and what each one does (note that the order of these matters): | ||
|
||
- `root` (optional) -- the HTML `id` to which your app will be rendered, the default is `root`; this MUST be reflected in your `index.html` file as an exact replication (spacing and all) of `<div id="root-id-here"></div>` (replacing `root-id-here` with the value of this property) | ||
- `templates` -- defines a list of your templates in which order is irrelevant | ||
- `error_pages` -- defines an instance of `ErrorPages`, which tells Perseus what to do on an error (like a *404 Not Found*) | ||
- `locales` (optional) -- defines options for i18n (internationalization), this shouldn't be specified for apps not using i18n | ||
- `default` -- the default locale of your app (e.g. `en-US`) | ||
- `other` -- a list of the other locales your app supports | ||
- `static_aliases` (optional) -- a list of aliases to static files in your project (e.g. for a favicon) | ||
- `dist_path` (optional) -- a custom path to distribution artifacts (this is relative to `.perseus/`!) | ||
- `mutable_store` (optional) -- a custom mutable store | ||
- `translations_manager` (optional) -- a custom translations manager | ||
|
||
**WARNING:** if you try to include something from outside the current directory in `static_aliases`, **no part of your app will load**! If you could include such content, you might end up serving `/etc/passwd`, which would be a major security risk. | ||
|
||
## Other Files | ||
|
||
There's only one other file that the `define_app!` macro expects to exist: `index.html`. Note that any content in the `<head>` of this will be on every page, above anything inserted by the template. | ||
|
||
Here's an example of this file (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/basic/index.html)): | ||
|
||
```html | ||
{{#include ../../../examples/basic/index.html}} | ||
``` |
Oops, something went wrong.