From 18f54a9a27696d46af40762b51d509920dc9403a Mon Sep 17 00:00:00 2001 From: arctic_hen7 Date: Tue, 29 Mar 2022 19:59:21 +1100 Subject: [PATCH] fix: fixed exporting with typed options system --- .../basic/.perseus/builder/src/bin/export.rs | 9 +++- .../builder/src/bin/export_error_page.rs | 11 ++++- .../core/basic/.perseus/server/src/main.rs | 10 ++++- packages/perseus/src/init.rs | 41 +++++++++++-------- 4 files changed, 49 insertions(+), 22 deletions(-) diff --git a/examples/core/basic/.perseus/builder/src/bin/export.rs b/examples/core/basic/.perseus/builder/src/bin/export.rs index 23918adb14..8020744f74 100644 --- a/examples/core/basic/.perseus/builder/src/bin/export.rs +++ b/examples/core/basic/.perseus/builder/src/bin/export.rs @@ -6,7 +6,7 @@ use perseus::{ export::{export_app, ExportProps}, get_path_prefix_server, }, - PluginAction, SsrNode, + PerseusApp, PluginAction, SsrNode, }; use perseus_engine as app; use std::fs; @@ -76,7 +76,8 @@ async fn build_and_export() -> i32 { } }; let templates_map = app.get_templates_map(); - let index_view = app.get_index_view().await; + let index_view_str = app.get_index_view_str(); + let root_id = app.get_root(); // This consumes `self`, so we get it finally let translations_manager = app.get_translations_manager().await; @@ -107,6 +108,10 @@ async fn build_and_export() -> i32 { .export_actions .after_successful_build .run((), plugins.get_plugin_data()); + // The app has now been built, so we can safely instantiate the HTML shell (which needs access to the render config, generated in the above build step) + // It doesn't matter if the type parameters here are wrong, this function doesn't use them + let index_view = + PerseusApp::get_html_shell(index_view_str, &root_id, &immutable_store, &plugins).await; // Turn the build artifacts into self-contained static files let export_res = export_app(ExportProps { templates: &templates_map, diff --git a/examples/core/basic/.perseus/builder/src/bin/export_error_page.rs b/examples/core/basic/.perseus/builder/src/bin/export_error_page.rs index 0484934309..9e36393ce1 100644 --- a/examples/core/basic/.perseus/builder/src/bin/export_error_page.rs +++ b/examples/core/basic/.perseus/builder/src/bin/export_error_page.rs @@ -1,5 +1,5 @@ use fmterr::fmt_err; -use perseus::{internal::serve::build_error_page, PluginAction, SsrNode}; +use perseus::{internal::serve::build_error_page, PerseusApp, PluginAction, SsrNode}; use perseus_engine as app; use std::{env, fs}; @@ -18,7 +18,13 @@ async fn real_main() -> i32 { let error_pages = app.get_error_pages(); // Prepare the HTML shell - let html_shell = app.get_index_view().await; + let index_view_str = app.get_index_view_str(); + let root_id = app.get_root(); + let immutable_store = app.get_immutable_store(); + // We assume the app has already been built before running this (so the render config must be available) + // It doesn't matter if the type parameters here are wrong, this function doesn't use them + let html_shell = + PerseusApp::get_html_shell(index_view_str, &root_id, &immutable_store, &plugins).await; // Get the error code to build from the arguments to this executable let args = env::args().collect::>(); let err_code_to_build_for = match args.get(1) { @@ -50,6 +56,7 @@ async fn real_main() -> i32 { (err_code_to_build_for, output.to_string()), plugins.get_plugin_data(), ); + // Build that error page as the server does let err_page_str = build_error_page( "", diff --git a/examples/core/basic/.perseus/server/src/main.rs b/examples/core/basic/.perseus/server/src/main.rs index 9f20d5b641..72c8f7fd2a 100644 --- a/examples/core/basic/.perseus/server/src/main.rs +++ b/examples/core/basic/.perseus/server/src/main.rs @@ -3,6 +3,7 @@ use perseus::internal::i18n::TranslationsManager; use perseus::internal::serve::{ServerOptions, ServerProps}; use perseus::plugins::PluginAction; use perseus::stores::MutableStore; +use perseus::PerseusApp; use perseus::SsrNode; use perseus_engine as app; use std::env; @@ -106,9 +107,16 @@ fn get_props(is_standalone: bool) -> ServerProps PerseusAppBase { .run((), self.plugins.get_plugin_data()) .unwrap_or_else(|| self.root.to_string()) } - /// Gets the index view. This is asynchronous because it constructs an HTML shell, which invovles fetching the configuration of pages. + /// Gets the index view as a string, without generating an HTML shell (pass this into `::get_html_shell()` to do that). /// /// Note that this automatically adds `` to the start of the HTMl shell produced, which can only be overriden with a control plugin (though you should really never do this /// in Perseus, which targets HTML on the web). #[cfg(feature = "server-side")] - pub async fn get_index_view(&self) -> HtmlShell { - // TODO Allow plugin modification of this + pub fn get_index_view_str(&self) -> String { // We have to add an HTML document type declaration, otherwise the browser could think it's literally anything! (This shouldn't be a problem, but it could be in 100 years...) - let index_view_str = format!("\n{}", self.index_view); + format!("\n{}", self.index_view) + } + /// Gets an HTML shell from an index view string. This is broken out so that it can be executed after the app has been built (which requries getting the translations manager, consuming + /// `self`). As inconvenient as this is, it's necessitated, otherwise exporting would try to access the built app before it had actually been built. + #[cfg(feature = "server-side")] + pub async fn get_html_shell( + index_view_str: String, + root: &str, + immutable_store: &ImmutableStore, + plugins: &Plugins, + ) -> HtmlShell { // Construct an HTML shell let mut html_shell = HtmlShell::new( index_view_str, - &self.get_root(), + root, // TODO Handle this properly (good enough for now because that's what we weere already doing) - &get_render_cfg(&self.get_immutable_store()) + &get_render_cfg(immutable_store) .await .expect("Couldn't get render configuration!"), &get_path_prefix_server(), ); // Apply the myriad plugin actions to the HTML shell (replacing the whole thing first if need be) - let shell_str = self - .plugins + let shell_str = plugins .control_actions .settings_actions .html_shell_actions .set_shell - .run((), self.plugins.get_plugin_data()) + .run((), plugins.get_plugin_data()) .unwrap_or(html_shell.shell); html_shell.shell = shell_str; // For convenience, we alias the HTML shell functional actions - let hsf_actions = &self - .plugins + let hsf_actions = &plugins .functional_actions .settings_actions .html_shell_actions; @@ -364,7 +371,7 @@ impl PerseusAppBase { html_shell.head_before_boundary.push( hsf_actions .add_to_head_before_boundary - .run((), self.plugins.get_plugin_data()) + .run((), plugins.get_plugin_data()) .values() .flatten() .cloned() @@ -373,7 +380,7 @@ impl PerseusAppBase { html_shell.scripts_before_boundary.push( hsf_actions .add_to_scripts_before_boundary - .run((), self.plugins.get_plugin_data()) + .run((), plugins.get_plugin_data()) .values() .flatten() .cloned() @@ -382,7 +389,7 @@ impl PerseusAppBase { html_shell.head_after_boundary.push( hsf_actions .add_to_head_after_boundary - .run((), self.plugins.get_plugin_data()) + .run((), plugins.get_plugin_data()) .values() .flatten() .cloned() @@ -391,7 +398,7 @@ impl PerseusAppBase { html_shell.scripts_after_boundary.push( hsf_actions .add_to_scripts_after_boundary - .run((), self.plugins.get_plugin_data()) + .run((), plugins.get_plugin_data()) .values() .flatten() .cloned() @@ -400,7 +407,7 @@ impl PerseusAppBase { html_shell.before_content.push( hsf_actions .add_to_before_content - .run((), self.plugins.get_plugin_data()) + .run((), plugins.get_plugin_data()) .values() .flatten() .cloned() @@ -409,7 +416,7 @@ impl PerseusAppBase { html_shell.after_content.push( hsf_actions .add_to_after_content - .run((), self.plugins.get_plugin_data()) + .run((), plugins.get_plugin_data()) .values() .flatten() .cloned()