Skip to content

Commit 2cf8783

Browse files
hdoordtTurbo87
authored andcommitted
Make location of frontend index.html file constant
1 parent 4da576c commit 2cf8783

File tree

5 files changed

+27
-44
lines changed

5 files changed

+27
-44
lines changed

.env.sample

+1-8
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,7 @@ export GH_CLIENT_SECRET=
8787
# export SENTRY_DSN_API=
8888
export SENTRY_ENV_API=local
8989

90-
# If set the server serves the frontend `index.html` for all
91-
# non-API requests using the Jinja template at the given path.
92-
# Setting this parameter requires setting
93-
# INDEX_HTML_TEMPLATE_PATH as well.
94-
export INDEX_HTML_TEMPLATE_PATH=dist/index.html
95-
9690
# Base URL for the service from which the OpenGraph images
97-
# for crates are loaded. Required if
98-
# INDEX_HTML_TEMPLATE_PATH is set. Make sure the URL ends
91+
# for crates are loaded. Make sure the URL ends
9992
# with a `/`.
10093
export OG_IMAGE_BASE_URL="http://localhost:3000/og/"

src/config/server.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use http::HeaderValue;
1717
use std::collections::{HashMap, HashSet};
1818
use std::convert::Infallible;
1919
use std::net::IpAddr;
20-
use std::path::PathBuf;
2120
use std::str::FromStr;
2221
use std::time::Duration;
2322

