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 does several things:
- It resolves a
- 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
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.