1
1
use app:: { get_error_pages, get_locales, get_templates_map, APP_ROOT } ;
2
+ use perseus:: error_pages:: ErrorPageData ;
2
3
use perseus:: router:: { RouteInfo , RouteVerdict } ;
3
- use perseus:: shell:: get_render_cfg;
4
+ use perseus:: shell:: { get_initial_state , get_render_cfg, InitialState } ;
4
5
use perseus:: { app_shell, create_app_route, detect_locale, ClientTranslationsManager , DomNode } ;
5
6
use std:: cell:: RefCell ;
6
7
use std:: rc:: Rc ;
@@ -13,15 +14,24 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
13
14
pub fn run ( ) -> Result < ( ) , JsValue > {
14
15
// Panics should always go to the console
15
16
std:: panic:: set_hook ( Box :: new ( console_error_panic_hook:: hook) ) ;
16
- // Get the root (for the router) we'll be injecting page content into
17
+ // Get the root we'll be injecting the router into
17
18
let root = web_sys:: window ( )
18
19
. unwrap ( )
19
20
. document ( )
20
21
. unwrap ( )
21
- . query_selector ( APP_ROOT )
22
+ . query_selector ( & format ! ( "#{}" , APP_ROOT ) )
22
23
. unwrap ( )
23
24
. unwrap ( ) ;
24
25
26
+ // Get the root we'll be injecting actual content into (created by the server)
27
+ // This is an `Option<Element>` until we know we aren't doing loclae detection (in which case it wouldn't exist)
28
+ let container = web_sys:: window ( )
29
+ . unwrap ( )
30
+ . document ( )
31
+ . unwrap ( )
32
+ . query_selector ( "#__perseus_content" )
33
+ . unwrap ( ) ;
34
+
25
35
// Create a mutable translations manager to control caching
26
36
let translations_manager =
27
37
Rc :: new ( RefCell :: new ( ClientTranslationsManager :: new ( & get_locales ( ) ) ) ) ;
@@ -32,17 +42,20 @@ pub fn run() -> Result<(), JsValue> {
32
42
create_app_route ! {
33
43
name => AppRoute ,
34
44
// The render configuration is injected verbatim into the HTML shell, so it certainly should be present
35
- render_cfg => get_render_cfg( ) . expect( "render configuration invalid or not injected" ) ,
36
- templates => get_templates_map( ) ,
37
- locales => get_locales( )
45
+ render_cfg => & get_render_cfg( ) . expect( "render configuration invalid or not injected" ) ,
46
+ templates => & get_templates_map( ) ,
47
+ locales => & get_locales( )
38
48
}
49
+ // TODO integrate templates fully
50
+ // BUG router sees empty template and moves on, fixed by above
39
51
40
52
sycamore:: render_to (
41
53
|| {
42
54
template ! {
43
55
Router ( RouterProps :: new( HistoryIntegration :: new( ) , move |route: StateHandle <AppRoute <DomNode >>| {
44
56
match & route. get( ) . as_ref( ) . 0 {
45
57
// Perseus' custom routing system is tightly coupled to the template system, and returns exactly what we need for the app shell!
58
+ // If a non-404 error occurred, it will be handled in the app shell
46
59
RouteVerdict :: Found ( RouteInfo {
47
60
path,
48
61
template,
@@ -53,15 +66,29 @@ pub fn run() -> Result<(), JsValue> {
53
66
locale. clone( ) ,
54
67
// We give the app shell a translations manager and let it get the `Rc<Translator>` itself (because it can do async safely)
55
68
Rc :: clone( & translations_manager) ,
56
- Rc :: clone( & error_pages)
69
+ Rc :: clone( & error_pages) ,
70
+ container. unwrap( ) . clone( )
57
71
) ,
58
72
// If the user is using i18n, then they'll want to detect the locale on any paths missing a locale
59
73
// Those all go to the same system that redirects to the appropriate locale
74
+ // Note that `container` doesn't exist for this scenario
75
+ // TODO redirect doesn't work until reload
60
76
RouteVerdict :: LocaleDetection ( path) => detect_locale( path. clone( ) , get_locales( ) ) ,
61
77
// We handle the 404 for the user for convenience
62
78
// To get a translator here, we'd have to go async and dangerously check the URL
63
- RouteVerdict :: NotFound => get_error_pages( ) . get_template_for_page( "" , & 404 , "not found" , None ) ,
64
- }
79
+ // If this is an initial load, there'll already be an error message, so we should only proceed if the declaration is not `error`
80
+ RouteVerdict :: NotFound => {
81
+ if let InitialState :: Error ( ErrorPageData { url, status, err } ) = get_initial_state( ) {
82
+ // Hydrate the error pages
83
+ // Right now, we don't provide translators to any error pages that have come from the server
84
+ error_pages. hydrate_page( & url, & status, & err, None , & container. unwrap( ) ) ;
85
+ } else {
86
+ get_error_pages:: <DomNode >( ) . get_template_for_page( "" , & 404 , "not found" , None ) ;
87
+ }
88
+ } ,
89
+ } ;
90
+ // Everything is based on hydration, and so we always return an empty template
91
+ sycamore:: template:: Template :: empty( )
65
92
} ) )
66
93
}
67
94
} ,
0 commit comments