@@ -73,15 +72,15 @@ pub struct Server {
7372
/// Should the server serve the frontend assets in the `dist` directory?
7473
pub serve_dist: bool,
7574

76-
/// If set the server serves the frontend `index.html` for all
77-
/// non-API requests using the Jinja template at the given path.
75+
/// Should the server serve the frontend `index.html` for all
76+
/// non-API requests?
7877
/// Setting this parameter requires setting
7978
/// [`Self::og_image_base_url`] as well.
80-
pub index_html_template_path: Option<PathBuf>,
79+
pub serve_html: bool,
8180

8281
/// Base URL for the service from which the OpenGraph images
8382
/// for crates are loaded. Required if
84-
/// [`Self::index_html_template_path`] is set.
83+
/// [`Self::serve_html`] is set.
8584
pub og_image_base_url: Option<Url>,
8685

8786
/// Maximum number of items that the HTML render
@@ -185,14 +184,13 @@ impl Server {
185184
cdn_domain = storage.cdn_prefix.as_ref().map(|cdn_prefix| format!("https://{cdn_prefix}")).unwrap_or_default()
186185
);
187186

188-
let index_html_template_path = var_parsed("INDEX_HTML_TEMPLATE_PATH")?;
189-
let og_image_base_url = match index_html_template_path {
190-
Some(_) => Some(
187+
let serve_html = var_parsed("SERVE_HTML")?.unwrap_or(true);
188+
let og_image_base_url = serve_html
189+
.then(|| {
191190
required_var_parsed("OG_IMAGE_BASE_URL")
192-
.context("OG_IMAGE_BASE_URL must be set when using INDEX_HTML_TEMPLATE_PATH")?,
193-
),
194-
None => None,
195-
};
191+
.context("OG_IMAGE_BASE_URL must be set when using INDEX_HTML_TEMPLATE_PATH")
192+
})
193+
.transpose()?;
196194

197195
Ok(Server {
198196
db: DatabasePools::full_from_environment(&base)?,
@@ -237,7 +235,7 @@ impl Server {
237235
cargo_compat_status_code_config: var_parsed("CARGO_COMPAT_STATUS_CODES")?
238236
.unwrap_or(StatusCodeConfig::AdjustAll),
239237
serve_dist: true,
240-
index_html_template_path,
238+
serve_html: true,
241239
og_image_base_url,
242240
html_render_cache_max_capacity: var_parsed("HTML_RENDER_CACHE_CAP")?.unwrap_or(1024),
243241
content_security_policy: Some(content_security_policy.parse()?),

src/middleware.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,9 @@ pub fn apply_axum_middleware(state: AppState, router: Router<()>) -> Router {
7777
.layer(conditional_layer(config.serve_dist, || {
7878
from_fn(static_or_continue::serve_dist)
7979
}))
80-
.layer(conditional_layer(
81-
config.index_html_template_path.is_some(),
82-
|| from_fn_with_state(state.clone(), ember_html::serve_html),
83-
))
80+
.layer(conditional_layer(config.serve_html, || {
81+
from_fn_with_state(state.clone(), ember_html::serve_html)
82+
}))
8483
.layer(AddExtensionLayer::new(state.clone()));
8584

8685
router

src/middleware/ember_html.rs

+11-18
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1010
use std::borrow::Cow;
1111
use std::ops::Not;
12-
use std::sync::{Arc, OnceLock};
12+
use std::sync::{Arc, LazyLock, OnceLock};
1313

1414
use axum::extract::Request;
1515
use axum::middleware::Next;
@@ -32,14 +32,12 @@ const PATH_PREFIX_CRATES: &str = "/crates/";
3232
type TemplateEnvFut = Shared<BoxFuture<'static, Arc<minijinja::Environment<'static>>>>;
3333
type TemplateCache = moka::future::Cache<Cow<'static, str>, String>;
3434

35-
/// Initialize [`minijinja::Environment`] given the path to the index.html file. This should
36-
/// only be done once as it will load said file from persistent storage.
37-
async fn init_template_env(
38-
index_html_template_path: impl AsRef<Path>,
39-
) -> Arc<minijinja::Environment<'static>> {
40-
let template_j2 = tokio::fs::read_to_string(index_html_template_path.as_ref())
35+
/// Initialize [`minijinja::Environment`] given the index.html file at `dist/index.html`.
36+
/// This should only be done once as it will load said file from persistent storage.
37+
async fn init_template_env() -> Arc<minijinja::Environment<'static>> {
38+
let template_j2 = tokio::fs::read_to_string("dist/index.html")
4139
.await
42-
.expect("Error loading index.html template. Is the frontend package built yet?");
40+
.expect("Error loading dist/index.html template. Is the frontend package built yet?");
4341

4442
let mut env = Environment::empty();
4543
env.add_template_owned(INDEX_TEMPLATE_NAME, template_j2)
@@ -55,7 +53,8 @@ fn init_html_cache(max_capacity: u64) -> TemplateCache {
5553
}
5654

5755
pub async fn serve_html(state: AppState, request: Request, next: Next) -> Response {
58-
static TEMPLATE_ENV: OnceLock<TemplateEnvFut> = OnceLock::new();
56+
static TEMPLATE_ENV: LazyLock<TemplateEnvFut> =
57+
LazyLock::new(|| init_template_env().boxed().shared());
5958
static RENDERED_HTML_CACHE: OnceLock<TemplateCache> = OnceLock::new();
6059

6160
let path = &request.uri().path();
@@ -75,7 +74,7 @@ pub async fn serve_html(state: AppState, request: Request, next: Next) -> Respon
7574
}
7675

7776
// `state.config.og_image_base_url` will always be `Some` as that's required
78-
// if `state.config.index_html_template_path` is `Some`, and otherwise this
77+
// if `state.config.serve_html` is `true`, and otherwise this
7978
// middleware won't be executed; see `crate::middleware::apply_axum_middleware`.
8079
let og_image_base_url = state.config.og_image_base_url.as_ref().unwrap();
8180
let og_image_url = generate_og_image_url(path, og_image_base_url);
@@ -84,16 +83,10 @@ pub async fn serve_html(state: AppState, request: Request, next: Next) -> Respon
8483
let html = RENDERED_HTML_CACHE
8584
.get_or_init(|| init_html_cache(state.config.html_render_cache_max_capacity))
8685
.get_with_by_ref(&og_image_url, async {
87-
// `OnceLock::get_or_init` blocks as long as its intializer is running in another thread.
86+
// `LazyLock::deref` blocks as long as its intializer is running in another thread.
8887
// Note that this won't take long, as the constructed Futures are not awaited
8988
// during initialization.
90-
let template_env = TEMPLATE_ENV.get_or_init(|| {
91-
// At this point we can safely assume `state.config.index_html_template_path` is `Some`,
92-
// as this middleware won't be executed otherwise; see `crate::middleware::apply_axum_middleware`.
93-
init_template_env(state.config.index_html_template_path.clone().unwrap())
94-
.boxed()
95-
.shared()
96-
});
89+
let template_env = &*TEMPLATE_ENV;
9790

9891
// Render the HTML given the OG image URL
9992
let env = template_env.clone().await;

src/tests/util/test_app.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ fn simple_config() -> config::Server {
481481

482482
// The frontend code is not needed for the backend tests.
483483
serve_dist: false,
484-
index_html_template_path: None,
484+
serve_html: false,
485485
og_image_base_url: None,
486486
html_render_cache_max_capacity: 1024,
487487
content_security_policy: None,

0 commit comments

Comments
 (0)