Page Exports
Every module export GioJS reads from the files of an app - pages, layouts, route handlers, special files and config - and what each one does.
GioJS configures a route with what its files export, not with a config object. The tables below list every export the framework reads, by file. An export that is not listed is ignored: it is an ordinary export of your module and nothing more.
export const revalidate = 3600; // cache the render for an hour
export const tags = ['posts']; // purge it with revalidateTag('posts')
export async function getServerSideProps(ctx) { /* load the post */ }
export async function generateMetadata(ctx, { props }) { /* its <title> */ }
export async function action(req) { /* handle the comment form's POST */ }
export default function PostPage({ post }) { /* render it */ }Pages
app/**/page.tsx (or .jsx, .js):
| Export | Type | What it does |
|---|---|---|
default | React component | The page. Receives what getServerSideProps returned, or { params, searchParams } without it, plus actionData after an action. See page.tsx. |
getServerSideProps | async function | Loads data on the server for each render; may redirect, answer 404 or set headers. |
action | async function | Handles a POST to the page's URL: redirect, re-render with actionData, or a Response. |
metadata | Metadata | Static head metadata: title, description, Open Graph, canonical URL, ... |
generateMetadata | function | Head metadata per request, from params, query or the page's props. |
revalidate | number | false | Caches the render in the Rust server for that many seconds (false: until a purge or deploy). Not set: rendered per request. |
tags | string[] | Cache tags for revalidateTag(). |
shell | 'cache' | Partial prerendering: caches the part before the Suspense boundaries, streams the holes per visitor. |
getStaticPaths | function | The params of a dynamic page to write under gio export. The server ignores it. |
GET | function | Legacy: a page with no default export can answer with Server-Sent Events. |
dynamic | string | Typed, but has no effect. |
Layouts
app/**/layout.tsx (or .jsx, .js):
| Export | Type | What it does |
|---|---|---|
default | React component | Wraps every page below its folder; receives { children, path }. The root layout renders <html> and is never hydrated. See layout.tsx. |
metadata | Metadata | Head metadata, merged under the pages below (title templates, a site-wide openGraph, metadataBase). |
generateMetadata | function | Head metadata per request; props is undefined in a layout. |
revalidate, tags, shell and getServerSideProps are read from pages only: in a layout they have no effect.
Route handlers
app/**/route.ts (or .js):
| Export | Type | What it does |
|---|---|---|
GET, POST, PUT, PATCH, DELETE | RouteHandler | Answer that HTTP method with a Response, JSON, null (204) or a GioEventStream. HEAD runs GET. |
wsHandler | WsHandler | Accepts WebSocket connections at the same path. |
Route handler responses are never cached, so revalidate has no effect in a route.ts. See route.ts.
Special files
| File | Exports | What they do |
|---|---|---|
error.tsx | default, metadata, generateMetadata | The error page of its folder: a client error boundary that receives { error, reset }. |
not-found.tsx | default, metadata, generateMetadata | The 404 page of its folder; the component gets no props. |
loading.tsx | default | The Suspense fallback around its folder. |
app/sitemap.ts, app/robots.ts, app/manifest.ts | default, revalidate | The data of /sitemap.xml, /robots.txt and /manifest.webmanifest: a value, or a function returning (a promise of) one. Cached for revalidate seconds, 3600 by default. |
Project files
| File | Export | What it does |
|---|---|---|
middleware.ts | default | defineMiddleware({ redirects, rewrites, headers, guards }): request rules the Rust server applies before rendering. |
gio.config.ts | default | defineConfig({ plugins }): Node plugins. Unknown keys stop startup. |
Where exports run
Everything on this page runs on the server. The browser bundle of a route imports only the default exports of its page, its nested layouts and its error.tsx and loading.tsx files, so the other exports - and the modules only they import, such as a database client - are left out of it. The root layout is never sent to the browser at all. A helper built by a module-scope call (export const getServerSideProps = withAuth(...)) can keep its imports in the bundle: mark such modules server-only so a leak fails the build.
The legacy page GET export
Before route handlers existed, a page could stream Server-Sent Events. That still works, for compatibility: a page.tsx with no default export whose GET(req) returns a GioEventStream answers with the event stream.
import { GioEventStream } from '@gio.js/core';
// No default export: GET answers the request.
export function GET() {
return new GioEventStream((stream) => {
stream.send({ hello: 'world' });
stream.close();
return () => {}; // nothing to clean up
});
}- A page that has a default export never calls its
GET: the component renders. - Write new streams as a
GETin aroute.tsinstead: it can also return anyResponse, a streamed body included, and it sits next to the other methods of the endpoint.
dynamic has no effect
The page module type declares dynamic?: 'force-dynamic' | 'force-static' | 'auto', but GioJS never reads it. Whether a page is cached is decided by revalidate alone: leave it out to render per request, export a number or false to cache. gio migrate rewrites a Next.js dynamic = 'force-static' page to revalidate = false. The same goes for the other Next.js segment options (runtime, fetchCache, dynamicParams, preferredRegion, maxDuration): GioJS ignores them.
Related
- Layouts and Pages
- Fetching Data, Forms and Mutations, Caching & Revalidating
- File Conventions
- TypeScript - the types for every export