All functions listed below are exported directly by one.
A function that takes two arguments: a string path, and a number status.
import { redirect } from 'one'
export function redirectToLogin() {
return redirect('/login')
}
It accepts relative paths by using the getURL helper internally.
On the server (including in loaders) it returns a Response.redirect object. On the client it calls router.navigate and returns void.
A function that takes no arguments and returns a string of the current URL of the running application on client or server.
For example, in dev-mode by default this would be a string of http://127.0.0.1:8081. In non-development environments you will need to set process.env.ONE_SERVER_URL to your production URL with no trailing /.
One uses Request/Response type objects for API routes, but for some environments doing an instanceof Response can fail, isResponse takes any value and returns true if it is a Response-like object. Useful for API utility functions.
A simple function allows for creating typed route strings. It's a type-level only check, at runtime it only validates that it is a string.
import { href } from 'one'
const postPageLink = href(`/post/hello-world`) // will type error if invalid Href
Developing
For improving performance of client hydration on the web, you can pass data from the server to the client. Data must be serializable to JSON.
Here's an example of a simple useFetch:
app/index.tsx
import { setServerData, getServerData } from 'one'
type SafeURLs = `${`https://tamagui.dev` | `http://localhost`}${string}
const useFetch = async (url: SafeURLs) => {
if (process.env.VITE_ENVIRONMENT === 'ssr') {
// on server data must be set during render
setServerData(url, await fetch(url).then(res => res.json()))
}
return getServerData(url)
}
export default async (props) => {
const serverData = await useFetch(props.url)
return <div />
}
// can use it in loaders, too
export const loader = async ({ params }) => {
await doSomething()
setServerData(params.idl, 'data')
return {}
}
Set HTTP response headers from anywhere during server-side rendering - loaders, components, or middleware. Headers are accumulated and merged onto the final response.
import { setResponseHeaders } from 'one'
await setResponseHeaders((headers) => {
headers.set('X-Custom-Header', 'value')
})
The headers parameter is a standard Headers object.
Use setResponseHeaders in loaders to enable CDN caching and Incremental Static Regeneration:
app/blog/[slug]+ssr.tsx
import { setResponseHeaders, useLoader } from 'one'
export async function loader({ params }) {
await setResponseHeaders((headers) => {
headers.set('Cache-Control', 'public, s-maxage=3600, stale-while-revalidate=86400')
})
const post = await fetchPost(params.slug)
return { post }
}
export default function BlogPost() {
const { post } = useLoader(loader)
return <article>{post.content}</article>
}
Common cache header patterns:
s-maxage=3600 - CDN caches for 1 hourstale-while-revalidate=86400 - Serve stale content while revalidating in background (up to 1 day)max-age=0, must-revalidate - Always revalidate with originprivate, no-store - Never cache (for user-specific data)Note: stale-while-revalidate requires CDN support (Vercel, CloudFront, Fastly). Cloudflare does not currently support it.
Set cookies using the standard Set-Cookie header:
app/auth/login+api.ts
import { setResponseHeaders } from 'one'
export async function POST(request: Request) {
const { token } = await authenticateUser(request)
await setResponseHeaders((headers) => {
headers.append('Set-Cookie', `session=${token}; HttpOnly; Secure; SameSite=Strict; Path=/`)
})
return Response.json({ success: true })
}
app/_middleware.ts
import { createMiddleware, setResponseHeaders } from 'one'
export default createMiddleware(({ request }) => {
setResponseHeaders((headers) => {
headers.set('X-Request-Id', crypto.randomUUID())
})
})
A function that registers a file dependency for hot reload during development. When the file changes, the loader will automatically re-run and refresh data on the client without a full page reload.
app/blog/[slug].tsx
import { watchFile } from 'one'
import { readFile } from 'fs/promises'
export async function loader({ params: { slug } }) {
const filePath = `./content/${slug}.mdx`
watchFile(filePath)
const content = await readFile(filePath, 'utf-8')
return { content }
}
fs.readFile or similarEdit this page on GitHub.