Skip to content

Commit 532243e

Browse files
authored
fix: 🐛 fixed build paths issues (#41)
* fix(routing): 🐛 fixed subsequent loads 404s Closes #40. * fix(routing): 🐛 allowed build paths to generate root pages * docs(book): 📝 updated docs on how to use build paths to generate root pages
1 parent f815626 commit 532243e

File tree

5 files changed

+39
-12
lines changed

5 files changed

+39
-12
lines changed

docs/0.3.x/src/strategies/build-paths.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ Note that, like _build state_, this strategy may be invoked at build-time or whi
88

99
## Usage
1010

11-
Here's the same example as given in the previous section (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/showcase/src/templates/post.rs)), which uses _build paths_ together with _build state_ and _incremental generation_:
11+
Here's the same example as given in the previous section (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/showcase/i18n/templates/post.rs)), which uses _build paths_ together with _build state_:
1212

1313
```rust,no_run,no_playground
14-
{{#include ../../../../examples/showcase/src/templates/post.rs}}
14+
{{#include ../../../../examples/i18n/src/templates/post.rs}}
1515
```
1616

1717
Note the return type of the `get_build_paths` function, which returns a `RenderFnResult<Vec<String>>`, which is just an alias for `Result<T, Box<dyn std::error::Error>>`, which means that you can return any error you want. If you need to explicitly `return Err(..)`, then you should use `.into()` to perform the conversion from your error type to this type automatically. Perseus will then format your errors nicely for you using [`fmterr`](https://github.com/arctic-hen7/fmterr).
18+
19+
Also note how this page renders the page `/docs` by specifying an empty string as one of the paths exported from `get_build_paths`.

docs/next/src/strategies/build-paths.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ Note that, like _build state_, this strategy may be invoked at build-time or whi
88

99
## Usage
1010

11-
Here's the same example as given in the previous section (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/showcase/src/templates/post.rs)), which uses _build paths_ together with _build state_ and _incremental generation_:
11+
Here's the same example as given in the previous section (taken from [here](https://github.com/arctic-hen7/perseus/blob/main/examples/showcase/i18n/templates/post.rs)), which uses _build paths_ together with _build state_:
1212

1313
```rust,no_run,no_playground
14-
{{#include ../../../../examples/showcase/src/templates/post.rs}}
14+
{{#include ../../../../examples/i18n/src/templates/post.rs}}
1515
```
1616

1717
Note the return type of the `get_build_paths` function, which returns a `RenderFnResult<Vec<String>>`, which is just an alias for `Result<T, Box<dyn std::error::Error>>`, which means that you can return any error you want. If you need to explicitly `return Err(..)`, then you should use `.into()` to perform the conversion from your error type to this type automatically. Perseus will then format your errors nicely for you using [`fmterr`](https://github.com/arctic-hen7/fmterr).
18+
19+
Also note how this page renders the page `/docs` by specifying an empty string as one of the paths exported from `get_build_paths`.

examples/basic/.perseus/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ pub fn run() -> Result<(), JsValue> {
100100
// Right now, we don't provide translators to any error pages that have come from the server
101101
error_pages.hydrate_page(&url, &status, &err, None, &container_rx_elem);
102102
} else {
103-
get_error_pages::<DomNode>().get_template_for_page("", &404, "not found", None);
103+
error_pages.hydrate_page("", &404, "not found", None, &container_rx_elem);
104104
}
105105
},
106106
};

examples/i18n/src/templates/post.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use perseus::{RenderFnResult, RenderFnResultWithCause, Template};
1+
use perseus::{link, RenderFnResult, RenderFnResultWithCause, Template};
22
use serde::{Deserialize, Serialize};
33
use std::rc::Rc;
44
use sycamore::prelude::{component, template, GenericNode, Template as SycamoreTemplate};
@@ -20,6 +20,7 @@ pub fn post_page(props: PostPageProps) -> SycamoreTemplate<G> {
2020
p {
2121
(content)
2222
}
23+
a(href = link!("/post")) { "Root post page" }
2324
}
2425
}
2526

@@ -51,5 +52,9 @@ pub async fn get_static_props(path: String) -> RenderFnResultWithCause<String> {
5152
}
5253

5354
pub async fn get_static_paths() -> RenderFnResult<Vec<String>> {
54-
Ok(vec!["test".to_string(), "blah/test/blah".to_string()])
55+
Ok(vec![
56+
"".to_string(),
57+
"test".to_string(),
58+
"blah/test/blah".to_string(),
59+
])
5560
}

packages/perseus/src/build.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,17 @@ pub async fn build_template(
4444
// Handle static path generation
4545
// Because we iterate over the paths, we need a base path if we're not generating custom ones (that'll be overriden if needed)
4646
let paths = match template.uses_build_paths() {
47-
true => template.get_build_paths().await?,
47+
true => template
48+
.get_build_paths()
49+
.await?
50+
// Trim away any trailing `/`s so we don't insert them into the render config
51+
// That makes rendering an index page from build paths impossible (see #39)
52+
.iter()
53+
.map(|p| match p.strip_suffix('/') {
54+
Some(stripped) => stripped.to_string(),
55+
None => p.to_string(),
56+
})
57+
.collect(),
4858
false => {
4959
single_page = true;
5060
vec![String::new()]
@@ -61,6 +71,11 @@ pub async fn build_template(
6171
// We don't want to concatenate the name twice if we don't have to
6272
false => urlencoding::encode(&template_path).to_string(),
6373
};
74+
// Strip trailing `/`s (but they're encoded) for the reasons described above
75+
let full_path_without_locale = match full_path_without_locale.strip_suffix("%2F") {
76+
Some(stripped) => stripped.to_string(),
77+
None => full_path_without_locale,
78+
};
6479
// Add the current locale to the front of that
6580
let full_path = format!("{}-{}", translator.get_locale(), full_path_without_locale);
6681

@@ -185,10 +200,13 @@ async fn build_template_and_get_cfg(
185200
} else {
186201
// Add each page that the template explicitly generated (ignoring ISR for now)
187202
for page in pages {
188-
render_cfg.insert(
189-
format!("{}/{}", &template_root_path, &page),
190-
template_root_path.clone(),
191-
);
203+
let path = format!("{}/{}", &template_root_path, &page);
204+
// Remove any trailing `/`s for the reasons described above
205+
let path = match path.strip_suffix('/') {
206+
Some(stripped) => stripped.to_string(),
207+
None => path,
208+
};
209+
render_cfg.insert(path, template_root_path.clone());
192210
}
193211
// Now if the page uses ISR, add an explicit `/*` in there after the template root path
194212
// Incremental rendering requires build-time path generation

0 commit comments

Comments
 (0)