Pojďme vytvořit vlastní e-commerce s React a JAMstack - část 3

Pokud si chcete přečíst tento článek ve španělštině, podívejte se na můj blog:
The Developer's Dungeon

Ahoj lidi, co se děje? už je to pár týdnů, co jsme o tomto projektu mluvili, takže jste si možná mysleli, že projekt selhal, dovolte mi, abych vám řekl, že se to ani zdaleka nestalo.

Pracovali jsme velmi tvrdě a udělali jsme dobrý pokrok v některých základech, které naše aplikace musí pokrýt. Dnes vám ukážu, jak využíváme všechnu sílu příčetnosti k tomu, aby byla naše domovská stránka konfigurovatelná a načítání obrázků velmi cool způsobem, takže bez dalších okolků pojďme na to.

Požadavky

Každá webová stránka by měla mít domovskou stránku, naštěstí pro nás náš designový tým poskytl velmi vybroušené návrhy pomocí Figma, což nám umožnilo zkontrolovat vše rychleji a být vždy synchronizovaní. Vypadá to nějak takto:

V souvislosti s tímto návrhem se začaly objevovat první požadavky.

  • Umožněte konfigurovat domovskou stránku
  • Všechny obrázky je třeba načítat výkonným způsobem

To jsou velké výzvy, ale Sanity poskytuje vše, co potřebujeme k jejich implementaci.

Vytvoření konfigurovatelné stránky

Zde uděláme nějaké schéma v Sanity, které uživateli umožní nastavit konfigurační vlastnosti, vybrat obrázky, text a zajistit, aby naše domovská stránka získala vše, co je potřeba z této konfigurace vykreslit.

Nejprve definujeme 3 schémata, jedno pro homepage , jeden pro hero a jeden pro categories .
Pro domovskou stránku začneme definováním názvu domovské stránky, což je vlastnost typu hero a vlastnost typu array of category

export default {
  name: "homeSettings",
  type: "document",
  title: "\"Home sections\","
  __experimental_actions: [/*'create',*/ "update", /*'delete',*/ "publish"],
  fields: [
    {
      title: "\"TituloPagina\","
      name: "homePageTitle",
      type: "string",
      readOnly: true,
      hidden: true,
    },
    {
      title: "\"Hero\","
      name: "hero",
      type: "hero",
    },
    {
      title: "\"Categorias\","
      name: "categories",
      type: "array",
      of: [{ type: "category" }],
    },
  ],
  initialValue: () => ({
    homePageTitle: "Configuración Home",
  }),
};

Pro hero definujeme obrázek, název, podnadpis, text na tlačítku a URL pro tlačítko.

export default {
  name: "hero",
  type: "document",
  title: "\"Hero\","
  __experimental_actions: [/*'create',*/ "update", /*'delete',*/ "publish"],
  fields: [
    {
      title: "\"Imagen\","
      name: "image",
      type: "image",
      options: {
        metadata: ["lqip"],
      },
    },
    {
      title: "\"Titulo\","
      name: "title",
      type: "string",
    },
    {
      title: "\"Subtitulo\","
      name: "subtitle",
      type: "string",
    },
    {
      title: "\"Texto del boton\","
      name: "buttonText",
      type: "string",
    },
    {
      title: "\"Url del boton\","
      name: "buttonURL",
      type: "string",
    },
  ],
};

Nakonec definujeme typ nazvaný category který použijeme k vytvoření seznamu kategorií, který je dynamický i upravitelný.

export default {
  name: "category",
  type: "document",
  title: "\"Categoria\","
  __experimental_actions: [/*'create',*/ "update", /*'delete',*/ "publish"],
  fields: [
    {
      title: "\"Imagen\","
      name: "image",
      type: "image",
      options: {
        metadata: ["lqip"],
      },
    },
    {
      title: "\"Nombre\","
      name: "name",
      type: "string",
    },
  ],
};

Jako třešničku na dortu provádíme některé úpravy způsobu, jakým Sanity zobrazuje typy uvnitř studia:

import S from "@sanity/desk-tool/structure-builder";
import { MdSettings } from "react-icons/md";

export default () =>
  S.list()
    .title("Content")
    .showIcons()
    .items([
      S.listItem()
        .title("Configuración Home")
        .child(
          S.document().schemaType("homeSettings").documentId("homeSettings")
        )
        .icon(MdSettings),
      // Add a visual divider (optional)
      S.divider(),
      // List out the rest of the document types, but filter out the config type
      ...S.documentTypeListItems().filter(
        (listItem) =>
          !["homeSettings", "hero", "category"].includes(listItem.getId())
      ),
    ]);

Tím získáme následující výsledek:


Jak můžete vidět, získáváme pěkné uživatelské rozhraní s možností nastavit všechna data, která chceme, aby naše stránky používaly, a zároveň zachovat samostatný model pro naše produkty. To se také stará o to, že můžeme definovat pouze jednu konfiguraci, neexistuje způsob, jak vytvořit další domovský dokument.

Jak to tedy používáme na našem webu? pokud si vzpomínáte na naši předchozí epizodu, podařilo se nám přinést produkty od Sanity na web pouhým zadáním dotazu pomocí Sanity JavaScript klienta, zde není žádný rozdíl, i když dotaz je trochu složitější.
Z naší aplikace Next.js děláme následující:

