Skip to content

Commit

Permalink
refactor: 🚚 renamed pages to templates for clarity
Browse files Browse the repository at this point in the history
We create templates that in turn render pages, avoids naming confusion
  • Loading branch information
arctic-hen7 committed Jul 29, 2021
1 parent b2e9a68 commit 7c9e433
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 83 deletions.
4 changes: 2 additions & 2 deletions examples/showcase/app/src/bin/build.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use perseus::{
config_manager::{FsConfigManager, ConfigManager},
build_pages
build_templates
};
use perseus_showcase_app::pages;
use sycamore::prelude::SsrNode;

fn main() {
let config_manager = FsConfigManager::new();

build_pages!([
build_templates!([
pages::index::get_page::<SsrNode>(),
pages::about::get_page::<SsrNode>(),
pages::post::get_page::<SsrNode>()
Expand Down
10 changes: 5 additions & 5 deletions examples/showcase/app/src/pages/about.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use sycamore::prelude::*;
use perseus::page::Page;
use sycamore::prelude::{template, component, GenericNode, Template as SycamoreTemplate};
use perseus::template::Template;

#[component(AboutPage<G>)]
pub fn about_page() -> Template<G> {
pub fn about_page() -> SycamoreTemplate<G> {
template! {
p { "About." }
}
}

pub fn get_page<G: GenericNode>() -> Page<(), G> {
Page::new("about")
pub fn get_page<G: GenericNode>() -> Template<(), G> {
Template::new("about")
.template(Box::new(|_| template! {
AboutPage()
}
Expand Down
10 changes: 5 additions & 5 deletions examples/showcase/app/src/pages/index.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
use sycamore::prelude::*;
use serde::{Serialize, Deserialize};
use perseus::page::Page;
use sycamore::prelude::{template, component, GenericNode, Template as SycamoreTemplate};
use perseus::template::Template;

#[derive(Serialize, Deserialize, Debug)]
pub struct IndexPageProps {
pub greeting: String
}

#[component(IndexPage<G>)]
pub fn index_page(props: IndexPageProps) -> Template<G> {
pub fn index_page(props: IndexPageProps) -> SycamoreTemplate<G> {
template! {
p {(props.greeting)}
a(href = "/about") { "About!" }
}
}

pub fn get_page<G: GenericNode>() -> Page<IndexPageProps, G> {
Page::new("index")
pub fn get_page<G: GenericNode>() -> Template<IndexPageProps, G> {
Template::new("index")
.build_state_fn(Box::new(get_static_props))
.template(Box::new(|props: Option<IndexPageProps>| template! {
IndexPage(props.unwrap())
Expand Down
10 changes: 5 additions & 5 deletions examples/showcase/app/src/pages/post.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use sycamore::prelude::*;
use serde::{Serialize, Deserialize};
use perseus::page::Page;
use sycamore::prelude::{template, component, GenericNode, Template as SycamoreTemplate};
use perseus::template::Template;

#[derive(Serialize, Deserialize)]
pub struct PostPageProps {
Expand All @@ -9,7 +9,7 @@ pub struct PostPageProps {
}

#[component(PostPage<G>)]
pub fn post_page(props: PostPageProps) -> Template<G> {
pub fn post_page(props: PostPageProps) -> SycamoreTemplate<G> {
let title = props.title;
let content = props.content;
template! {
Expand All @@ -22,8 +22,8 @@ pub fn post_page(props: PostPageProps) -> Template<G> {
}
}

pub fn get_page<G: GenericNode>() -> Page<PostPageProps, G> {
Page::new("post")
pub fn get_page<G: GenericNode>() -> Template<PostPageProps, G> {
Template::new("post")
.build_paths_fn(Box::new(get_static_paths))
.build_state_fn(Box::new(get_static_props))
.incremental_path_rendering(true)
Expand Down
52 changes: 26 additions & 26 deletions src/build.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
// This binary builds all the pages with SSG
// This binary builds all the templates with SSG

use serde::{Serialize, de::DeserializeOwned};
use crate::{
page::Page,
template::Template,
config_manager::ConfigManager,
render_cfg::RenderOpt
};
use crate::errors::*;
use std::any::Any;
use sycamore::prelude::SsrNode;

/// Builds a page, writing static data as appropriate. This should be used as part of a larger build process.
pub fn build_page<Props: Serialize + DeserializeOwned + Any>(page: Page<Props, SsrNode>, config_manager: &impl ConfigManager) -> Result<Vec<RenderOpt>> {
/// Builds a template, writing static data as appropriate. This should be used as part of a larger build process.
pub fn build_template<Props: Serialize + DeserializeOwned + Any>(template: Template<Props, SsrNode>, config_manager: &impl ConfigManager) -> Result<Vec<RenderOpt>> {
let mut render_opts: Vec<RenderOpt> = Vec::new();
let page_path = page.get_path();
let template_path = template.get_path();

// Handle the boolean properties
if page.revalidates() {
if template.revalidates() {
render_opts.push(RenderOpt::Revalidated);
}
if page.uses_incremental() {
if template.uses_incremental() {
render_opts.push(RenderOpt::Incremental);
}

// Handle static path generation
// Because we iterate over the paths, we need a base path if we're not generating custom ones (that'll be overriden if needed)
let paths = match page.uses_build_paths() {
let paths = match template.uses_build_paths() {
true => {
render_opts.push(RenderOpt::StaticPaths);
page.get_build_paths()?
template.get_build_paths()?
},
false => vec![page_path.clone()]
false => vec![template_path.clone()]
};

// Iterate through the paths to generate initial states if needed
for path in paths.iter() {
// If needed, we'll contruct a full path that's URL encoded so we can easily save it as a file
// BUG: insanely nested paths won't work whatsoever if the filename is too long, maybe hash instead?
let full_path = match render_opts.contains(&RenderOpt::StaticPaths) {
true => urlencoding::encode(&format!("{}/{}", &page_path, path)).to_string(),
true => urlencoding::encode(&format!("{}/{}", &template_path, path)).to_string(),
// We don't want to concatenate the name twice if we don't have to
false => page_path.clone()
false => template_path.clone()
};

// Handle static initial state generation
// We'll only write a static state if one is explicitly generated
if page.uses_build_state() {
if template.uses_build_state() {
render_opts.push(RenderOpt::StaticProps);
// We pass in the latter part of the path, without the base specifier (because that would be the same for everything in the template)
let initial_state = page.get_build_state(path.to_string())?;
let initial_state = template.get_build_state(path.to_string())?;
let initial_state_str = serde_json::to_string(&initial_state).unwrap();
// Write that intial state to a static JSON file
config_manager
.write(&format!("./dist/static/{}.json", full_path), &initial_state_str)
.unwrap();
// Prerender the page using that state
// Prerender the template using that state
let prerendered = sycamore::render_to_string(
||
page.render_for_template(Some(initial_state))
template.render_for_template(Some(initial_state))
);
// Write that prerendered HTML to a static file
config_manager
Expand All @@ -67,17 +67,17 @@ pub fn build_page<Props: Serialize + DeserializeOwned + Any>(page: Page<Props, S

// Handle server-side rendering
// By definition, everything here is done at request-time, so there's not really much to do
// Note also that if a page only uses SSR, it won't get prerendered at build time whatsoever
if page.uses_request_state() {
// Note also that if a template only uses SSR, it won't get prerendered at build time whatsoever
if template.uses_request_state() {
render_opts.push(RenderOpt::Server);
}

// If the page is very basic, prerender without any state
if page.is_basic() {
// If the template is very basic, prerender without any state
if template.is_basic() {
render_opts.push(RenderOpt::StaticProps);
let prerendered = sycamore::render_to_string(
||
page.render_for_template(None)
template.render_for_template(None)
);
// Write that prerendered HTML to a static file
config_manager
Expand All @@ -89,20 +89,20 @@ pub fn build_page<Props: Serialize + DeserializeOwned + Any>(page: Page<Props, S
Ok(render_opts)
}

/// Runs the build process of building many different pages. This is done with a macro because typing for a function means we have to do
/// Runs the build process of building many different templates. This is done with a macro because typing for a function means we have to do
/// things on the heap.
/// (Any better solutions are welcome in PRs!)
#[macro_export]
macro_rules! build_pages {
macro_rules! build_templates {
(
[$($page:expr),+],
[$($template:expr),+],
$config_manager:expr
) => {
let mut render_conf: $crate::render_cfg::RenderCfg = ::std::collections::HashMap::new();
$(
render_conf.insert(
$page.get_path(),
$crate::build::build_page($page, $config_manager)
$template.get_path(),
$crate::build::build_template($template, $config_manager)
.unwrap()
);
)+
Expand Down
6 changes: 3 additions & 3 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ error_chain! {
display("the following error occurred while interfacing with javascript: {:?}", err)
}

PageFeatureNotEnabled(name: String, feature: String) {
description("a page feature required by a function called was not present")
display("the page '{}' is missing the feature '{}'", name, feature)
TemplateFeatureNotEnabled(name: String, feature: String) {
description("a template feature required by a function called was not present")
display("the template '{}' is missing the feature '{}'", name, feature)
}
}
links {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ pub mod shell;
pub mod serve;
pub mod render_cfg;
pub mod config_manager;
pub mod page;
pub mod template;
pub mod build;
1 change: 1 addition & 0 deletions src/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub fn get_render_cfg() -> Result<RenderCfg> {
pub fn get_page(raw_path: &str, render_cfg: &RenderCfg, config_manager: &impl ConfigManager) -> Result<PageData> {
// Remove `/` from the path by encoding it as a URL (that's what we store)
let path = urlencoding::encode(raw_path).to_string();
// TODO Match the path to one of the templates
// TODO support SSR

// Get the static HTML
Expand Down
2 changes: 1 addition & 1 deletion src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use sycamore::prelude::*;
use serde::{Serialize, de::DeserializeOwned};
use crate::errors::*;
use crate::serve::PageData;
use crate::page::TemplateFn;
use crate::template::TemplateFn;

pub async fn fetch(url: String) -> Result<Option<String>> {
let js_err_handler = |err: JsValue| ErrorKind::JsErr(format!("{:?}", err));
Expand Down
Loading

0 comments on commit 7c9e433

Please sign in to comment.