|
| 1 | +# CLI |
| 2 | + |
| 3 | +Perseus has a CLI (command line interface) designed to make your life significantly easier when developing Perseus apps. Its primary functions are to build and serve your apps for you, meaning you can focus pretty much entirely on your application code and ignore all the boilerplate! |
| 4 | + |
| 5 | +## Installation |
| 6 | + |
| 7 | +You can install the Perseus CLI by running `cargo install perseus-cli`, it should then be available as `perseus` on your system! |
| 8 | + |
| 9 | +We currently don't provide independent executables installable without `cargo` because you'll need `cargo` and Rust generally to be able to write a Perseus app, and Perseus depends on the `cargo` commands being available, so there's really no point. That said, if you have a use-case for this, please [open an issue](https://github.com/arctic-hen7/perseus/issues/new/choose)! |
| 10 | + |
| 11 | +## Setup |
| 12 | + |
| 13 | +Set up a library project with `cargo`, and add the following to the `[dependencies]` section in your `Cargo.toml`: |
| 14 | + |
| 15 | +```toml |
| 16 | +perseus = { path = "../../packages/perseus" } |
| 17 | +sycamore = { version = "0.5.1", features = ["ssr"] } |
| 18 | +sycamore-router = "0.5.1" |
| 19 | +# You only need these for pages that take properties |
| 20 | +serde = { version = "1", features = ["derive"] } |
| 21 | +serde_json = "1" |
| 22 | +``` |
| 23 | + |
| 24 | +Then, add a `lib.rs` file to your project under `src/` that contains the following: |
| 25 | + |
| 26 | +```toml |
| 27 | +mod pages; |
| 28 | +mod error_pages; |
| 29 | + |
| 30 | +use perseus::define_app; |
| 31 | + |
| 32 | +#[derive(perseus::Route)] |
| 33 | +pub enum Route { |
| 34 | + #[to("/")] |
| 35 | + Index, |
| 36 | + #[to("/about")] |
| 37 | + About, |
| 38 | + #[not_found] |
| 39 | + NotFound, |
| 40 | +} |
| 41 | +define_app!{ |
| 42 | + root: "#root", |
| 43 | + route: Route, |
| 44 | + router: { |
| 45 | + Route::Index => [ |
| 46 | + "index".to_string(), |
| 47 | + pages::index::template_fn() |
| 48 | + ], |
| 49 | + Route::About => [ |
| 50 | + "about".to_string(), |
| 51 | + pages::about::template_fn() |
| 52 | + ] |
| 53 | + } |
| 54 | + error_pages: crate::error_pages::get_error_pages(), |
| 55 | + templates: [ |
| 56 | + crate::pages::index::get_template::<G>(), |
| 57 | + crate::pages::about::get_template::<G>() |
| 58 | + ] |
| 59 | + // config_manager: perseus::FsConfigManager::new() |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +This assumes you've defined a function to get your error pages elsewhere (you can read more about that [here](error_pages.md)), and that it's in a module called `error_pages`, you can customize that as needed. |
| 64 | + |
| 65 | +The way the rest of this works is pretty simple. First off, you define a router with [Sycamore](https://sycamore-rs.netlify.app/docs/advanced/routing), which defines each of your templates and the paths on your site that it will accept. This **must** have a variant explicitly named `NotFound`, that's handled for you. Then, you define your app itself, which takes the following properties (which need to be in order right now!): |
| 66 | + |
| 67 | +- `root` – the CSS selector for the element to render Perseus to, which should be unique, like an HTML `id` |
| 68 | +- `route` – the `enum` for your app's routes that you just defined |
| 69 | +- `router` – a match-like input that handles each of the variants of your `route`, except `NotFound` (handled for you); each one gets mapped to the corresponding page's path (e.g. `Post` with slug `test` might be mapped to `format!("post/{}", slug)`), which shouldn't include a leading or trailing `/` |
| 70 | +- `error_pages` – your [error pages](error_pages.md) |
| 71 | +- `templates` – each of your templates, taking the `G` parameter (which will be used at runtime to render them for the server or the client) |
| 72 | +- `config_manager` (optional) – the [config manager](config_manager.md) your app should use, default is the inbuilt `FsConfigManager::new()` |
| 73 | + |
| 74 | +## Usage |
| 75 | + |
| 76 | +Once you've got that out of the way, go ahead and define your templates as usual, and then run the following command in your project's directory: |
| 77 | + |
| 78 | +``` |
| 79 | +perseus serve |
| 80 | +``` |
| 81 | + |
| 82 | +That will automatically prepare the CLI to work with your app, then it will build your app and statically generate everything as appropriate (using any custom config manager your specified), and then it will serve your app on <http://localhost:8080> by default! |
| 83 | + |
| 84 | +If you want to change the host/port your app is served on, just set the `HOST`/`PORT` environment variables as you'd like. |
| 85 | + |
| 86 | +## Other Commands |
| 87 | + |
| 88 | +If you just want to build your app, you can run `perseus build`. If you only want to prepare the CLI to interface with your app (which creates a `.perseus/` directory), you can run `perseus prep`. |
| 89 | + |
| 90 | +If you want to serve pre-built files (which you'll have to generate with `perseus build`), you can run `perseus serve --no-build`. |
| 91 | + |
| 92 | +## Watching |
| 93 | + |
| 94 | +All these commands act statically, they don't watch your code for any changes. This feature will be added _very_ soon to the CLI, but until it is, we advise you to use a tool like [`entr`](https://github.com/eradman/entr), which you can make work with Perseus like so (on Linux): |
| 95 | + |
| 96 | +``` |
| 97 | +find . -not -path "./.perseus/*" -not -path "./target/*" | entr -s "perseus serve" |
| 98 | +``` |
| 99 | + |
| 100 | +This just lists all files except those in `.perseus/` and `target/` and runs `perseus serve` on any changes. You should exclude anything else as necessary. |
0 commit comments