export const getServerSideProps = async () => {
  const sanityResult = await sanity.fetch(
    `
    *[_type == "homeSettings"][0]{
      categories[] {      
        ...,
         "asset": image.asset-> {
            url,
            metadata 
         }
      },
       hero {
           ...,
         "asset": image.asset-> {
            url,
            metadata 
         }
       }
     }
  `
  );

  return { props: { ...sanityResult } };
};

Načteme celý homeSettings model, všimněte si, jak transformujeme obrázky do speciálního zdravého typu zvaného Asset, bude velmi jasné, proč to dělat při vytváření dalšího požadavku.

Odtud pouze vytvoříme normální aplikaci pro reakce, která tyto hodnoty používá k zobrazení obrázků a textu, jakmile administrátor něco změní ze sanity studio, změny se automaticky projeví na našem webu. Mimochodem, pokud chcete zkontrolovat, jak postupujeme, možná budete chtít zkontrolovat nasazení naší hlavní větve zde

Načítání obrázků správným způsobem

Toto je složité téma, existuje spousta článků a přístupů o tom, jak byste měli načítat obrázky na web, dnes se podíváme na dva problémy a uvidíme, jak jsme implementovali řešení pomocí Sanity.

První věc, kterou chceme vzít v úvahu, je, že obrázky, jako je ten v hrdinovi, mohou být super velké, což způsobí, že se naše webové stránky budou načítat velmi pomalu. Standardním přístupem k tomuto problému by bylo nahrát stejný obrázek ve 3 různých velikostech a načíst každý, když je to vhodné.

To je dobrý přístup, ale ve skutečnosti nemůžeme očekávat, že uživatel bude řešit všechny ty potíže. Naštěstí nám Sanity poskytuje transformace obrázků přímo z jejich API. Pokud si chcete přečíst více na toto téma, můžete jít sem.

Co to ale znamená pro nás? velmi jednoduché, spuštěním metod z JavaScript klienta Sanity můžeme přimět Sanity, aby se vypořádal s problémem poskytnutí správné velikosti obrázku, musíme se postarat pouze o nahrání obrázku v největším rozlišení, které chceme podporovat, a poté bude vše uděláno pro nás.

Podívejme se jak:

V naší běžné značce obrázků definujeme sadu srcset pro poskytování responzivních obrázků, ale místo 3 různých souborů požadujeme 3 různé šířky klienta Sanity.

 srcSet={`
     ${builder.image(image).auto('format')?.width(600)} 600w,
     ${builder.image(image).auto('format')?.width(1000)} 1000w,
     ${builder.image(image).auto('format')} 2000w
`}

Super snadné, že? možná se ptáte, co je to auto('format') to je další skvělá věc, kterou můžeme s příčetností udělat.

Nemůžeme očekávat, že uživatel nahraje obrázek ve formátu, který je dobrý pro náš web, takže zahrnutím tohoto volání, pokud prohlížeč podporuje webp vrátí obrázek v tomto formátu, který je pro web nejlepší.

stačí to? dobře, pojďme o tom jednu minutu přemýšlet. Nyní se budou obrázky načítat v závislosti na rozlišení, které máme na zařízení, což je skvělé, ale stále se potýkáme s tím, že pokud je připojení k internetu pomalé, obrázky se načítají věčnost a načítání uživatelského rozhraní bude trvat věky a vypadat při tom divně.

Pro vyřešení tohoto problému můžeme udělat dvě věci, první je líné načítání.
Léné načítání znamená, že obrázky budou požádány o Sanity pouze tehdy, když je budeme potřebovat. Pokud snímek není součástí výřezu, snímky nejsou požadovány.

Pro implementaci jsou dvě možnosti, můžete si vybrat vlastní komponentu nebo použít knihovnu jako React Lazy Loading Image Component. V našem případě jsme se stále nerozhodli, zda knihovna pokryje všechny naše potřeby, takže obě implementace si zatím necháváme.
S těmito změnami se naše kategorie produktů načtou, až když se posuneme dolů na naší domovské stránce.

A konečně poslední změnou, kterou potřebujeme, je použití Low-Quality Image Placeholder (LQIP). LQIP je jen velmi malá rozmazaná verze vašeho obrázku, která je načtena jako první a okamžitě zobrazena, zatímco skutečný je načten na pozadí. Po načtení skutečného obrázku se zástupný symbol nahradí. To umožňuje, aby naše webové stránky vypadaly dobře, zatímco čekáme na stažení obrázků.

K tomu použijeme Asset jsme zmínili dříve. Sanity pro nás automaticky vytvoří LQIP jako metadata obrazového díla. Jediné, co musíme udělat, je vyžádat si jej od klienta a použít jej v rámci naší Image Comonennt. Pojďme na to:

import { getImageAsset } from '@sanity/asset-utils';

src={getImageAsset(asset).metadata.lqip}

Neříkejte, že to nebylo snadné? Podívejme se na výsledek:

Neznám vás, ale já jsem s výsledkem maximálně spokojená 😄

To je ono, tohle byl dlouhý praktický příklad, takže vám chci moc poděkovat, že jste se mnou vydrželi až do konce. Myslím, že vám to dává pěknou představu o tom, jaké věci můžete dosáhnout pomocí CMS, jako je Sanity, uvnitř vašeho projektu. Btw nemám žádný vztah k Sanity, ale díky tomuto projektu miluji jejich úžasný produkt.

Pokud se vám můj článek a tato série líbily, sdílejte a dejte mi vědět v komentářích 😄