Páginas y rutas
Crea rutas SSR con pages/, definePage y serverApi.
La CLI convierte los archivos de pages/ en rutas. No configures TanStack
Router ni Vite manualmente.
| Archivo | Ruta |
|---|---|
pages/index.tsx | / |
pages/products.index.tsx | /products/ |
pages/products.$productSlug.tsx | /products/:productSlug |
pages/api/$.ts | /api/* |
Las páginas de UI usan .tsx o .jsx. Las rutas API usan .ts y pueden
exportar handlers GET, POST, PUT, PATCH y DELETE.
Página con datos
import {
definePage,
serverApi,
stripHtml,
z,
type ProductDetail,
} from "@ecomiq/storefront";
const SearchSchema = z.object({
sellerId: z.string().uuid().optional(),
});
type ProductSearch = z.infer<typeof SearchSchema>;
export default definePage<
ProductDetail,
{ productSlug: string },
ProductSearch
>({
validateSearch: (raw) => SearchSchema.parse(raw),
loader: ({ params, search }) =>
serverApi.getProductBySlug(params.productSlug, {
sellerId: search.sellerId,
}),
meta: ({ data }) => ({
title: data.name,
description: stripHtml(data.description).slice(0, 155),
ogImage: data.images[0]?.url || data.imageUrl,
}),
component: ({ data, settings }) => (
<article>
<p>{settings.store.name}</p>
<h1>{data.name}</h1>
<p>
{data.price} {settings.store.currency}
</p>
</article>
),
});loader recibe { params, search, config }. component recibe
{ data, params, search, settings }. Las búsquedas de la URL vuelven a ejecutar
el loader por defecto; usa reloadOnSearch: false si las manejarás en el cliente.
definePage también acepta:
preloadloadingerrormetacontitle,description,ogImage,noIndex,metayjsonLd
Layout global
layout.tsx es opcional. Si existe, reemplaza el layout básico del framework:
import { defineLayout, Link, useMenu } from "@ecomiq/storefront";
export default defineLayout(({ children, settings }) => {
const main = useMenu("main");
return (
<>
<header>
<Link to="/">{settings.store.name}</Link>
<nav>
{main.map((item) => (
<Link key={item.url} to={item.url}>
{item.label}
</Link>
))}
</nav>
</header>
<main>{children}</main>
</>
);
});Proxy same-origin
Las cuentas de cliente usan un proxy /api/*. El starter lo define así:
import { proxyStorefrontRequest } from "@ecomiq/storefront";
type ApiHandlerArgs = {
request: Request;
params: { _splat?: string };
};
async function handle({ request, params }: ApiHandlerArgs) {
return proxyStorefrontRequest(request, params._splat);
}
export const GET = handle;
export const POST = handle;
export const PUT = handle;
export const PATCH = handle;
export const DELETE = handle;Rutas reservadas
El framework genera y protege estas rutas:
/checkout/y/checkout/:checkoutId/thank-you/pages/:pageSlug/account/,/account/addressesy/account/orders/account/orders/:orderIdy/account/devices
No crees archivos en pages/ que intenten reemplazarlas. /account/devices
es actualmente una pantalla informativa: todavía no hay un endpoint para
listar dispositivos.