Options and files
The options of framework(), the files src/routes/ may hold, and what each entry point of @k8ordo/framework exports. How to use each is in the guide pages.
On this page
Entry points
@k8ordo/framework splits its entry points by where the code runs. No entry point that a deployed application loads imports Vite.
@k8ordo/framework: the types and functions the application’s code imports.@k8ordo/framework/vite:framework(), the plugin forvite.config.ts. It loads Vite.@k8ordo/framework/server: server mode only. The functions and types that code inside the handler imports. In static mode, a module that imports a value from it fails the build. It needs nothing from Node.js butAsyncLocalStorage, so it runs wherever the handler does.@k8ordo/framework/serve:serve(), which runs a build on Node.js. A server mode build’sdist/server.jscalls it, and a server of your own can too. A static mode build it serves the way a static host does.@k8ordo/framework/vercel:vercel(), the plugin that writes the build for Vercel, in either mode.@k8ordo/framework/generated: what the generated.k8ordo/files import. Code written by hand does not import it.
framework
Import from @k8ordo/framework/vite
The Vite plugin that builds the application. It returns an array holding React’s plugin and the RSC pipeline, so pass it to plugins as it is.
framework(options: FrameworkOptions): PluginOption[]Parameters
options.mode'static' | 'server''static'or'server', with no default.'static'renders pages at build time, into an app that runs with no server.'server'renders pages per request, in an app that runs on a server.options.routesDirstring- The route directory, relative to the project root.
src/routesby default. The generated files go to.k8ordo/either way. options.paths(patterns: readonly string[]) => readonly string[] | Promise<readonly string[]>- Static mode only. A function that returns the pathnames of routes with parameters. It receives the patterns that need values and returns an array of pathnames, or a promise of one. The pathnames carry no Vite
base. For a page with afallback.tsx, it may also return shell locations that leave a value open, such as/ja/posts/:id. options.sitestring- Static mode only. The origin the site is served from, such as
https://example.com. With it, the build also writessitemap.xml. It is also the origin of therequest.urlaroute.tsreceives. options.cspReadonly<Record<string, readonly string[]>>- Static mode only. The Content-Security-Policy every page carries, as an array of sources per directive. The build adds the hashes of the framework’s scripts and writes it into a
<meta>.
Returns
PluginOption[] — An array of Vite plugins.
Caveats
paths,siteorcspwritten besidemode: 'server'is a type error.- When
cspholds a directive a<meta>ignores, or'strict-dynamic',framework()fails as soon as it is called, with the errorthe "csp" option cannot go into a page's <meta> as it is.
vite.config.tsimport { framework } from '@k8ordo/framework/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
framework({
mode: 'static',
paths: () => ['/products/1', '/products/2'],
site: 'https://example.com',
}),
],
});Route files
The files a directory under src/routes/ may hold, with what each exports and receives. Any other file lives outside src/routes/: components in src/components/, every other module in src/lib/.
page.tsx
- Default export: the page component for the directory’s URL. It receives
paramsandpathname. - In server mode, it also receives
request, aRouteRequest. paramsSchema: a schema that validates the parameters. Anything that implements Standard Schema works. Optional.search: server mode only. The schema of the query the page reads, theurlof a@k8ordo/statedefinition. A page that exports it receives the parsed values assearch.
layout.tsx
- Default export: a component that wraps what renders below it, received as
children. It also receivesparamsandpathname.paramsstays typed as strings. - In server mode, it also receives
request, aRouteRequest. paramsSchema: runs for every page below, before the page’s own schema.
not-found.tsx
- Default export: the component rendered for a URL below the directory that no route matched. It receives
paramsandpathname. Theparamsare unvalidated strings. - In server mode, it also receives
request, aRouteRequest. - In static mode, it is written as
404.html, so an application may hold only one. In server mode, it answers with a 404 status, and each directory may hold its own.
error.tsx
- A
'use client'file. - Default export: a component that receives
errorandreset. It renders in place of what is below it when that throws. It receives noparams.
loading.tsx
- Default export: a component with no props. It renders as the
<Suspense>fallback while the page below it loads.
fallback.tsx
- Default export: a component with no props. Under static mode it renders in place of the
page.tsxbeside it, for a URL whose valuepathsdid not list. - It sits beside a
page.tsxthat has a parameter. Its directory may not hold alayout.tsx. - Server mode does not use it:
page.tsxrenders every value per request.
redirect.ts
- Default export: the target as a string, or
{ to, permanent }.tois a pattern of the route table. Its parameters are filled with the matched values. - In static mode, it is written as a page that sends the visitor to the target. In server mode, it answers
GETandHEADwith a307, or a308whenpermanent.
route.ts
- Exports named after methods, such as
GETandPOST: functions that receive{ request, params }and return aResponse. paramsSchema: validates the parameters, as a page’s does.- In static mode, only
GETmay be exported, and its response is written as the file at that URL. In server mode, any of the seven methods may be exported.
guard.ts
- Server mode only. Default export: a function of type
Guard. It runs before anything below the directory responds. Returning aResponseanswers the request there. Returning nothing goes on to the page or theroute.ts.
Application API
import {
bindParams,
href,
isNotFound,
matchPath,
navigateTo,
normalizePathname,
notFound,
useMatch,
usePathname,
usePendingPathname,
withBase,
} from '@k8ordo/framework';
import type {
BoundLinks,
BoundParams,
ErrorProps,
LayoutProps,
MatchablePattern,
MatchOptions,
NavigateToOptions,
PageProps,
RegisteredNavigablePattern,
RegisteredPageParams,
RegisteredParams,
RegisteredPattern,
RouteContext,
} from '@k8ordo/framework';Each is an export of @k8ordo/router, re-exported by name. useParams and useRoute are not among them: they read a <Router> the framework never renders. A page receives params as a prop instead. Each one is described on the API page of @k8ordo/router.
cookies
Import from @k8ordo/framework/server
Server mode only. Reads and writes the request’s cookies. Call it from a guard.ts, a route.ts or a Server Action.
cookies(): CookiesFields
get(name: string) => string | undefined- Reads a value by name.
undefinedwhen there is none. has(name: string) => boolean- Whether a cookie of that name exists.
set(name: string, value: string, options?: CookieOptions) => void- Writes a value. The third argument takes the attributes of
CookieOptions. delete(name: string, scope?: CookieScope) => void- Deletes a cookie. Pass the
pathanddomainit was written with.
Caveats
- A read reflects what was written earlier in the same request. A name not written yet returns the value the request carried.
- Every write goes to the browser as a
Set-Cookieon the response, whatever the response is. - Called while a page renders, it fails with
cookies() belongs to what answers the request. A page readsrequest.cookiesinstead.
cookies().get('session');
cookies().set('session', token, { maxAge: 60 * 60 * 24 });
cookies().delete('session');CookieOptions
Import from @k8ordo/framework/server
The cookie attributes passed to cookies().set() as its third argument. The defaults suit a session cookie.
type CookieOptions = {
readonly path?: string;
readonly domain?: string;
readonly maxAge?: number;
readonly expires?: Date;
readonly httpOnly?: boolean;
readonly secure?: boolean;
readonly sameSite?: 'strict' | 'lax' | 'none';
};Fields
pathstring/by default.domainstring- Not set by default.
maxAgenumber- The lifetime in seconds.
0expires it at once. expiresDate- The expiry, as a
Date. httpOnlybooleantrueby default, so a page’s script cannot read it.securebooleantrueby default, so it is sent over HTTPS only. For an HTTP request tolocalhost,127.0.0.1or[::1], the default isfalse.sameSite'strict' | 'lax' | 'none''lax'by default.'none'is alwayssecure, by default too. Passing it withsecure: falseis an error.
responseHeaders
Import from @k8ordo/framework/server
Server mode only. Returns the Headers the final response will carry. Call it from a guard.ts, a route.ts or a Server Action.
responseHeaders(): HeadersCaveats
- A header set here goes on the response, whether that is a page’s HTML, its RSC payload or a
Responseaguard.tsreturned. A header the response already carries is replaced. - Outside a request it fails with
responseHeaders() needs a request, and inside a page render withresponseHeaders() belongs to what answers the request.
requestHeaders
Import from @k8ordo/framework/server
Server mode only. Returns the headers the request arrived with. Call it from a guard.ts, a route.ts or a Server Action. It is how a Server Action, which receives only its arguments, reads the headers.
requestHeaders(): HeadersCaveats
- Outside a request it fails with
requestHeaders() needs a request, and inside a page render withrequestHeaders() belongs to what answers the request.
redirect
Import from @k8ordo/framework/server
Server mode only. Ends a Server Action and redirects to another URL.
redirect(to: string): neverParameters
tostring- The target URL. It is sent as written, so build it with
href().
Returns
never — Never returns. The lines after it never run.
Caveats
- It ends the action by throwing, so do not call it inside a
try. - A form posted before JavaScript loaded gets a
303. A call from the client runtime gets a payload that tells the router where to go.
nonce
Import from @k8ordo/framework/server
Server mode only. Returns the nonce this response’s inline scripts carry. It is new for every request.
nonce(): stringCaveats
- While the request is being handled, the render included, it returns the same value.
- Outside a request it fails with
nonce() needs a request.
Guard
Import from @k8ordo/framework/server
Server mode only. The type of what a guard.ts default-exports. Pass its directory’s pattern as the type argument.
type Guard<P extends string = string> = (
context: GuardContext<P>,
) => Response | void | Promise<Response | void>;Fields
requestRequest- The
Requestas it arrived. paramsParamsOf<P>- The parameters of the directory’s pattern. A
guard.tsruns before any schema, so they are the URL’s strings.
RouteRequest
Import from @k8ordo/framework/server
Server mode only. The type of the request a page, a layout and a not-found.tsx receive. Both fields are read-only.
type RouteRequest = {
readonly headers: Headers;
readonly cookies: ReadonlyMap<string, string>;
};Fields
headersHeaders- The request’s headers.
cookiesReadonlyMap<string, string>- The
Cookieheader parsed by name. When a name appears twice, the first value is used.
RedirectTarget
Import from @k8ordo/framework/server
The type of what a redirect.ts default-exports. Write satisfies RedirectTarget to check the shape where it is written. It is a type-only import, so static mode may use it too.
type RedirectTarget =
| string
| { to: string; permanent?: boolean };serve
Import from @k8ordo/framework/serve
Runs the build on a Node.js HTTP server. Once it is listening, it returns its URL and a function to stop it.
serve(options?: ServeOptions): Promise<Server>Parameters
options.diststring- The build output directory.
distby default, resolved from the working directory. options.portnumber- The port to listen on.
3000by default.0lets the system pick a free one. options.hoststring- The host to listen on. The default,
localhost, is reachable from the same machine only, so pass0.0.0.0inside a container.
Returns
Promise<Server> — The server, once it is listening.
Fields
portnumber- The port it actually listens on.
urlstring- Its URL, in the form
http://<host>:<port>. close() => Promise<void>- Stops the server. The promise resolves once it has stopped.
Caveats
- To call it from a server of your own, put
@k8ordo/frameworkindependenciesand install it for run time as well. Thedist/server.jsa server mode build writes has it bundled in. - For a server mode build, a
GETorHEADthat names a file indist/client/gets that file. Everything else goes to the handler. - When the handler throws, it responds with a
500and the bodyinternal errorand logs what was thrown. - For a static mode build, the handler is never called. It looks for the file, then a rewrite in
_redirects, then404.html, and answers any method butGETandHEADwith a405.
serve.jsimport { serve } from '@k8ordo/framework/serve';
const server = await serve({ port: 3000 });
console.log(server.url);vercel
Import from @k8ordo/framework/vercel
A plugin that has vite build also write .vercel/output/ in the shape of Vercel’s Build Output API (v3). Put it beside framework(), in either mode.
vercel(): PluginReturns
Plugin — A Vite plugin.
Caveats
- Under server mode the function is the handler, with every dependency bundled in. A dependency left out with
resolve.externalis not in the function, and does not work on Vercel. - Under static mode there is no function: only the written files, and routes that rewrite a value the build did not write to its shell. Vercel does not read
_redirects.
vite.config.tsimport { framework } from '@k8ordo/framework/vite';
import { vercel } from '@k8ordo/framework/vercel';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [framework({ mode: 'server' }), vercel()],
});