JavaScript Pages can return any web Response, but they can also reuse the same layout as Markdown
Pages. The recommended pattern is to use the pageData object Rocket passes in the JavaScript Page
context.
Do not construct PageData manually. The Page Runtime already creates it with the current title,
URL, Page registry, menu tree, and any component hydration script.
import { html } from 'lit';
import { ssrRender } from '@rocket/js/ssr.js';
import { atlasDocLayout, atlasDocComponents as components } from '@rocket/js/layouts/atlasDoc.js';
import { siteData } from '../siteData.js';
export { components };
/** @type {import('@rocket/js/types.js').JsPage} */
export default async (request, { pageData }) => {
const url = new URL(request.url);
pageData.content = html`
<h1>Status</h1>
<p>This response was rendered for <code>${url.pathname}</code>.</p>
`;
return new Response(await ssrRender(atlasDocLayout(pageData, siteData)), {
headers: {
'Content-Type': 'text/html; charset=utf-8',
},
});
};
export const config = {
path: '/status',
metadata: { title: 'Status' },
};
This keeps the Page inside the same header, navigation, table of contents, and footer as the rest of
the site. Because /status is a concrete path and the content can be produced once, this Page uses
the default static render mode and builds to dist/status/index.html.
The Server Time Page is a live JavaScript Page using the same pattern:
export default async (request, { pageData }) => {
const now = new Date();
pageData.content = html`
<h1>Server Time Page</h1>
<p>${now.toISOString()}</p>
`;
return new Response(await ssrRender(atlasDocLayout(pageData, globalData)), {
headers: {
'Content-Type': 'text/html; charset=utf-8',
'Cache-Control': 'no-store',
},
});
};
export const config = {
path: '/examples/time',
render: 'server',
};
Route parameters from config.path are available as context.params:
import { html } from 'lit';
import { ssrRender } from '@rocket/js/ssr.js';
import { atlasDocLayout, atlasDocComponents as components } from '@rocket/js/layouts/atlasDoc.js';
import { siteData } from '../siteData.js';
export { components };
const componentsBySlug = new Map([
['button', { name: 'Button', status: 'stable' }],
['callout', { name: 'Callout', status: 'preview' }],
]);
/** @type {import('@rocket/js/types.js').JsPage} */
export default async (_request, { params, pageData }) => {
const component = componentsBySlug.get(params.componentName || '');
if (!component) {
return new Response('Component not found', { status: 404 });
}
pageData.content = html`
<h1>${component.name}</h1>
<p>Status: ${component.status}</p>
`;
return new Response(await ssrRender(atlasDocLayout(pageData, siteData)), {
headers: {
'Content-Type': 'text/html; charset=utf-8',
},
});
};
export const config = {
path: '/playground/:componentName',
metadata: { title: 'Component playground' },
render: 'server',
menu: false,
};
Use menu: false for parameterized Pages unless the configured path is also a useful link target.
Use the layout pattern only when the response is an HTML document. For JSON, return JSON directly:
export default async () => {
return Response.json({
status: 'ok',
renderedAt: new Date().toISOString(),
});
};
export const config = {
path: '/api/status',
render: 'server',
menu: false,
};
This route uses render: 'server' because it returns request-time status data.
JavaScript Pages use the same components export as Markdown Pages when they render Registered
Components:
import { atlasDocComponents } from '@rocket/js/layouts/atlasDoc.js';
const acmeChartFile = new URL('../components/AcmeChart.js', import.meta.url).href;
export const components = {
...atlasDocComponents,
'acme-chart': {
file: acmeChartFile,
className: 'AcmeChart',
loading: 'hydrate:onVisible',
},
};
Rocket injects the hydration script into pageData.clientCode; layouts built with Rocket's
document helper include it automatically.
const pageData = {
title: 'Status',
content,
pageTree: { children: [] },
};
Use the object from the context instead:
export default async (_request, { pageData }) => {
pageData.content = html`<h1>Status</h1>`;
return new Response(await ssrRender(atlasDocLayout(pageData, siteData)));
};
Concrete JavaScript Pages can stay static. Use render: 'server' when the Page depends on the
current request or uses route parameters:
export const config = {
path: '/status/:region',
render: 'server',
};
return new Response(await ssrRender(pageData.content));
Render the full layout instead:
return new Response(await ssrRender(atlasDocLayout(pageData, siteData)));
pageData and the document helper.