-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ✨ added revalidation and refactored a fully modular rendering s…
…ystem
- Loading branch information
1 parent
5baf9bf
commit c9df616
Showing
14 changed files
with
480 additions
and
61 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
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 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 |
---|---|---|
@@ -0,0 +1,48 @@ | ||
use sycamore::prelude::{template, component, GenericNode, Template as SycamoreTemplate}; | ||
use perseus::template::Template; | ||
use serde::{Serialize, Deserialize}; | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct TimePageProps { | ||
pub time: String | ||
} | ||
|
||
#[component(TimePage<G>)] | ||
pub fn time_page(props: TimePageProps) -> SycamoreTemplate<G> { | ||
template! { | ||
p { (format!("The time when this page was last rendered was '{}'.", props.time)) } | ||
} | ||
} | ||
|
||
pub fn get_page<G: GenericNode>() -> Template<G> { | ||
Template::new("timeisr") | ||
.template(template_fn()) | ||
// This page will revalidate every five seconds (to illustrate revalidation) | ||
.revalidate_after("5s".to_string()) | ||
.incremental_path_rendering(true) | ||
.build_state_fn(Box::new(get_build_state)) | ||
.build_paths_fn(Box::new(get_build_paths)) | ||
} | ||
|
||
pub fn get_build_state(_path: String) -> String { | ||
serde_json::to_string( | ||
&TimePageProps { | ||
time: format!("{:?}", std::time::SystemTime::now()) | ||
} | ||
).unwrap() | ||
} | ||
|
||
pub fn get_build_paths() -> Vec<String> { | ||
vec![ | ||
"test".to_string() | ||
] | ||
} | ||
|
||
pub fn template_fn<G: GenericNode>() -> perseus::template::TemplateFn<G> { | ||
Box::new(|props: Option<String>| template! { | ||
TimePage( | ||
serde_json::from_str::<TimePageProps>(&props.unwrap()).unwrap() | ||
) | ||
} | ||
) | ||
} |
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,44 @@ | ||
use sycamore::prelude::{template, component, GenericNode, Template as SycamoreTemplate}; | ||
use perseus::template::Template; | ||
use serde::{Serialize, Deserialize}; | ||
|
||
#[derive(Serialize, Deserialize, Debug)] | ||
pub struct TimePageProps { | ||
pub time: String | ||
} | ||
|
||
#[component(TimePage<G>)] | ||
pub fn time_page(props: TimePageProps) -> SycamoreTemplate<G> { | ||
template! { | ||
p { (format!("The time when this page was last rendered was '{}'.", props.time)) } | ||
} | ||
} | ||
|
||
pub fn get_page<G: GenericNode>() -> Template<G> { | ||
Template::new("time") | ||
.template(template_fn()) | ||
// This page will revalidate every five seconds (to illustrate revalidation) | ||
// Try changing this to a week, even though the below custom logic says to always revalidate, we'll only do it weekly | ||
.revalidate_after("5s".to_string()) | ||
.should_revalidate_fn(Box::new(|| { | ||
true | ||
})) | ||
.build_state_fn(Box::new(get_build_state)) | ||
} | ||
|
||
pub fn get_build_state(_path: String) -> String { | ||
serde_json::to_string( | ||
&TimePageProps { | ||
time: format!("{:?}", std::time::SystemTime::now()) | ||
} | ||
).unwrap() | ||
} | ||
|
||
pub fn template_fn<G: GenericNode>() -> perseus::template::TemplateFn<G> { | ||
Box::new(|props: Option<String>| template! { | ||
TimePage( | ||
serde_json::from_str::<TimePageProps>(&props.unwrap()).unwrap() | ||
) | ||
} | ||
) | ||
} |
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 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 |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use crate::errors::*; | ||
use chrono::{Duration, Utc}; | ||
|
||
// Decodes time strings like '1w' into actual datetimes from the present moment. If you've ever used NodeJS's [`jsonwebtoken`](https://www.npmjs.com/package/jsonwebtoken) module, this is | ||
/// very similar (based on Vercel's [`ms`](https://github.com/vercel/ms) module for JavaScript). | ||
/// Accepts strings of the form 'xXyYzZ...', where the lower-case letters are numbers meaning a number of the intervals X/Y/Z (e.g. 1m4d -- one month four days). | ||
/// The available intervals are: | ||
/// | ||
/// - s: second, | ||
/// - m: minute, | ||
/// - h: hour, | ||
/// - d: day, | ||
/// - w: week, | ||
/// - M: month (30 days used here, 12M ≠ 1y!), | ||
/// - y: year (365 days always, leap years ignored, if you want them add them as days) | ||
pub fn decode_time_str(time_str: &str) -> Result<String> { | ||
let mut duration_after_current = Duration::zero(); | ||
// Get the current datetime since Unix epoch, we'll add to that | ||
let current = Utc::now(); | ||
// A working variable to store the '123' part of an interval until we reach the idnicator and can do the full conversion | ||
let mut curr_duration_length = String::new(); | ||
// Iterate through the time string's characters to get each interval | ||
for c in time_str.chars() { | ||
// If we have a number, append it to the working cache | ||
// If we have an indicator character, we'll match it to a duration | ||
if c.is_numeric() { | ||
curr_duration_length.push(c); | ||
} else { | ||
// Parse the working variable into an actual number | ||
let interval_length = curr_duration_length.parse::<i64>().unwrap(); // It's just a string of numbers, we know more than the compiler | ||
let duration = match c { | ||
's' => Duration::seconds(interval_length), | ||
'm' => Duration::minutes(interval_length), | ||
'h' => Duration::hours(interval_length), | ||
'd' => Duration::days(interval_length), | ||
'w' => Duration::weeks(interval_length), | ||
'M' => Duration::days(interval_length * 30), // Multiplying the number of months by 30 days (assumed length of a month) | ||
'y' => Duration::days(interval_length * 365), // Multiplying the number of years by 365 days (assumed length of a year) | ||
c => bail!(ErrorKind::InvalidDatetimeIntervalIndicator(c.to_string())), | ||
}; | ||
duration_after_current = duration_after_current + duration; | ||
// Reset that working variable | ||
curr_duration_length = String::new(); | ||
} | ||
} | ||
// Form the final duration by reducing the durations vector into one | ||
let datetime = current + duration_after_current; | ||
|
||
// We return an easily parsible format (RFC 3339) | ||
Ok(datetime.to_rfc3339()) | ||
} |
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
Oops, something went wrong.