Saltar al contenido
Guías

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.

ArchivoRuta
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

pages/products.$productSlug.tsx
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:

  • preload
  • loading
  • error
  • meta con title, description, ogImage, noIndex, meta y jsonLd

Layout global

layout.tsx es opcional. Si existe, reemplaza el layout básico del framework:

layout.tsx
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í:

pages/api/$.ts
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/addresses y /account/orders
  • /account/orders/:orderId y /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.

En esta página