Skip to content

Commit a85f150

Browse files
committed
docs(book): 📝 updated docs for plugins system changes
1 parent 686f369 commit a85f150

File tree

4 files changed

+22
-32
lines changed

4 files changed

+22
-32
lines changed

docs/0.3.x/en-US/plugins/using.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ The plugins system is designed to be as easy as possible to use, and you can imp
88

99
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.
1010

11-
To register a plugin, we use the `.plugin()` 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`).
11+
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`).
12+
13+
Plugins in Perseus are fantastic, but they're also a great way to increase your Wasm bundle size, which will make your website slower to laod when users first visit it. To mitigate this, Perseus lets plugin authors define where their plugins should run: in the browser (`PluginEnv::Client`), on the server-side (`PluginEnv::Server`), or on both (`PluginEnv::Both`). Plugins that only run on the server-side should be registered with `.plugin()`, and they will not be included in your final Wasm binary, which keeps your website nimble. If a plugin does need to run on the client though, it can be registered with `.plugin_with_client_privilege()` instead, which is named separately for conditional compilation reasons as well as to create a clear separation. But don't worry, if you accidentally register a plugin with the wrong function, your app won'y build, and Perseus will tell you that you've used the wrong function.

docs/0.3.x/en-US/plugins/writing.md

+4-11
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ To define a plugin, you'll call `perseus::plugins::Plugin::new()`, which takes f
1313
- The name of the plugin as a `&str`, which should be the name of the crate the plugin is in (or the name of a larger app with some extension) (**all plugins MUST have unique names**)
1414
- A [functional actions](:plugins/functional) registrar function, which is given some functional actions and then extends them
1515
- A [control actions](:plugins/control) registrar, which is given some control actions and then extends them
16-
- Whether or not the plugin should only run at `tinker`-time (see below)
16+
- The environment for the plugin to run in (see below)
1717

1818
Here's an example of a very simple plugin that adds a static alias for the project's `Cargo.toml`, creates an about page, and prints the working directory at [tinker](:plugins/tinker)-time (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/plugins/src/plugin.rs)):
1919

@@ -41,15 +41,8 @@ Right now, there are few things that you can't do with Perseus plugins, which ca
4141
- You can't set the [mutable store](: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
4242
- Similarly, you can't set the translations manager from a plugin
4343

44-
## Tinker-Only Plugins
44+
## Plugin Environments
4545

46-
There are some cases of plugin development in which a plugin only uses [the `tinker` action](:plugins/tinker), and therefore it should only be included when the user is running `perseus tinker`. The main reason you'd want to do this is to prevent your plugin from becoming part of the client-side Wasm bundle, which will be served to browsers. For example, a size optimizations plugin only needs to run at tinker-time, and, if it were allowed to leak into the client-side bundle, it would actually increase the bundle size because it draws in all its dependencies!
46+
As explained [here](:plugins/using), plugins can either run on the client (`PluginEnv::Client`), the server-side (`PluginEnv::Server`), or on both (`PluginEnv::Both`). Note that the server-side includes `tinker`-time and during the build process. If your plugin does not absolutely need to run on the client, use `PluginEnv::Server`! Your users will thank you for their much smaller bundles! If you don't do this, every single dependency of your plugin will end up in the user's final Wasm bundle, which has to be sent to browsers, and bundle sizes can end up doubling or more as a result! If this is the case though, make sure to tell your users to register your plugin using `.plugin_with_client_privilege()` rather than just `.plugin()` (but don't stress, they'll get an explanatory error if they use the wrong one accidentally).
4747

48-
You can make your plugin tinker-only by setting the fourth argument to `Plugin::new()` to `true`.
49-
50-
<details>
51-
<summary>I want my plugin to run on the server, but not the client.</summary>
52-
53-
You should make it a tinker-only plugin. As a technicality, tinker-only plugins will actually run on the server and in the build process in addition to the `tinker` process. They just won't run on the client. Be warned though: a future release may well change this.
54-
55-
</details>
48+
You can set the environment your plugin runs on by changing the fourth argument to a variant of `PluginEnv`.

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ The plugins system is designed to be as easy as possible to use, and you can imp
88

