Skip to content

Commit 5473683

Browse files
committed
feat!: passed path, locale, and request to logic-based revalidation
1 parent 869000b commit 5473683

File tree

5 files changed

+75
-11
lines changed

5 files changed

+75
-11
lines changed

examples/core/state_generation/src/templates/revalidation.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ pub async fn get_build_state(_path: String, _locale: String) -> RenderFnResultWi
4040
// revalidated This acts as a secondary check, and can perform arbitrary logic
4141
// to check if we should actually revalidate a page
4242
#[perseus::should_revalidate]
43-
pub async fn should_revalidate() -> RenderFnResultWithCause<bool> {
43+
pub async fn should_revalidate(
44+
_path: String,
45+
_locale: String,
46+
_req: perseus::Request,
47+
) -> RenderFnResultWithCause<bool> {
4448
// For simplicity's sake, this will always say we should revalidate, but you
4549
// could amke this check any condition
4650
Ok(true)

examples/core/state_generation/src/templates/revalidation_and_incremental_generation.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ pub async fn get_build_paths() -> RenderFnResult<Vec<String>> {
5353
// revalidated This acts as a secondary check, and can perform arbitrary logic
5454
// to check if we should actually revalidate a page
5555
#[perseus::should_revalidate]
56-
pub async fn should_revalidate() -> RenderFnResultWithCause<bool> {
56+
pub async fn should_revalidate(
57+
_path: String,
58+
_locale: String,
59+
_req: perseus::Request,
60+
) -> RenderFnResultWithCause<bool> {
5761
// For simplicity's sake, this will always say we should revalidate, but you
5862
// could amke this check any condition
5963
Ok(true)

packages/perseus-macro/src/state_fns.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ pub fn state_fn_impl(input: StateFn, fn_type: StateFnType) -> TokenStream {
251251
// This normal version is identical to the user's (we know it won't have any arguments, and we know its return type)
252252
// We use the user's return type to prevent unused imports warnings in their code
253253
#[cfg(not(target_arch = "wasm32"))]
254-
#vis async fn #name() -> #return_type {
254+
#vis async fn #name(path: ::std::string::String, locale: ::std::string::String, req: ::perseus::Request) -> #return_type {
255255
#block
256256
}
257257
},

packages/perseus/src/server/render.rs

+50-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ use crate::Request;
88
use crate::SsrNode;
99
use chrono::{DateTime, Utc};
1010

11+
/// Clones a `Request` from its internal parts.
12+
fn clone_req(raw: &Request) -> Request {
13+
let mut builder = Request::builder();
14+
15+
for (name, val) in raw.headers() {
16+
builder = builder.header(name, val);
17+
}
18+
19+
builder
20+
.uri(raw.uri())
21+
.method(raw.method())
22+
.version(raw.version())
23+
// We always use an empty body because, in a Perseus request, only the URI matters
24+
// Any custom data should therefore be sent in headers (if you're doing that, consider a
25+
// dedicated API)
26+
.body(())
27+
.unwrap() // This should never fail...
28+
}
29+
1130
/// Gets the path with the locale, returning it without if i18n isn't being
1231
/// used.
1332
fn get_path_with_locale(path_without_locale: &str, translator: &Translator) -> String {
@@ -170,6 +189,9 @@ async fn should_revalidate(
170189
template: &Template<SsrNode>,
171190
path_encoded: &str,
172191
mutable_store: &impl MutableStore,
192+
translator: &Translator,
193+
path: &str,
194+
req: Request,
173195
) -> Result<bool, ServerError> {
174196
let mut should_revalidate = false;
175197
// If it revalidates after a certain period of time, we needd to check that
@@ -197,7 +219,9 @@ async fn should_revalidate(
197219

198220
// Now run the user's custom revalidation logic
199221
if template.revalidates_with_logic() {
200-
should_revalidate = template.should_revalidate().await?;
222+
should_revalidate = template
223+
.should_revalidate(path.to_string(), translator.get_locale(), req)
224+
.await?;
201225
}
202226
Ok(should_revalidate)
203227
}
@@ -299,7 +323,6 @@ pub struct GetPageProps<'a, M: MutableStore, T: TranslationsManager> {
299323
/// load server-side routing). Because this handles templates with potentially
300324
/// revalidation and incremental generation, it uses both mutable and immutable
301325
/// stores.
302-
// TODO possible further optimizations on this for futures?
303326
pub async fn get_page_for_template<M: MutableStore, T: TranslationsManager>(
304327
GetPageProps {
305328
raw_path,
@@ -313,6 +336,10 @@ pub async fn get_page_for_template<M: MutableStore, T: TranslationsManager>(
313336
}: GetPageProps<'_, M, T>,
314337
template: &Template<SsrNode>,
315338
) -> Result<PageData, ServerError> {
339+
// Since `Request` is not actually `Clone`able, we hack our way around needing
340+
// it twice An `Rc` won't work because of future constraints, and an `Arc`
341+
// seems a little unnecessary
342+
let req_2 = clone_req(&req);
316343
// Get a translator for this locale (for sanity we hope the manager is caching)
317344
let translator = translations_manager
318345
.get_translator_for_locale(locale.to_string())
@@ -350,7 +377,16 @@ pub async fn get_page_for_template<M: MutableStore, T: TranslationsManager>(
350377
// It's cached
351378
Some((html_val, head_val)) => {
352379
// Check if we need to revalidate
353-
if should_revalidate(template, &path_encoded, mutable_store).await? {
380+
if should_revalidate(
381+
template,
382+
&path_encoded,
383+
mutable_store,
384+
&translator,
385+
path,
386+
req,
387+
)
388+
.await?
389+
{
354390
let (html_val, head_val, state) = revalidate(
355391
template,
356392
&translator,
@@ -448,7 +484,16 @@ pub async fn get_page_for_template<M: MutableStore, T: TranslationsManager>(
448484

449485
// Handle if we need to revalidate
450486
// It'll be in the mutable store if we do
451-
if should_revalidate(template, &path_encoded, mutable_store).await? {
487+
if should_revalidate(
488+
template,
489+
&path_encoded,
490+
mutable_store,
491+
&translator,
492+
path,
493+
req,
494+
)
495+
.await?
496+
{
452497
let (html_val, head_val, state) = revalidate(
453498
template,
454499
&translator,
@@ -492,7 +537,7 @@ pub async fn get_page_for_template<M: MutableStore, T: TranslationsManager>(
492537
// page will be built soon If we're not, and there's no build state,
493538
// then we still need to build, which we'll do after we've checked for
494539
// amalgamation
495-
let state = get_request_state(template, &translator, path, req).await?;
540+
let state = get_request_state(template, &translator, path, req_2).await?;
496541
states.request_state = state;
497542
}
498543

packages/perseus/src/template/core.rs

+14-3
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,13 @@ make_async_trait!(
6969
req: Request
7070
);
7171
#[cfg(not(target_arch = "wasm32"))]
72-
make_async_trait!(ShouldRevalidateFnType, RenderFnResultWithCause<bool>);
72+
make_async_trait!(
73+
ShouldRevalidateFnType,
74+
RenderFnResultWithCause<bool>,
75+
path: String,
76+
locale: String,
77+
req: Request
78+
);
7379
#[cfg(not(target_arch = "wasm32"))]
7480
make_async_trait!(
7581
AmalgamateStatesFnType,
@@ -423,9 +429,14 @@ impl<G: Html> Template<G> {
423429
/// can be caused by either the server or the client, so the
424430
/// user must specify an [`ErrorCause`].
425431
#[cfg(not(target_arch = "wasm32"))]
426-
pub async fn should_revalidate(&self) -> Result<bool, ServerError> {
432+
pub async fn should_revalidate(
433+
&self,
434+
path: String,
435+
locale: String,
436+
req: Request,
437+
) -> Result<bool, ServerError> {
427438
if let Some(should_revalidate) = &self.should_revalidate {
428-
let res = should_revalidate.call().await;
439+
let res = should_revalidate.call(path, locale, req).await;
429440
match res {
430441
Ok(res) => Ok(res),
431442
Err(GenericErrorWithCause { error, cause }) => Err(ServerError::RenderFnFailed {

0 commit comments

Comments
 (0)