A Loader in deco.cx is a Typescript function that returns data typically
needed in a Section. These functions are executed
before page renders, and their main purpose is to fetch data from external
sources, transform it if necessary, and provide it to the site Sections that
need it. Loaders can be used to fetch data from APIs, databases, or any other
external source. They live locally on the /loaders/
folder of your project,
but it's also possible to
Installing apps that contain
loaders.
In addition to fetching data, Loaders in deco.cx can also export a Typescript Props type, which allows them to be configured in the Admin just like Sections. This means that business users can configure details about how the Loader will operate, such as setting up filters or passing parameters to APIs. By making Loaders configurable in this way, it becomes easier to manage the data flowing into Sections and ensure that the Site is displaying the right information to visitors.
One other great benefit of Loaders in deco.cx is that multiple loaders can return the same data type. This allows Sections that receive, for example, an array of canonical Product to get data from different Loaders, depending on the user's configuration. This means that UIs can be reused across Sites or across teams, making it easier to manage and scale your project.
All Sections for ecommerce stores created by deco.cx in the Storefront start use a canonical Product type, and also every Loader that connects to ecommerce providers's APIs. This means that you can reuse the same UI to show data from different places, depending on the configuration.
Example Code
This is the implementation of the shopify/loaders/ProductList.ts
Loader:
import type { Product } from "../../commerce/types.ts";
import { AppContext } from "../../shopify/mod.ts";
import { ListProducts } from "../utils/storefront/queries.ts";
import {
ListProductsQuery,
ListProductsQueryVariables,
} from "../utils/storefront/storefront.graphql.gen.ts";
import { toProduct } from "../utils/transform.ts";
export interface Props {
/** @description search term to use on search */
query: string;
/** @description total number of items to display */
count: number;
}
/**
* @title Shopify Integration
* @description Product List loader
*/
const loader = async (
props: Props,
_req: Request,
ctx: AppContext,
): Promise<Product[] | null> => {
const { storefront } = ctx;
const count = props.count ?? 12;
const query = props.query || "";
const data = await storefront.query<
ListProductsQuery,
ListProductsQueryVariables
>({
variables: { first: count, query },
...ListProducts,
});
// Transform Shopify product format into schema.org's compatible format
// If a property is missing from the final `products` array you can add
// it in here
const products = data?.products.nodes.map((p) =>
toProduct(p, p.variants.nodes[0], new URL(_req.url))
);
return products ?? [];
};
export default loader;