99
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.
1010

11-
To register a plugin, we use the `.plugin()` 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`).
11+
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`).
12+
13+
Plugins in Perseus are fantastic, but they're also a great way to increase your Wasm bundle size, which will make your website slower to laod when users first visit it. To mitigate this, Perseus lets plugin authors define where their plugins should run: in the browser (`PluginEnv::Client`), on the server-side (`PluginEnv::Server`), or on both (`PluginEnv::Both`). Plugins that only run on the server-side should be registered with `.plugin()`, and they will not be included in your final Wasm binary, which keeps your website nimble. If a plugin does need to run on the client though, it can be registered with `.plugin_with_client_privilege()` instead, which is named separately for conditional compilation reasons as well as to create a clear separation. But don't worry, if you accidentally register a plugin with the wrong function, your app won'y build, and Perseus will tell you that you've used the wrong function.

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

+12-19
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ A plugin will usually occupy its own crate, but it may also be part of a larger
1010

1111
To define a plugin, you'll call `perseus::plugins::Plugin::new()`, which takes four parameters:
1212

13-
- The name of the plugin as a `&str`, which should be the name of the crate the plugin is in (or the name of a larger app with some extension) (**all plugins MUST have unique names**)
14-
- A [functional actions](:plugins/functional) registrar function, which is given some functional actions and then extends them
15-
- A [control actions](:plugins/control) registrar, which is given some control actions and then extends them
16-
- Whether or not the plugin should only run at `tinker`-time (see below)
13+
- The name of the plugin as a `&str`, which should be the name of the crate the plugin is in (or the name of a larger app with some extension) (**all plugins MUST have unique names**)
14+
- A [functional actions](:plugins/functional) registrar function, which is given some functional actions and then extends them
15+
- A [control actions](:plugins/control) registrar, which is given some control actions and then extends them
16+
- The environment for the plugin to run in (see below)
1717

1818
Here's an example of a very simple plugin that adds a static alias for the project's `Cargo.toml`, creates an about page, and prints the working directory at [tinker](:plugins/tinker)-time (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/plugins/src/plugin.rs)):
1919

@@ -25,31 +25,24 @@ One particularly important thing to note here is the absence of any control acti
2525

2626
Another notable thing is the presence of `GenericNode` as a type parameter, because some plugin actions take this, so you'll need to pass it through. We also tell Perseus what type of data out plugin will take in the second type parameter, which enables type checking in the `.plugin()` call when the user imports the plugin.
2727

