When we think of Flarum's frontend, the first thing that comes to mind is the dynamic, JS-powered SPA. However, before this frontend is rendered by JS, the first thing your browser receives is a simple, server-generated HTML page. This generally includes:
- A simple no-js view, so that the forum is remotely usable even if something breaks with the JS SPA.
- SEO metadata, since search engines gather the majority of their data from the initial returned HTML.
- A bit of code that starts up the JS SPA.
- An initial payload of data, so that users don't need to wait for a spinner right after opening a page.
Flarum responds to requests based on routing config, so the first place we look is the forum routes.php, where core's forum routes are defined. We see that for all "frontend" routes (ie those you can type into your browser bar and visit), we use $routes->toForum(Content\Something::class), which in turn uses RouteHandlerFactory::toFrontend.
RouteHandlerFactory::toFrontend does several things:
- It resolves a
frontend object
- It applies the
Content\Something::class argument (back from when toForum was called in routes.php) to the frontend object
- It returns the
frontend object wrapped in Flarum\Frontend\Controller, which calls the frontend's render method, and returns the result wrapped in HTML.
The bulk of interesting things happen with the frontend object, so let's focus on that. It's an instance of Flarum\Frontend\Frontend.php, which is essentially a wrapper around Flarum\Frontend/Document.php. You can think of Document as a util for building an HTML response: you can give it various info (see the list at the top of the page), and it'll put everything together into HTML when its render method is called.
How does that information actually get into the document? Well, that's where Content\Something::class comes in. A content callback is essentially a function that takes a document, and adds some stuff onto it. Some contents are applied to every document, when a frontend/document is first instantiated. The other major source of content is route config: for example, in the forum routes config file many routes have content just for that route. This is where things like the page title, the initial payload, and no-js HTML are configured.