-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: ✨ added support for server to run as standalone binary This enables realistic production deployments. * feat: ✨ added ability to deploy with single command Standalone package folders can be created easily now. * docs(book): 📝 added docs for deployment * feat(templates): ✨ switched to `ImmutableStore` from `ConfigManager` It's currently used in places it shouldn't be, `MutableStore` coming soon BREAKING CHANGE: removed `ConfigManager` in favor of `ImmutableStore`, replaced `config_manager` with `dist_path` in `define_app!` * feat: ✨ created `MutableStore` for mutable build artifacts This replaces `ConfigManager` fully. BREAKING CHANGE: many function signatures now include `MutableStore`, changes to `dist/` structure, `mutable_store` now in `define_app!`, `RouteInfo` includes `was_incremental_match` * docs(book): 📝 added docs for new stores system * refactor(examples): ♻️ refactored perseus idioms to make more sense Specifically, template functions are now defined inside the `get_template` function. * docs(book): 📝 updated docs for current state of features * fix: 🐛 fixed inconsistencies in paths given to build paths vs incremental Build paths used to get locale as well in path, not anymore. * chore: 🙈 ignored testing deployments * fix: 🐛 fixed content being interpolated in head in production Just a missing `.head.html` rather than `.html`.
- Loading branch information
1 parent
85b6712
commit a8989dd
Showing
58 changed files
with
1,005 additions
and
443 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 |
---|---|---|
@@ -1,2 +1,3 @@ | ||
/target | ||
Cargo.lock | ||
pkg/ |
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
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
This file was deleted.
Oops, something went wrong.
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
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 |
---|---|---|
@@ -1,5 +1,25 @@ | ||
# Deploying | ||
|
||
> **WARNING:** although Perseus is technically ready for deployment, the system is not yet recommended for production! See [here](../what-is-perseus.md#how-stable-is-it) for more details. | ||
Perseus is a complex system, but we aim to make deploying it as easy as possible. This section will describe a few different types of Perseus deployments, and how they can be managed. | ||
|
||
*Note: Perseus deployment is still under design and development, so this information in particular is subject to rapid change before v1.0.0.* | ||
## Release Mode | ||
|
||
The Perseus CLI supports the `--release` flag on the `build`, `serve`, and `export` commands. When you're preparing a production release of your app, be sure to use this flag! | ||
|
||
## `perseus deploy` | ||
|
||
If you haven't [ejected](../cli/ejecting.md), then you can prepare your app for deployment with a single command: `perseus deploy`. If you can use [static exporting](../exporting.md), then you should run `perseus deploy -e`, otherwise you should just use `perseus deploy`. | ||
|
||
This will create a new directory `pkg/` for you (you can change that by specifying `--output`) which will contain everything you need to deploy your app. That directory is entirely self-contained, and can be copied to an appropriate hosting provider for production deployment! | ||
|
||
Note that this command will run a number of optimizations in the background, including using the `--release` flag, but it won't try to aggressively minimize your Wasm code size. For tips on how to do that, see [here](./size.md). | ||
|
||
### Static Exporting | ||
|
||
If you use `perseus deploy -e`, the contents of `pkg/` can be served by any file host that can handle the [slight hiccup](../exporting.md#file-extensions) of file extensions. Locally, you can test this out with [`serve`](https://github.com/vercel/serve), a JavaScript package designed for this purpose. | ||
|
||
### Fully-Fledged Server | ||
|
||
If you just use `perseus deploy`, the `pkg/` directory will contain a binary called `server` for you to run, which will serve your app on its own. However, it's important to note that this binary is structured to support either the development configuration of running inside `.perseus/` or the production configuration of running inside `pkg/`, and you have to provide the `PERSEUS_STANDALONE` environment variable to tell it to do the latter. This binary can then be run on any server with a writable filesystem. For more details on this, see the next subsection. |
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,27 @@ | ||
# Server Deployment | ||
|
||
If your app uses rendering strategies that need a server, you won't be able to export your app to purely static files, and so you'll need to host the Perseus server itself. | ||
|
||
You can prepare your production server by running `perseus deploy`, which will create a new directory called `pkg/`, which will contain the standalone binary and everything needed to run it. You should then upload this file to your server and set the `PERSEUS_STANDALONE` environment variable to `true` so that Perseus expects a standalone binary configuration. Note that this process will vary depending on your hosting provider. | ||
|
||
## Hosting Providers | ||
|
||
As you may recall from [this section](../stores.md) on immutable and mutable stores, Perseus modifies some data at runtime, which is problematic if your hosting provider imposes the restriction that you can't write to the filesystem (as Netlify does). Perseus automatically handles this as well as it can by separating out mutable from immutable data, and storing as much as it can on the filesystem without causing problems. However, data for pages that use the *revalidation* or *incremental generation* strategies must be placed in a location where it can be changed while Perseus is running. | ||
|
||
If you're only using *build state* and/or *build paths* (or neither), you should export your app to purely static files instead, which you can read more about doing [here](../exporting.md). That will avoid this entire category of problems, and you can deploy basically wherever you want. | ||
|
||
If you're bringing *request state* into the mix, you can't export to static files, but you can run on a read-only filesystem, because only the *revalidation* and *incremental generation* strategies require mutability. Perseus will use a mutable store on the filesystem in the background, but won't ever need it. | ||
|
||
If you're using *revalidation* and *incremental generation*, you have two options, detailed below. | ||
|
||
### Writable Filesystems | ||
|
||
The first of these is to use an old-school provider that gives you a filesystem that you can write to. This may be more expensive for hosting, but it will allow you to take full advantage of all Perseus' features in a highly performant way. | ||
|
||
You can deploy to one of these providers without any further changes to your code, as they mimic your local system almost entirely (with a writable filesystem). Just run `perseus deploy` and copy the resulting `pkg/` folder to the server! | ||
|
||
### Alternative Mutable Stores | ||
|
||
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. | ||
|
||
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. |
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 @@ | ||
# Serverless Deployment | ||
|
||
> This strategy of Perseus deployment will be possible eventually, but right now more work needs to be done on support for read-only filesystems before work on this can even be considered. |
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,43 @@ | ||
# Optimizing Code Size | ||
|
||
If you're used to working with Rust, you're probably used to two things: performance is everything, and Rust produces big binaries. With Wasm, these actually become problems because of the way the web works. If you think about it, your Wasm files (big because Rust optimizes for speed instead of size by default) need to be sent to browsers. So, the larger they are, the slower your site will be. Fortunately, Perseus only makes this relevant when a user first navigates to your site with its [subsequent loads](../advanced/subsequent-loads.md) system. However, it's still worth optimizing code size in places. | ||
|
||
If you've worked with Rust and Wasm before, you may be familiar with `wasm-opt`, which performs a ton of optimizations for you. Perseus does this automatically with `wasm-pack`. But we can do better. | ||
|
||
## `wee_alloc` | ||
|
||
Rust's memory allocator takes up quite a lot of space in your final Wasm binary, and this can be solved by trading off performance for smaller sizes, which can actually make your site snappier because it will load faster. `wee_alloc` is an alternative allocator built for Wasm, and you can enable it by adding it to your `Cargo.toml` as a dependency: | ||
|
||
```toml | ||
wee_alloc = "0.4" | ||
``` | ||
|
||
And then you can add it to the top of your `src/lib.rs`: | ||
|
||
```rust,no_run,no_playground | ||
#[global_allocator] | ||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; | ||
``` | ||
|
||
With the [basic example](https://github.com/arctic-hen7/perseus/tree/main/examples/basic), we saw improvements from 369.2kb to 367.8kb with `wee_alloc` and release mode. These aren't much though, and we can do better. | ||
|
||
## Aggressive Optimizations | ||
|
||
More aggressive optimizations need to be applied to both Perseus' engine and your own code, so you'll need to [eject](../ejecting.md) for this to work properly. Just run `perseus eject`, and then add the following to `.perseus/Cargo.toml`: | ||
|
||
```toml | ||
[profile.release] | ||
lto = true | ||
opt-level = "z" | ||
``` | ||
|
||
Then add the same thing to your own `Cargo.toml`. Note that, if this is the only modification you make after ejecting, `perseus deploy` will still work perfectly as expected. | ||
|
||
What this does is enable link-time optimizations, which do magic stuff to make your code smaller, and then we set the compiler to optimize aggressively for speed. On the [basic example](https://github.com/arctic-hen7/perseus/tree/main/examples/basic), we say improvements from 367.8kb with `wee_alloc` and release mode to 295.3kb when we added these extra optimizations. That's very significant, and we recommend using these if you don't have a specific reason not to. Note however that you should definitely test your site's performance after applying these to make sure that you feel you've achieved the right trade-off between performance and speed. If not, you could try setting `opt-level = "s"` instead of `z` to optimize less aggressively for speed, or you could try disabling some optimizations. | ||
|
||
<details> | ||
<summary>Read this if something blows up in your face.</summary> | ||
|
||
As of time of writing, Netlify (and possibly other providers) doesn't support Rust binaries that use `lto = true` for some reason, it simply doesn't detect them, so you shouldn't use that particular optimization if you're working with Netlify. | ||
|
||
</details> |
6 changes: 2 additions & 4 deletions
6
docs/next/src/deploying/exporting.md → docs/next/src/exporting.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 |
---|---|---|
@@ -1,13 +1,11 @@ | ||
# Static Exporting | ||
|
||
The easiest way to deploy Perseus is as a set of static files, which is supported if your app uses only the _build state_ and _build paths_ strategies, or none at all. If you use _incremental generation_, _revalidation_, or _request state_ in any of your templates though, you can't export your app to static file, because these strategies require a custom server. For these cases, please continue to the rest of this section to learn how to deploy your more complex setup. | ||
|
||
However, if your app only needs to run server-side computations at build-time, then you can export it to a set of static files without changing anything, simply by running `perseus export`. This will create a new directory called `.perseus/dist/exported`, the contents of which can be served on a system like [GitHub Pages](https:://pages.github.com). Your app should behave in the exact same way with exporting as with normal serving. If this isn't the case, please [open an issue](https://github.com/arctic-hen7/perseus/issues/new/choose). | ||
Thus far, we've used `perseus serve` to build and serve Perseus apps, but there is an alternative way that offers better performance in some cases. Namely, if your app doesn't need any rendering strategies that can't be run at build time (so if you're only using *build state* and/or *build paths* or neither), you can export your app to a set of purely static files that can be served by almost any hosting provider. You can do this by running `perseus export`, which will create a new directory `.perseus/dist/exported/`, the contents of which can be served on a system like [GitHub Pages](https:://pages.github.com). Your app should behave in the exact same way with exporting as with normal serving. If this isn't the case, please [open an issue](https://github.com/arctic-hen7/perseus/issues/new/choose). | ||
|
||
There is only one known difference between the behavior of your exported site and your normally served site, and that's regarding [static aliases](../static-content.md). In a normal serving scenario, any static aliases that conflicted with a Perseus page or internal asset would be ignored, but, in an exporting context, **any static aliases that conflict with Perseus pages will override them**! If you suspect this might be happening to you, try exporting without those aliases and make sure the URL of your alias file doesn't already exist (in which case it would be a Perseus component). | ||
|
||
## File Extensions | ||
|
||
One slight hiccup with Perseus' static exporting system comes with regards to the `.html` file extension. Perseus' server expects that pages shouldn't have such extensions (hence `/about` rather than `/about.html`), but, when statically generated, they must have these extensions in the filesystem. So, if you don't want these extensions for your users (and if you want consistent behavior between exporting and serving), it's up to whatever system you're hosting your files with to strip these extensions. Many systems do this automatically, though some (like Python's `http.server`) do not. | ||
|
||
One of the best systems for testing static exporting on your local machine is the [`serve`](https://github.com/versel/serve) JavaScript package, which can be run from the command-line without touching any JavaScript, and it handles this problem automatically. However, other solutions certainly exist if you don't want any JS polluting your system! | ||
One of the best systems for testing static exporting on your local machine is the [`serve`](https://github.com/vercel/serve) JavaScript package, which can be run from the command-line without touching any JavaScript, and it handles this problem automatically. However, other solutions certainly exist if you don't want any JS polluting your system! |
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
Oops, something went wrong.