Layouts
The Hyperspan framework
does not have a built-in layout system where layouts get automatically
applied to routes. However, the recommended way to use layouts is to place them in the
app/layouts
directory and use the createLayout
function from
@hyperspan/framework
to define them.
For example, you can create a app/layouts/main-layout.ts
file like this:
import { html } from '@hyperspan/html';
import { createLayout } from '@hyperspan/framework';
type LayoutProps = { children: any, title: string };
export default createLayout(({ children, title }: LayoutProps) => {
return html`
<html>
<head>
<title>${title}</title>
</head>
<body>${children}</body>
</html>
`;
});
Then, you can use the layout in your app/routes/index.ts
file like this:
import { createRoute } from '@hyperspan/framework';
import { html } from '@hyperspan/html';
import MainLayout from '@/app/layouts/main-layout';
export default createRoute(() => {
const content = html`
<h1>Hello, world!</h1>
<p>Some page content here</p>
`;
return MainLayout({
title: 'Home',
content,
});
}
In this example, layouts are just normal functions that return HTML. You can use them in any route you like, and you can pass any data you want to the layout. All of it is rendered on the server, so you don't have to worry about data serialization either.
Why No Built-In Layout System?
Simply put, Hyperspan aims to be as simple as possible, and intentionally avoids adding any additional complexity or conceptual overhead to the framework. Calling a layout function and passing whatever data you want to is as simple as it gets, and does not introduce any new conceptual overhead.
Since routes often require the same data in both the layout and the page itself — meta
tags, titles, and page headings — any built-in layout system needs to be able to
handle data passing well. If your layouts and routes are in separate files, this can be
tricky, and necessitates the creation of novel solutions to a problem the framework itself
creates. In a React framework like Next.js, having to use React
cache()
to avoid duplicate data fetching in both your route and layout is a good example of this.
Note: There may be some kind of built-in layout system in the future — it is not completely off the table — but if it happens, it will be very simple and straightforward.