28-
The rest of the code is the functional actions registrar, which just registers the plugin on the `functional_actions.settings_actions.add_static_aliases`, `functional_actions.settings_actions.add_templates`, and `functional_actions.tinker` actions. The functions provided to the `.register_plugin()` function are *runners*, which will be executed at the appropriate time by the Perseus engine. Runners take two parameters, *action data*, and *plugin data*. Action data are data provided to every runner for the given action (e.g. an action that runs after a failed build will be told what the error was). You should refer to [the API docs](https://docs.rs/perseus) to learn more about these for different actions. The second parameter is plugin data, covered below.
28+
The rest of the code is the functional actions registrar, which just registers the plugin on the `functional_actions.settings_actions.add_static_aliases`, `functional_actions.settings_actions.add_templates`, and `functional_actions.tinker` actions. The functions provided to the `.register_plugin()` function are _runners_, which will be executed at the appropriate time by the Perseus engine. Runners take two parameters, _action data_, and _plugin data_. Action data are data provided to every runner for the given action (e.g. an action that runs after a failed build will be told what the error was). You should refer to [the API docs](https://docs.rs/perseus) to learn more about these for different actions. The second parameter is plugin data, covered below.
2929

3030
## Plugin Data
3131

3232
Quite often, plugins should accept user configuration, and this is supported through the second runner parameter, which will be given any data that the user defined for your plugin. You can define the type of this with the second type parameter to `Plugin`.
3333

34-
However, because Perseus is juggling all the data for all the plugins the user has installed, across all their different runners, it can't store the type of the data that the user gives (but don't worry, whatever they provide will be type-checked). This means that your runner ends up being given what Rust considers to be *something*. Basically, **we know that it's your plugin data, but Rust doesn't**. Specifically, you'll be given `&dyn Any`, which means you'll need to *downcast* this to a concrete type (the type of your plugin data). As in the above example, we can do this with `plugin_data.downcast_ref::<YourPluginDataTypeHere>()`, which will return an `Option<T>`. **This will always be `Some`**, which is why it's perfectly safe to label the `None` branch as `unreachable!()`. If this ever does result in `None`, then either you've tried to downcast to something that's not your plugin's data type, or there's a critical bug in Perseus' plugins system, which you should [report to us](https://github.com/arctic-hen7/perseus/issues/new/choose).
34+
However, because Perseus is juggling all the data for all the plugins the user has installed, across all their different runners, it can't store the type of the data that the user gives (but don't worry, whatever they provide will be type-checked). This means that your runner ends up being given what Rust considers to be _something_. Basically, **we know that it's your plugin data, but Rust doesn't**. Specifically, you'll be given `&dyn Any`, which means you'll need to _downcast_ this to a concrete type (the type of your plugin data). As in the above example, we can do this with `plugin_data.downcast_ref::<YourPluginDataTypeHere>()`, which will return an `Option<T>`. **This will always be `Some`**, which is why it's perfectly safe to label the `None` branch as `unreachable!()`. If this ever does result in `None`, then either you've tried to downcast to something that's not your plugin's data type, or there's a critical bug in Perseus' plugins system, which you should [report to us](https://github.com/arctic-hen7/perseus/issues/new/choose).
3535

3636
## Caveats
3737

3838
Right now, there are few things that you can't do with Perseus plugins, which can be quite weird.
3939

40-
- 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](:plugins/tinker))
41-
- You can't set the [mutable store](: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
42-
- Similarly, you can't set the translations manager from a plugin
40+
- 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](:plugins/tinker))
41+
- You can't set the [mutable store](: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
42+
- Similarly, you can't set the translations manager from a plugin
4343

44-
## Tinker-Only Plugins
44+
## Plugin Environments
4545

46-
There are some cases of plugin development in which a plugin only uses [the `tinker` action](:plugins/tinker), and therefore it should only be included when the user is running `perseus tinker`. The main reason you'd want to do this is to prevent your plugin from becoming part of the client-side Wasm bundle, which will be served to browsers. For example, a size optimizations plugin only needs to run at tinker-time, and, if it were allowed to leak into the client-side bundle, it would actually increase the bundle size because it draws in all its dependencies!
46+
As explained [here](:plugins/using), plugins can either run on the client (`PluginEnv::Client`), the server-side (`PluginEnv::Server`), or on both (`PluginEnv::Both`). Note that the server-side includes `tinker`-time and during the build process. If your plugin does not absolutely need to run on the client, use `PluginEnv::Server`! Your users will thank you for their much smaller bundles! If you don't do this, every single dependency of your plugin will end up in the user's final Wasm bundle, which has to be sent to browsers, and bundle sizes can end up doubling or more as a result! If this is the case though, make sure to tell your users to register your plugin using `.plugin_with_client_privilege()` rather than just `.plugin()` (but don't stress, they'll get an explanatory error if they use the wrong one accidentally).
4747

48-
You can make your plugin tinker-only by setting the fourth argument to `Plugin::new()` to `true`.
49-
50-
<details>
51-
<summary>I want my plugin to run on the server, but not the client.</summary>
52-
53-
You should make it a tinker-only plugin. As a technicality, tinker-only plugins will actually run on the server and in the build process in addition to the `tinker` process. They just won't run on the client. Be warned though: a future release may well change this.
54-
55-
</details>
48+
You can set the environment your plugin runs on by changing the fourth argument to a variant of `PluginEnv`.

0 commit comments

Comments
 (0)