Skip to content

Commit bd0710d

Browse files
committed
docs: updated docs for typed options system
1 parent d1ba2ef commit bd0710d

File tree

19 files changed

+99
-46
lines changed

19 files changed

+99
-46
lines changed

docs/next/en-US/SUMMARY.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010

1111
# Reference
1212

13-
- [`define_app!`](/docs/reference/define-app)
13+
- [`PerseusApp`](/docs/reference/perseus-app)
14+
- [`define_app!`](/docs/reference/define-app)
1415
- [Writing Views](/docs/reference/views)
16+
- [The Index View](/docs/reference/index-view)
1517
- [Debugging](/docs/reference/debugging)
1618
- [Live Reloading](/docs/reference/live-reloading)
1719
- [Templates and Routing](/docs/reference/templates/intro)

docs/next/en-US/reference/define-app.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# `define_app!`
22

3-
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.
3+
Perseus used to be configured through a macro rather than through `PerseusApp`: `define_app!`. For now, this is still supported, but it will be removed in the next major release. If you're still using `define_app!`, you should switch to `PerseusApp` when possible. Note also that `define_app!` is now simply a wrapper for `PerseusApp`.
44

55
The smallest this can reasonably get is a fully self-contained app (taken from [here](https://github.com/arctic-hen7/perseus/tree/main/examples/comprehensive/tiny/src/lib.rs)):
66

docs/next/en-US/reference/deploying/serverful.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ You can deploy to one of these providers without any further changes to your cod
2222

2323
### Alternative Mutable Stores
2424

25-
The other option you have is deploying to a modern provider that has a read-only filesystem and then using an alternative mutable store. That is, you store your mutable data in a database or the like rather than on the filesystem. This requires you to implement the `MutableStore` `trait` for your storage system (see the [API docs](https://docs.rs/perseus)), which should be relatively easy. You can then provide this to the `define_app!` macro with the `mutable_store` parameter. Make sure to test this on your local system to ensure that your connections all work as expected before deploying to the server, which you can do with `perseus deploy` and by then copying the `pkg/` directory to the server.
25+
The other option you have is deploying to a modern provider that has a read-only filesystem and then using an alternative mutable store. That is, you store your mutable data in a database or the like rather than on the filesystem. This requires you to implement the `MutableStore` `trait` for your storage system (see the [API docs](https://docs.rs/perseus)), which should be relatively easy.
26+
27+
You can then provide this to `PerseusApp` with the `.new_with_mutable_store()` function, which must be run on `PerseusAppWithMutableStore`, which takes a second parameter for the type of the mutable store.
28+
29+
Make sure to test this on your local system to ensure that your connections all work as expected before deploying to the server, which you can do with `perseus deploy` and by then copying the `pkg/` directory to the server.
2630

2731
This approach may seem more resilient and modern, but it comes with a severe downside: speed. Every request that involves mutable data (so any request for a revalidating page or an incrementally generated one) must go through four trips (an extra one to and from the database) rather than two, which is twice as many as usual! This will bring down your site's time to first byte (TTFB) radically, so you should ensure that your mutable store is as close to your server as possible so that the latency between them is negligible. If this performance pitfall is not acceptable, you should use an old-school hosting provider instead.

docs/next/en-US/reference/error-pages.md

+4
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,7 @@ The most important thing to note about these error pages is the arguments they e
2828
Error pages are also available for you to use yourself (see the [API docs](https://docs.rs/perseus) on the functions to call for that) if an error occurs in one of your own pages, and in that case, if you're using i18n, you'll have a `Translator` available. However, there are _many_ cases in Perseus in which translators are not available to error pages (e.g. the error page might have been rendered because the translator couldn't be initialized for some reason), and in these cases, while it may be tempting to fall back to the default locale, you should optimally make your page as easy to decipher for speakers of other languages as possible. This means emoji, pictures, icons, etc. Bottom line: if the fourth parameter to an error page is `None`, then communicate as universally as possible.
2929

3030
An alternative is just to display an error message in every language that your app supports, which may in some cases be easier and more practical.
31+
32+
## Error Pages in Development
33+
34+
When you start building a new app, you want to spend as little time on boilerplate as possible, and Perseus enables this by having a default set of error pages that you can use in development so you can get straight to work on your app, but you'll need to make them eventually for production, otherwise you'll get an error when you try to deploy your app. The reason for not allowing the default error pages in production is to avoid people not noticing that they're using the defaults, which may not be what they want, or even in the language they want (even if you're building an i18n site, the default development error pages are still in English for simplicity).

docs/next/en-US/reference/i18n/defining.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Defining Translations
22

3-
The first part of setting up i18n in Perseus is to state that your app uses it, which is done in the `define-app!` macro like so (taken from [the i18n example](https://github.com/arctic-hen7/perseus/tree/main/examples/core/i18n)):
3+
The first part of setting up i18n in Perseus is to state that your app uses it, which is done in `PerseusApp` like so (taken from [the i18n example](https://github.com/arctic-hen7/perseus/tree/main/examples/core/i18n)):
44

55
```rust
66
{{#include ../../../../examples/core/i18n/src/lib.rs}}
77
```
88

9-
There are two subfields under the `locales` key: `default` and `other`. Each of these locales should be specified in the form `xx-XX`, where `xx` is the language code (e.g. `en` for English, `fr` for French, `la` for Latin) and `XX` is the region code (e.g. `US` for United States, `GB` for Great Britain, `CN` for China).
9+
There are two paremeters to the `.locales()` function: the default locale for your app, and then any other locales it supports (other than the default). Each of these locales should be specified in the form `xx-XX`, where `xx` is the language code (e.g. `en` for English, `fr` for French, `la` for Latin) and `XX` is the region code (e.g. `US` for United States, `GB` for Great Britain, `CN` for China).
1010

1111
## Routing
1212

@@ -16,7 +16,7 @@ Of course, it's hardly optimal to direct users to a pre-translated page if they
1616

1717
## Adding Translations
1818

19-
After you've added those definitions to `define_app!`, if you try to run your app, you'll find that ever page throws an error because it can't find any of the translations files. These must be defined under `translations/` (which should be NEXT to `/src`, not under it!), though this can be customized (explained later). They must also adhere to the naming format `xx-XX.ftl` (e.g. `en-US.ftl`). `.ftl` is the file extension that [Fluent](https://projectfluent.org) files use, which is the default translations system of Perseus. If you'd like to use a different system, this will be explained later.
19+
After you've added those definitions to `PerseusApp`, if you try to run your app, you'll find that ever page throws an error because it can't find any of the translations files. These must be defined under `translations/` (which should be NEXT to `/src`, not in it!), though this can be customized (explained later). They must also adhere to the naming format `xx-XX.ftl` (e.g. `en-US.ftl`). `.ftl` is the file extension that [Fluent](https://projectfluent.org) files use, which is the default translations system of Perseus. If you'd like to use a different system, this will be explained later.
2020

2121
Here's an example of a translations file (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/core/i18n/translations/en-US.ftl)):
2222

docs/next/en-US/reference/i18n/translations-managers.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ If you'd like to change this default behavior, this section is for you! Perseus
66

77
## Using a Custom Translations Manager
88

9-
The `define_app!` macro accepts a property called `translations_manager` if you define `locales`, which can be used to specify a non-default translations manager.
9+
`PerseusApp` can be used with a custom translations manager through the `.translations_manager()` function. Note that this must be used with `PerseusAppWithTranslationsManager` rather than the usual `PerseusApp` (there's also `PerseusAppBase` if you want this and a custom mutable store). Further, translations managers all instantiate asynchronously, but we can't have asynchronous code in `PerseusApp` because of how it's called in the browser, so you should provide a future here (just don't add the `.await`), and Perseus will evaluate this when needed.
1010

1111
## Using a Custom Directory
1212

13-
If you just want to change the directory in which translations are stored, you can still use `FsTranslationsmanager`, just initialize it with a different directory, and make sure to set up caching properly. See [here](https://github.com/arctic-hen7/perseus/blob/f7f7892fbf124a7d887b1f22a1641c79773d6246/packages/perseus/src/macros.rs#L35-L50) for how this is done internally.
13+
If you just want to change the directory in which translations are stored, you can still use `FsTranslationsmanager`, just initialize it with a different directory, and make sure to set up caching properly.
1414

1515
## Building a Custom Translations Manager
1616

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# The Index View
2+
3+
In most Perseus apps, you can just ofcus on building your app's templates, and leave the boilerplate entirely to the Perseus engine, but sometimes that isn't quite sufficient, like if you want to use one stylesheet across your entire app. In traditional architectures, these are the kinds of modifications you might make to an `index.html` file that a framework inserts itself into, and you can do exactly this with Perseus! If you provide an `index.html` file in the root of your porject (not inside `src/`), Perseus will insert itself into that!
4+
5+
However, if you're using Perseus, you probably don't want to be writing HTML right? You're supposed to be using Sycamore! Well, that's completely true, and so Perseus supports creating an index view with Sycamore code! You can do this like so:
6+
7+
```rust
8+
TODO example
9+
```
10+
11+
Note that you can also use `.index_view_str()` to provide an arbitrary HTML string to use instead of Sycamore code.
12+
13+
It's also important to remember that whatever you put in your index view will persist across *all* the pages of your app! There is no way to change this, as Perseus literally injects itself into this, using it as a super-template for all your other templates!
14+
15+
## Requirements for the Index View
16+
17+
Perseus' index view is very versatile, but there are a few things you HAVE to include, or Perseus moves into undefined behavior, and almost anything could happen! This mostly translates to your app just spitting out several hundred errors when it tries to build though, because none of the tactics Perseus uses to insert itself into your app will work anymore.
18+
19+
1. You need a `<head>`. This can be empty, but it needs to be present in the form `<head></head>` (no self-closing tags allowed). The reason for this is that Perseus uses these tags as markers for inserting components of the magical metadata that makes your app work.
20+
2. You need a `<body>`. This needs to be defined as `<body></body>`, for similar reasons to the `<head>`.
21+
3. You need a `<div id="root"></div>`. Literally, you need that *exact* string in your index view, or Perseus won't be able to find your app at all! Now, yes we could parse the HTML fully and find this by ID, or we could just use string replacement and reduce dependencies and build time. Importantly, you can't use this directly is you use `.index_view()` and provide Sycamore code, as Sycamore will add some extra information that stuffs things up. Instead, you should use `perseus::PerseusRoot`, which is specially designed to be a drop-in entrypoint for Perseus. It should go without saying that you need to put this in the `<body>` of your app.
22+
23+
*Note: you don't need the typical `<!DOCTYPE html>`in your index view, since that's all Perseus targets, so it's added automatically. If, for some magical reason, you need to override this, you can do so with a [control plugin](reference/plugins/control).*
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# `PerseusApp`
2+
3+
The core of Perseus is how it interacts with the code in `.perseus/`, which defines the engine that actually runs your app. Of course, to perform this interaction, you need to be able to tell the engine details about your app, like the templates you've written, the error pages you want to use, etc. All this is done through the `PerseusApp` `struct`, which acts as a bridge between your code and the engine, so this is essentially the core of Perseus, from the perspective of building apps with it.
4+
5+
The way you define `PerseusApp` in any Perseus app is by creating a function that returns an instance of it, with a type parameter (usually called `G`) of type `Html`, which gives Perseus the flexibility to render your app on both the server-side (as it needs to do for prerendering) and in a browser. You need to export this from the root of your app (`lib.rs`), and it's conventional to define it there too as a function called `main` or something similar. Notably, what you call this function is completely irrelevant, provided it has the `#[perseus::main]` attribute macro annotating it, which automatically tells Perseus to use it as your main function.
6+
7+
<details>
8+
<summary>What does that attribute macro do?</summary>
9+
10+
Currently, `#[perseus::main]` just wraps your function in another one with the name `__perseus_entrypoint`, but this behavior could change at any time, so using this macro isn't optional! For example, in future it might modify your code in some crucial way, and such a modification to the macro would be considered a non-breaking change, which means your code could break in production. To be safe, use the macro (or pin Perseus to a specific minor version if you *really* hate it).
11+
12+
</details>
13+
14+
The smallest this can reasonably get is a fully self-contained app (taken from [here](https://github.com/arctic-hen7/perseus/tree/main/examples/comprehensive/tiny/src/lib.rs)):
15+
16+
```rust
17+
{{#include ../../../examples/comprehensive/tiny/src/lib.rs}}
18+
```
19+
20+
In a more complex app though, this macro still remains very manageable (taken from [here](https://github.com/arctic-hen7/perseus/tree/main/examples/core/state_generation/src/lib.rs)):
21+
22+
```rust
23+
{{#include ../../../examples/core/state_generation/src/lib.rs}}
24+
```
25+
26+
Note that, in theory, you could just define your entire app with `PerseusApp::new()`, and this would work, but you would have no pages and no functionality whatsoever. This might be a good way of benchmarking a server's performance with Perseus, perhaps??
27+
28+
## Configuration
29+
30+
To learn about all the functions this macro supports, see [here](https://docs.rs/perseus/latest/perseus/struct.PerseusApp.html).
31+
32+
Again, `PerseusApp` is just a bridge, so all the features you can use through it are documented elsewhere on this site.

docs/next/en-US/reference/plugins/control.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ If you'd like to request that a new action, functional or control, be added, ple
1212

1313
_Note: there are currently very few control actions, and this list will be expanded over time._
1414

15-
- `settings_actions` -- actions that can alter the settings provided by the user with [`define_app!`](:reference/define-app)
15+
- `settings_actions` -- actions that can alter the settings provided by the user with [`PerseusApp`](:reference/perseus-app)
1616
- `set_immutable_store` -- sets an alternative [immutable store](:reference/stores) (e.g. to store data somewhere other than the filesystem for some reason)
1717
- `set_locales` -- sets the app's locales (e.g. to fetch locales from a database in a more convenient way)
1818
- `set_app_root` -- sets the HTML `id` of the `div` in which to render Perseus (e.g. to fetch the app root from some other service)

docs/next/en-US/reference/plugins/functional.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Here's a list of all the functional actions currently supported by Perseus, whic
99
If you'd like to request that a new action, functional or control, be added, please [open an issue](https://github.com/arctic-hen7/perseus/issues/new/choose).
1010

1111
- `tinker` -- see [this section](:reference/plugins/tinker)
12-
- `settings_actions` -- actions that can alter the settings provided by the user with [`define_app!`](:reference/define-app)
12+
- `settings_actions` -- actions that can alter the settings provided by the user with [`PerseusApp`](:reference/perseus-app)
1313
- `add_static_aliases` -- adds extra static aliases to the user's app (e.g. a [TailwindCSS](https://tailwindcss.com) stylesheet)
1414
- `add_templates` -- adds extra templates to the user's app (e.g. a prebuilt documentation system)
1515
- `add_error_pages` -- adds extra [error pages](:reference/error-pages) to the user's app (e.g. a prebuilt 404 page)

docs/next/en-US/reference/plugins/using.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ The plugins system is designed to be as easy as possible to use, and you can imp
66
{{#include ../../../../examples/core/plugins/src/lib.rs}}
77
```
88

9-
In addition to the usual `define_app!` calls, this also uses the `plugins` parameter, passing to it an instance of `perseus::plugins::Plugins`, which manages all the intricacies of the plugins system. If this parameter isn't provided, it'll default to `Plugins::new()`, which creates the configuration for plugins without registering any.
9+
In addition to the usual `PerseusApp` setup, this also uses the `.plugins()` function, passing to it an instance of `perseus::plugins::Plugins`, which manages all the intricacies of the plugins system. If this parameter isn't provided, it'll default to `Plugins::new()`, which creates the configuration for plugins without registering any.
1010

1111
To register a plugin, we use the `.plugin()`/`.plugin_with_client_privilege()` function on `Plugins`, which takes two parameters: the plugin's definition (a `perseus::plugins::Plugin`) and any data that should be provided to the plugin. The former should be exported from the plugin's crate, and the latter you'll need to provide based on the plugin's documentation. Note that plugins can accept almost anything as data (specifically, anything that can be expressed as `dyn Any`).
1212

docs/next/en-US/reference/plugins/writing.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ However, because Perseus is juggling all the data for all the plugins the user h
3838
Right now, there are few things that you can't do with Perseus plugins, which can be quite weird.
3939

4040
- You can't extend the engine's server (due to a limitation of Actix Web types), you'll need to manually run a `tinker` on it (add your code into the file by writing it in using [the `tinker` action](:reference/plugins/tinker))
41-
- You can't set the [mutable store](:reference/stores) from a plugin due to a traits issue, so you'll need to provide something for the user to provide to the `mutable_store` parameter of the `define_app!` macro
41+
- You can't set the [mutable store](:reference/stores) from a plugin due to a traits issue, so you'll need to provide something for the user to set as a custom mutable store (see [here](:reference/stores/))
4242
- Similarly, you can't set the translations manager from a plugin
4343

4444
## Plugin Environments

docs/next/en-US/reference/state/global.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ To being with, you'll need to set up a `GlobalStateCreator`, which will look som
2323
{{#include ../../../../examples/core/global_state/src/global_state.rs}}
2424
```
2525

26-
Then, you can tell Perseus about that by adding it to `define_app!` like so:
26+
Then, you can tell Perseus about that by adding it to `PerseusApp` like so:
2727

2828
```rust
2929
{{#include ../../../../examples/core/global_state/src/lib.rs}}

0 commit comments

Comments
 (0)