Breaking down a page load
What happens between hitting the URL and the page being interactive.
You hit Enter, and a second later (hopefully), your app is on screen.
A lot happens in that time. None of it is visible to your users, but understanding it is important to reasoning about why a page might be slow.
- Browser asks for the page
- CDN returns the HTML shell
- Browser fetches engine + source
- Both scripts arrive
- Engine builds the JSON tree
- Flags nodes that need data
- Queues pending fetches
- Sends fetches to the app server
- Data returns; nodes render
- Page is interactive
The shell
When the browser asks for /yourpage, the request goes to the CDN. The CDN returns a small HTML shell - barely any markup, mostly the links the browser needs to keep going.
Specifically, the shell contains references to (among other things) two scripts: the Bubble engine (run.js) and your app's source (dynamic.js). Both are also on the CDN. The browser parses the shell, sees the script tags, and starts fetching them.
The scripts
run.jsis the Bubble engine. It's the same file for every Bubble app - the runtime that knows how to interpret a JSON tree, render elements, run client-side workflows, fetch data, and talk to the app server.
dynamic.jsis your app. It's the JSON tree from the last lesson, wrapped in a script. It's specific to your app, but generated once and cached on the CDN; redeploying produces a new version.
Processing the app
Once both scripts have arrived, the engine takes over. It walks the app JSON for the page you requested and figures out what data it needs.
Most of your app is conditional on data - repeating groups bound to searches, text expressions referencing the current user, conditions that hide or show elements. The engine iterates the tree, calculates these dependencies, and queues fetches for everything it can't evaluate yet. Those fetches go to the app server, which runs them against the database and returns the relevant data.
Rendering is somewhat progressive. The engine paints elements as soon as it can - anything that doesn't depend on outstanding data appears immediately. As each fetch returns, the engine evaluates the conditions that were waiting on it and renders the relevant parts of the page. If one of those groups has a ‘Search when element is visible’, then now it's visible, that new search might get added to the fetch queue.
After load
The page is interactive, but the engine's work isn't done. As the user interacts, clicks, or types, the same dependency loop runs again - new data needed, fetched from the app server, re-evaluated, re-rendered.
This is also where workflows fire. When, for example, a Button is clicked that triggers a workflow, it collects all of its ‘dependencies’ (perhaps the input used in the workflow, and a custom state value) and sends them to the app server, where the workflow runs and returns results back to the browser. The next lesson unpacks that distinction.