allow to send static compiled file when 404
prabirshrestha opened this issue · comments
I have a trillium server that is backed by create-react-app.
In dev mode I would like to proxy directly to the server created by create-react-app, while in release mode I would like to serve the file that is embedded in the binary. Working sample of this can be found at https://github.com/prabirshrestha/objstor/pull/16.
Here is the main snippet:
use trillium::Handler;
#[cfg(not(debug_assertions))]
lazy_static_include::lazy_static_include_str! {
INDEX_HTML => "../client/build/index.html",
}
#[cfg(debug_assertions)]
pub fn spa() -> impl Handler {
use trillium_rustls::RustlsConnector;
use trillium_tokio::TcpConnector;
type Proxy = trillium_proxy::Proxy<RustlsConnector<TcpConnector>>;
Proxy::new("http://localhost:3000")
}
#[cfg(not(debug_assertions))]
pub fn spa() -> impl Handler {
use trillium_static_compiled::static_compiled;
let handler = static_compiled!("../client/build").with_index_file("index.html");
(handler, serve_index_file)
}
#[cfg(not(debug_assertions))]
async fn serve_index_file(conn: trillium::Conn) -> trillium::Conn {
conn.with_header("content-type", "text/html; charset=UTF-8")
.ok(INDEX_HTML.as_bytes())
}
I had to introduce lazy_static_include
library and do a bit of custom code. It would be great if this was simplified as it is a common pattern for single page applications where there is usually just a single html file with most of the code logic in js. This could then be simplified as following.
#[cfg(not(debug_assertions))]
pub fn spa() -> impl Handler {
trillium_static_compiled::static_compiled!
("../client/build").with_index_file("index.html").with_fallback_file("index.html")
}
The other option would be to introduce static_compiled_file
but then the file contents would be duplicated.
Why doesn't an include_str
based handler work for this?
#[cfg(not(debug_assertions))]
async fn serve_index_file(conn: trillium::Conn) -> trillium::Conn {
conn.with_header(trillium::KnownHeaderName::ContentType, "text/html; charset=UTF-8")
.ok(include_str!("../client/build/index.html"))
}
This is identical to a "404 not found" handler that I've written a few times and realized it's actually far more expressive to just write as a handler fn
It works. Seems like I had to change my path to use ../../
instead of ../
. Hence I was using lazy_static_include_str
.
I went further and inlined it. Should be good for now.
use trillium::Handler;
#[cfg(debug_assertions)]
pub fn spa() -> impl Handler {
use trillium_rustls::RustlsConnector;
use trillium_tokio::TcpConnector;
type Proxy = trillium_proxy::Proxy<RustlsConnector<TcpConnector>>;
Proxy::new("http://localhost:3000")
}
#[cfg(not(debug_assertions))]
pub fn spa() -> impl Handler {
(
trillium_static_compiled::static_compiled!("../client/build").with_index_file("index.html"),
|conn: trillium::Conn| async move {
conn.with_header(
trillium::KnownHeaderName::ContentType,
"text/html; charset=UTF-8",
)
.ok(include_str!("../../client/build/index.html"))
},
)
}
Noticed that include_str!
allows to add other macros while static_compiled!
doesn't.
pub fn spa() -> impl Handler {
use trillium_compression::compression;
(
compression(),
trillium_static_compiled::static_compiled!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../client/build"
))
.with_index_file("index.html"),
|conn: trillium::Conn| async move {
conn.with_header(
trillium::KnownHeaderName::ContentType,
"text/html; charset=UTF-8",
)
.ok(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../client/build",
"/index.html"
)))
},
)
}
Fails with:
error: no rules expected the token `!`
--> app/src/spa.rs:16:58
|
16 | trillium_static_compiled::static_compiled!(concat!(
| ^ no rules expected this token in macro call
Is it possible for static_compiled!
to have the same behavior as include_str!
?
It is not possible for static_compiled!
to have the same behavior as include_str, but you should be able to do static_compiled!("$CARGO_MANIFEST_DIR/../client/build")
although I believe that's the same as static_compiled!("../client/build")
I was hoping to create trillium-spa
so that I could use the same the same path something similar to this.
spa!("https://localhost:3000", "../client/build", "index.html")
Would it be better to support with_fallback_file("index.html")
or fallback_to_index_file(true)
?
trillium_static_compiled::static_compiled!("../client/build")
.with_index_file("index.html")
.with_fallback_file("index.html")
I don't think I really understand your question about the spa macro, but I don't plan to add with_fallback_file to trillium-static-compiled for now, for the reasons above — it's quite easy for the end application to define a fall through handler with whatever arbitrary logic is needed for the application. You could always fork trillium-static-compiled and add whatever behavior it needs, though, or use it as the basis for trillium-spa
instead of depending on trillium-static-compiled
from trillium-spa