framesurge / perseus

A state-driven web development framework for Rust with full support for server-side rendering and static generation.
https://framesurge.sh/perseus/en-US
MIT License
2.15k stars 89 forks source link

Switch to JS for defining internal constants #293

Closed arctic-hen7 closed 1 year ago

arctic-hen7 commented 1 year ago

This PR removes the definitions of the render configuration and translations from the HTML bundle in initial loads, instead moving them to /.perseus/initial_consts/<locale>.js, with an unlocalized version at /.perseus/initial_consts.js. These are new routes that will need to be supported by all server integrations, but otherwise this is not a breaking change, and it purely alters implementation details.

The reason for this change is to change the page load scaling properties of Perseus: right now, very large apps with many pages have longer initial page loads, even for very simple pages, because Perseus injects a JSON sitemap (called the render configuration) into the HTML bundle so it knows how the routing of the app works. So, as the site gets bigger, so does every initial load bundle. To be clear, this effect is usually minimal, and incremental generation has no impact on it (that uses wildcards in the render config), and it does not affect subsequent loads. With this change, the user can load the HTML bundle and then load the JS defining those constants, waiting to instantiate Perseus itself until they are defined. This will marginally increase the page load times of very small sites (incredibly marginally) while significantly decreasing the load times of larger sites and removing any scaling issues: the page load time will be dependent on the page only, not the size of the site.

Note that the process of waiting for constants to be defined is necessary to prevent a fatal error in Perseus itself, but this is done in inlined JS without blocking the main thread, meaning failures will leave the app uninteractive, but still responsive.

arctic-hen7 commented 1 year ago

The only thing left to do here, assuming the tests pass, is to add support to this for Rocket. I'm not familiar with that part of the codebase, so that may take a little longer.