bridgetownrb / bridgetown

A next-generation progressive site generator & fullstack framework, powered by Ruby
https://www.bridgetownrb.com
MIT License
1.11k stars 114 forks source link

Experimental: Fast refresh feature in development #872

Closed jaredcwhite closed 2 months ago

jaredcwhite commented 3 months ago

This is an early WIP look (higher-quality refactored & tested code forthcoming!) at the fast refresh feature for faster reloading in development. I'll write up more detailed notes and some ideas for future TODOs, but in a nutshell:

But that's not where the real magic happens. What we ideally want is if you change Resource A, resources B, C, D, E, and F are also rebuilt along with Resource A because there's some sort of dependency there.

Doing that is pretty challenging if you have to trace all those dependencies by hand (either under the hood automatically or with specific directives users must maintain). Thankfully…Signals to the rescue!

By placing resource data into Signals and transformation steps inside of Effects, we can observe which resources/generated pages Effects might get executed again when the data in certain Signals change—thereby assembling a dependency graph in real-time of which pages should be rebuilt. That way instead of only acting on a simple piece of source data and leaving that data stale on other parts of the site, or performing a full rebuild which can take a while (as was the case to date), we can instead only rebuild 5 pages or 10 pages or even 50 pages…but not 200! (Plus we also get to skip a lot of other slow code reloading paths and so forth.)

For the most part, this will require no changes to existing site repos. It'll "just work". But we do have a new mechanism in particular for handling site data which can prove quite interesting. Instead of reaching for site.data, reach for site.signals. All of the keys will be shortcuts for setting/getting signal values—aka site.signals.authors == site.signals.authors_signal.value and site.signals.authors.value = ... == site.signals.authors_signal.value = ... This means you can save and access site data through various plugins/templates and changes made to data files will propagate accordingly. This is enabled by some enhancements to Signalize::Struct which you can read more about here.

All of this serves to enable fast refresh paths in many cases shaving off several seconds on complex sites. And even on simple sites, sometimes I can make a change to a file and it's rebuilt so quickly that by the time I switch from my editor back over to the site it's already been refreshed. Booyeah!

More details coming…

render[bot] commented 3 months ago

Your Render PR Server URL is https://bridgetown-api-pr-872.onrender.com.

Follow its progress at https://dashboard.render.com/static/srv-cnvsskuv3ddc739tev0g.

render[bot] commented 3 months ago

Your Render PR Server URL is https://bridgetown-beta-pr-872.onrender.com.

Follow its progress at https://dashboard.render.com/static/srv-cnvssl6v3ddc739tev50.

jaredcwhite commented 3 months ago

Layouts, partials, and Ruby components are all fast-refreshing now. The list of cases where Fast Refresh can't happen is shrinking rapidly! 😲

KonnorRogers commented 3 months ago

Layouts, partials, and Ruby components are all fast-refreshing now. The list of cases where Fast Refresh can't happen is shrinking rapidly! 😲

🎉 so excited! So cool!

jaredcwhite commented 3 months ago

I spend some time today on gnarly code to see how I might handle taxonomy changes in fast refresh (aka your resource was in Category A but you change it to Category B), but after a lot of tearing my hair out I decided this is an abortable offense. So moving pages across categories/tags/etc. will trigger a full refresh…not the end of the world because I assume this happens very rarely (you might add taxonomy to a page right when you first author it, but likely not much if ever after that).

Perhaps down the road when I refactor Prototype/Paginated pages, there can be a new fast-refreshable path.

jaredcwhite commented 2 months ago

I'm going to go ahead and merge this into main because it's already getting to be a bit of a monster. I'll file a series of follow-up issues for possible improvements, as well as adding documentation.