Home
The store's home page: loads the blocks the merchant arranged and draws each one with the component registered for its path.
import { Home, homeLoader, HomeSkeleton, HomeLoaderData, HomePageProps } from '@salla.sa/twilight-theme-engine/routes/home';In plain words
In the Salla dashboard a merchant builds the home page from blocks: a slider, a banner, a row of products. Home.loader asks the API for that list, and Home.Component draws the blocks in order, each with the component your theme registered for that kind of block.
HomeSkeleton is the grey placeholder the home route shows while the list loads during a client navigation.
See the whole page running on Built-in pages.
Signature
const Home: {
readonly id: 'index';
readonly loader: (ctx?: { locale?: string }) => Promise<HomeLoaderData>; // no extend
readonly head: (ctx: TwilightContext) => HeadDescriptor; // ignores loader data
readonly Component: React.MemoExoticComponent<(props: HomePageProps) => JSX.Element>;
};
function homeLoader(ctx?: { locale?: string }): Promise<HomeLoaderData>;
const HomeSkeleton: React.MemoExoticComponent<() => JSX.Element>;
interface HomeLoaderData {
locale: string; // ctx.locale, or 'ar'
components: HomeComponentData[]; // the blocks, "home." removed from each path
page: { slug: string }; // 'index'
}
interface HomePageProps {
locale?: string;
components?: HomeComponentData[];
}Try it live
import { createFileRoute } from '@tanstack/react-router';
import { Home } from '@salla.sa/twilight-theme-engine/routes/home';
import type { HomeLoaderData } from '@salla.sa/twilight-theme-engine/routes/home';
import { HomeSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
// app/routes/index.tsx, as the plugin generates it (without its first line)
export const Route = createFileRoute('/{-$locale}/')({
loader: ({ params }): Promise<HomeLoaderData> => Home.loader({ locale: params.locale }),
head: withHead(Home),
pendingComponent: () => <HomeSkeleton />,
component: HomeComponent,
});
function HomeComponent() {
const data: HomeLoaderData = Route.useLoaderData(); // <- drawn now
return <Home.Component {...data} />;
}
Example
import { createFileRoute } from '@tanstack/react-router';
import { Home } from '@salla.sa/twilight-theme-engine/routes/home';
import type { HomeLoaderData } from '@salla.sa/twilight-theme-engine/routes/home';
import { HomeSkeleton } from '@salla.sa/twilight-theme-engine/skeleton';
import { withHead } from '@salla.sa/twilight-theme-engine/tanstack';
export const Route = createFileRoute('/{-$locale}/')({
loader: ({ params }): Promise<HomeLoaderData> => Home.loader({ locale: params.locale }),
head: withHead(Home),
pendingComponent: () => <HomeSkeleton />,
component: HomeComponent,
});
function HomeComponent() {
const data: HomeLoaderData = Route.useLoaderData();
return <Home.Component {...data} />;
}
How it behaves
URL:
/{-$locale}/. The generated route importsHomeSkeletonfrom@salla.sa/twilight-theme-engine/skeleton; it is the same component.homeLoaderreads the list withqueryClient.ensureQueryData(home.queries.components()), so a list already in the query cache is returned without a request. It removes the firsthome.from each block'spath(home.enhanced-sliderbecomesenhanced-slider), which is the name themes register their own blocks under.Home.loaderpasses onlylocaletohomeLoader.HomeLoaderData.localeis not used by the component.headignores the loader data. Title, description and keywords come from the store's SEO settings (store.meta, falling back to the store name and description),canonicalfrom the store URL, the Open Graph and Twitter image from the logo, plus hreflang alternates. It returns{}when the context has no store.Home.Componentrenders the slotshome:startandhome:content, oneHomeComponentRendererper block, thenhome:end. The first three blocks render at once; later ones mount when scrolled near (see HomeComponentRenderer).To show the blocks outside the home route, read them in a component with
useQuery(home.queries.components())and removehome.from each path, as the demo does.homeLoaderbelongs in loaders.In development the dev settings widget can overlay edits on the blocks; that code is removed from production builds.
Gotchas
Nothing registers blocks for you. Without
registerHomeComponents(...)inapp/router.tsxevery block resolves to nothing: a yellow "Unknown component" card in development, an empty space in production. See the home block registry.HomeComponentRendererlogs[HomeComponentRenderer] MOUNTandUNMOUNTwithconsole.logfor every block, in production too: that effect is not behind a development check (packages/theme-engine/src/components/home/HomePageRenderer.tsx).
Related
The home block registry, re-exported beside the Home module: register which component draws each kind of block before any page renders.
HomeComponentRendererDraws one home page block from its API data: finds its registered component, wraps it in an error boundary, and defers it until visible.
registerHomeComponentsTells the engine which component draws each home page block, by the block path the Salla API sends. Call it once at startup.
Page skeletonsLoading placeholders shaped like the home, product, cart, blog and account pages, shown while the next page loads its data.