Hopp til innholdet

Start et prosjekt med React, Sanity og Sass fra scratch

I denne tutorialen går vi svært grundig gjennom steg for steg hvordan man setter opp et prosjekt som bruker React for frontend med visning av data, Sanity som CMS for lagring og henting av data og en innebygd kompileringsfunksjon for å skrive Sass som blir laget om til komprimert CSS.

Mål

Når vi er gjennom denne tutorialen har vi et prosjekt på vår datamaskin som kjører React, som igjen er koblet mot et datasett i Sanity og klarer å ta imot data derfra, og har Sass-kompilator installert og klart til å skrive (S)CSS og brukes for styling. Prosjektet er lastet opp til Github, og kan videreutvikles eller brukes som en boilerplate for andre prosjekter.

Vi bruker en enkel handleliste som eksempel i tutorialen for å ha et lettforståelig eksempel med lite ferdig utfylt data, slik at det vil være lett å bruke produktet av denne tutorialen som en base for nye prosjekter.

Forutsetninger

Du bør ha en fungerende kunnskap om HTML og CSS, og vite hva JavaScript er for noe. Du må ikke ha jobbet med React mye tidligere for å komme gjennom dette oppsettet, men må regne med å lære deg en del underveis og etter tutorialen er ferdig.

For å følge denne tutorialen med minst mulig tankekraft trenger du følgende klart før du starter:

  • I tutorialen bruker vi GitHub for å lagre koden vår til skylagring og holde versjonskontroll. Hvis du er kjent med Git og repositories, hopp videre og start på steg 2. Hvis ikke, last ned Github Desktop og lag en brukerkonto på Github.com. Mer hjelp? Sjekk tutorialen «Kjapp introduksjon til Git og Github».
  • I tutorialen bruker vi kodeeditoren Visual Studio Code. Du kan fint bruke en annen kodeeditor dersom du ønsker dette. Hvis du ikke har en kodeeditor, eller ønsker å følge tutorialen så likt som mulig, last ned Visual Studio Code herfra og installer den på maskinen din.
  • Du må ha node.js installert på maskinen din. Hvis du ikke har det, last det ned fra nodejs.org og installer det på maskinen din.
  • Du må ha en konto på og være innlogget på Sanity sine nettsider.

Innhold i tutorialen

  1. Klargjør et Github repository
  2. Sett opp arbeidsmiljøet og React-prosjektet
  3. Sett opp Sanity-prosjektet
  4. Lage et innholds-schema i Sanity
  5. Koble Sanity-databasen med React-appen (client)
  6. Sett opp CSS/SASS i prosjektet

Steg 1: Klargjør et Github repository

Logg deg på Github.com, og lag et repository du vil lagre prosjektet ditt i. I vår tutorial kaller vi dette repositoriet (og prosjektet) RSS_boilerplate, hvor RSS er en forkortelse for React + Sanity + Sass.

Åpne Github Desktop, og klon prosjektet ned til din lokale maskin. Obs: legg merke til feltet «Local Path», som forteller hvor på din lokale maskin dette prosjektet blir opprettet og lagret.

På din lokale datamaskin, naviger deg fram til mappen du klonet. I dette eksempelet ligger mappen på den lokale filstien C:\Users\toremake\Documents\GitHub\RSS_boilerplate.

Steg 2: Sett opp arbeidsmiljøet og React-prosjektet

Åpne Visual Studio Code (heretter forkortet VSCode). Hvis dette er første gangen du åpner VSCode, vil du få noen valg om å åpne filer eller mapper. Hvis du allerede har et åpnet prosjekt du ikke ønsker å lukke, gå til Fil i toppmenyen og velg Nytt vindu (tastatursnarvei: CTRL + SHIFT + N).

I åpningsbildet for det nye VSCode-vinduet, velg «Åpne mappe…» og finn fram den lokale mappen fra du klonet Github-repositoriet i steg 1. Da vil du få opp et arbeidsmiljø kalt RSS_boilerplate som kun innholder èn fil: readme.md.

Det første vi skal gjøre er å sette opp React-prosjektet vårt. Høyreklikk rett under mappenavnet RSS_boilerplate i VSCode, og velg «Åpne i integrert terminal» fra menyen. Da vil du få opp et terminalvindu som lar seg skrive kommandoer.

Terminalvinduet brukes for å fortelle VSCode at den skal installere de grunnleggende filene vi trenger for å kunne kjøre React-programkode. Fordi vi har node.js installert på maskinen vår nå, kan vi bruke kommandoene fra Node Package Manager (forkortet npm) for å hente ned småprogrammer som hjelper oss i utviklingen. Det første vi skal gjøre er å hente alt vi trenger for å kjøre React, som heldigvis er pakket sammen for oss til et startpunkt. Vi skriver derfor kommandoen

 npx create-react-app rss_boilerplateCode language: JavaScript (javascript)

Denne kommandoen består av tre sekvenser:

  • npx: kommandoen for å bruke pakkekjøringsverktøyet i npm
  • create-react-app: forteller hvilken pakke vi ønsker å kjøre. Denne installerer alle pakker vi trenger for å kjøre et react-prosjekt.
  • rss_boilerplate: vårt eget prosjektnavn som pakken create-react-app blir kjørt til

Når vi kjører denne kommandoen, blir det installert en mappe kalt rss_boilerplate på vår maskin med alle filer og pakker som behøves for å lage en react-applikasjon. I filexploreren i VSCode, åpne den nyinstallerte rss_boilerplate-mappen. Her inne ligger det en del filer og mapper tilgjengelig for oss:

  • node_modules: Mappe med pakker fra node.js og node package manager med scripts og funksjoner vi trenger for å kjøre react-prosjektet vårt.
  • public: Mappe med den endelige applikasjonen vi lager
  • src: Kort for «source», altså kilde. Denne mappen inneholder alle kode- og script-filer vi skal bruke for å programmere applikasjonen vår og sette opp datastrukturen vi skal bruke (som lagres og hentes fra Sanity)
  • .gitignore: Fil som forteller hvilke mapper og filer som ikke behøves lastes opp til Github når vi lagrer prosjektet vårt. Dette er spesielt viktig for node_modules: denne mappen inneholder massevis av filer og tar opp stor plass. Hvis man skal åpne prosjektet på en annen PC (eller f.eks. jobbe sammen med andre som skal installere og jobbe på det samme prosjektet), vil filen package.json fortelle hvilke pakker fra node_modules dette prosjektet er avhengig av, og enten bruke dem hvis de finnes på denne PCen, eller installere dem der uten å måtte lastes ned fra Github.
  • package-lock.json: Sikkerhetsfil som sørger for at oppsettet i package.json forblir likt selv om flere datamaskiner åpner og jobber på det samme prosjektet.
  • package.json: Prosjektoversikt som viser hvilke pakker dette prosjektet er avhengig av. Viktig for at man skal kunne kjøre det samme prosjektet på flere PC-er, f.eks. ved samarbeid.
  • readme.md: En standard les meg-fil fra React, som viser hvilke kommandoer som fungerer sammen med react-prosjektet.

Nå kan vi kjøre i gang prosjektet vårt for å sjekke at det fungerer! For å få til det, må vi først inn i prosjektmappa vår. Dette gjør vi ved å skrive følgende kommando i terminalen:

cd rss_boilerplate

Nå er vi inne i react-appen vår. I terminalen, skriv følgende kommando:

npm run start
Code language: JavaScript (javascript)

Hvis alt har gått bra ved installasjonen nå, vil det åpnes et nettleservindu med adressen http://localhost:3000. Dette betyr at React lager en lokal server med tilgang på port 3000, og kjører all koden fra react-applikasjonen dit. Bildet nå viser en standard react-forside:

Hva er npm run start?

Dette er en kommando til et script i prosjektet vårt. Hvis du åpner package.json, vil du finne en seksjon som heter scripts. «start» er kort-navnet på et script som kjører en funksjon fra react kalt react-scripts start – som igjen starter react-prosjektet og snurrer i gang en lokal server med websiden som utgjør applikasjonen vår.

Herlig. React-prosjektet er satt opp og vi kan begynne å gjøre det klart for vårt boilerplate-prosjekt.

Vi kommer til å gjøre mest arbeid i mappen src, som inneholder alle kode-filene. Åpne denne mappen i filutforskeren i VSCode, og lokaliser filen App.js. Dette er superhelten i react-applikasjonen din.

Fjern den første linjen, import logo from ‘./logo.svg’;, og alt som står mellom return ( og ), og bytt dette ut med en <h1>-tag med teksten «Handleliste», slik at du står igjen med følgende kode:

import './App.css';

function App() {
  return (
    <h1>Handleliste</h1>
  );
}

export default App;
Code language: JavaScript (javascript)

Lagre filen App.js. Nå vil nettsiden i nettleservinduet som åpnet seg i sted vise en veeeeldig enkel nettside:

Men det enkle er jo ofte det beste! Dette betyr at vi har et oppegående react-prosjekt! Nå er en grei tid å lagre boilerplaten vi har laget så langt til Github. Gå tilbake til Github Desktop-programmet. Der vil dere nå i venstre kolonne se en liste med «18 changed files». (Denne listen hadde vært på mange 1000 dersom vi ikke hadde hatt med .gitignore-filen, som sørger for at node_modules-mappen ikke må lastes opp.

Skriv en kort, beskrivende tekst i summary-feltet for hva vi har gjort, eksempelvis «Opprettet react-prosjekt», og klikk knappen «Commit to main».

Når de endrede filene er «commitet», klikk knappen «Push origin». Dette sender filene til repositoriet vi laget på Github.com tidligere, og vil nå fungere både som en versjonskontroll som gjør det mulig å hente tilbake gamle filer dersom vi tuller til noe i framtiden, og som en kjerne for all jobben vår som kan hentes ned og jobbes med av flere.

Etter du har klikket «Push origin» og filene er lastet opp til Github, vil listen under «Changes» bli tom igjen. Dette er helt riktig; nå har du lastet opp de siste endringene, og Github Desktop følger med i mappen for å se om/når du gjør nye endringer i noen av filene. Da dukker de opp i listen, og lar deg gjøre en ny Commit og Push-prosedyre.

Det neste vi ønsker nå, er å koble dette opp mot Sanity, slik at vi har et sted å hente informasjon fra.

Steg 3: Sett opp Sanity-prosjektet

Sanity lagrer data, og er enkelt sagt en database. Det blir litt tydeligere etter hvert som vi nå installerer Sanity i prosjektet vårt og ser på hvordan vi strukturerer og lager innhold, og senere henter dette inn i React-appen vår.

Som med React-prosjektet vårt bruker vi terminalen og kommandoer mot node.js og npm for å hente de pakkene med kode vi trenger for å kunne bruke Sanity. Hvis du fortsatt har React-applikasjonen kjørende (etter vi kjørte npm run start i slutten av steg 2) får du ikke skrevet noe i terminalen nå. Dette er fordi React-applikasjonen må kjøre konstant for å ha den virtuelle serveren med nettsiden levende, og for å klare å spore og vise endringer vi gjør i applikasjonen vår. Mens vi installerer Sanity, trenger vi ikke å ha applikasjonen vår kjørende, derfor kan vi trykke CTRL + C, for å få spørsmål om vi ønsker å avslutte den pågående prosessen. Vi svarer ja på dette ved å trykke Y (for Yes), og får muligheten til å skrive kommandoer i terminalen igjen:

PS: før vi starter installasjonen av Sanity, sørg for at du har en konto på sanity.io og er logget inn der. Dette må du for å koble sammen React-applikasjonen vi har laget med Sanity-databasen på internett.

Når du har laget deg en sanity konto kan du gå til forsiden og trykke på den blå knappen med teksten «Get started». Det som skal møte deg etter dette er en tilsvarende side:

Hvis man er logget inn på en Google eller Github konto kan siden som møter deg være:

Hvis du møter det første bilde velger du hva du vil bruke for å logge inn med, deretter trykker du «Let´s go». Når du gjør det kommer du videre til en side som setter opp prosjektet for deg, huk av for de alternativene som er relevant for deg og ditt prosjekt. For dette prosjektet kan vi velge: Other, React og None. Og deretter velge «continue». Etter dette skal du komme til en installasjonsside, den skal se slik ut:

Kopier med deg terminal kommandoen, denne skal limes inn i terminalen i Visual Studio Code. Den kan limes inn på samme nivå som src mappa (IKKE I SRC) i React prosjektet.

Når du har limt inn kommandoen og kjørt den kommer du til å få noen valg før du kan fortsette. Det første du må bekrefte er filstien sanity skal legge seg på. Slik som filstien er nå kommer prosjektet til å legge seg i React mappa på samme nivå som src, node_moduels, public, .gitignore, package-lock.json, pacakage.json og README.md. Mappenavnet blir prosjektetnavnet som sanity ga oss når prosjektet ble satt opp. Når du har godkjent plasseringen til mappen får du et valg over hvilken «package manager» du skal bruke for å installere «dependencies», by default så står den på npm, det er den vi skal bruke derfor kan du trykke enter her også.

Ved bruk av kommandoen vi fikk i starten har sanity satt opp prosjektet vårt, dette er nytt i v3. I den tidligere versjonen v2 måtte vi sette opp prosjekt, datasett og filsti fra kommandolinjen.

Hva er et datasett i Sanity?

Et datasett er en samling med data. Dette er nyttig dersom du lager et prosjekt som stadig skal utvikles. Da har du et datasett for applikasjonen som ligger live, og et datasett for utvikling eller testing, slik at du ikke rører dataene i den levende applikasjonen mens du utvikler.

OBS: Hvis vi åpner Github Desktop nå, ser vi at det plutselig er veldig mange filer i listen over endrede filer!

Alle ligger i den nye mappen vår, her kalt rssdatabase. Dette er fordi vi får en ny node_modules-mappe med pakkene vi trenger for å kjøre Sanity!

Her må vi oppdatere .gitignore-filen vår, og fortelle at vi ikke ønsker å sende med denne node_modules-mappen når vi laster opp til Github. Finn filen .gitignore i VSCode-filutforskeren og åpne denne. Under linje 4, legg til følgende mappe- og filsti for å fortelle at vi ikke ønsker å inkludere node_modules-mappen inni rssdatabase-mappen når vi lagrer prosjektet i Github:

/rssdatabase/node_modules

Når vi lagrer .gitignore-filen nå, og går tilbake til Github Desktop, er listen redusert fra 50.000+ filer til kun 18. Pjuh! Da kan vi passe på å lagre endringene til Github, så vi skriver en kort melding i summary-feltet ala «Installert Sanity-klienten», klikker «Commit»-knappen, og deretter «Push»-er vi endringene til Github.

Nå er tiden kommer for å se om vi får kjørt Sanity hos oss. Ser vi i terminalen vår, har vi noen forslag til kommandoer vi kan kjøre. For å bekrefte at sanity er riktig installert og kjører, kjører vi følgende kommandoer i terminalen:

cd rssdatabase

Denne kommandoen flytter oss inn i mappen som inneholder alle filer vi trenger for å kjøre oppsett og tilkobling til sanity-databasen vår. Deretter må vi kjøre kommandoen for å starte vårt databasemiljø:

npm run dev

Hvis alt går som det skal nå, vil Sanity kjøre et lokalt studio vi får tilgang til. Studioet er et visuelt grensesnitt hvor vi etterhvert kan administrere innholdet vårt (etter vi har konfigurert innholdstyper og -felter via prosjektet vi jobber med).

Nå kan du åpne en fane i nettleser din og navigere til URL-en http://localhost:3333. Hvis du er logget inn i Sanity allerede (som nevnt i forutsetningene), vil du bli sendt direkte til «Desk»-visningen av prosjektet rss_database. Hvis ikke du er logget inn, blir du bedt om å logge inn med din Sanity-konto først.

Denne siden viser ikke stort enda, siden vi ikke har laget noen typer innhold vi skal lagre og vise enda. Men, at vi kommer inn på denne visningen betyr at Sanity er installert riktig og koblet til vår profil, som betyr at vi er klare for de to neste stegene; Lage innholdstyper via en struktur kalt Schema, og koble Sanity til React-applikasjonen vår så vi kan hente og vise innholdet!

Steg 4: Lag et innholds-schema i Sanity

For at Sanity skal forstå hvilket innhold vi vil ha tilgjengelig, må vi lage det som kalles et Schema. Men først er det greit med en kort forklaring av hva vi mener med innhold.

Innhold er tekst, bilder, linker og andre innholdselementer vi ønsker å lagre i en fast struktur. Vi kan ha ulike typer innhold (eller, «innholdstyper»). På en blogg vil for eksempel «artikkel» være en naturlig innholdstype, sammen med en innholdstype «kategori». Disse to typene innhold har en relasjon – en artikkel vil typisk være plassert i en (eller flere) kategori(er).

En innholdstype vil ha noen biter med informasjon, kalt «felter». Innholdstypen «blogg» vil typisk ha en tittel og en større tekst, antagelig publiseringsdato og kategori. Disse tre bitene med informasjon vil det være naturlig å tenke på som felter i en innholdstype.

Felter kan være av ulike typer. Det kan være tekststrenger, tall – eller som kategori-feltet i en blogg-artikkel – en referanse til en annen innholdstype. Det finnes utallige muligheter rundt felttyper i Sanity, men vi holder det forholdsvis enkelt i starten her.

Hvis vi tenker oss applikasjonen vi skal sette opp nå, tar vi utgangspunkt i en handleliste. Hvilke innholdstyper trenger vi her? «Vare» er en naturlig innholdstype – vi trenger noen varer vi skal kjøpe i handlelisten. For å teste relasjonen mellom innholdstyper, tenker vi også at vi vil ha et felt kalt «Kategori». Eksempel: vi vil ha kategoriene «kjøtt», «meieri», «snacks» og «husholdning» for å kunne gruppere varene i handlelisten vår.

Hvilke felter trenger innholdstypene våre? «Vare» bør ha et varenavn, og kanskje antall eller mengde (hvor mange skal vi kjøpe?). «Kategori» bør ha kategori-tittel. Med det oppsettet kan vi visuelt se for oss følgende struktur på innholdet:

I Sanity vil «Kategori» og «Vare» være hvert sitt Schema; altså strukturerte innholdsdokumenter. Den vanligste typen av Schema i Sanity er typen «document», som oppretter en menystruktur og muligheten for å lage innhold av denne typen i Sanitys studio. Ser vi på det samme bildet med Sanity-øyne, vil det se slik ut:

Nå har vi en grei oversikt over informasjonsstrukturen:

  • Schemaet «Vare» inneholder to felter:
    • et kalt varenavn av typen string (tekststreng)
    • et kalt kategori som er en referanse til et innhold av typen «Kategori».
  • «Kategori» er det andre Schemaet
    • med et felt kalt tittel av typen string.

Vår neste oppgave blir å lage disse Schemaene, så Sanity også blir kjent med denne innholdsstrukturen, og tillater oss å lage innhold.

Tilbake i Visual Studio Code, finn mappen «schemas» i filutforskeren. Denne ligger inne i rssdatabase-mappen. Opprett en ny fil i denne mappen kalt kategori.js.

Vi følger en rimelig standard struktur når vi gjør klar et schema. Følgende fire biter med informasjon er så og si alltid med, og er obligatoriske:

  • title: Tittelen som vises i Sanitys grensesnitt der du lager og administrerer innhold
  • name: navnet på schemaet, som brukes i koden. VIKTIG: bruk kun små bokstaver og til nøds understrek. Ikke bruk æ, ø, å eller spesialtegn, ikke mellomrom eller bindestrek. Du kan takke oss senere…
  • type: Hvilken type schemaet er. Når vi lager de viktigste innholdstypene er dette typisk «document»
  • fields: array med objecter. Objectene er felter som skal være tilgjengelig for denne innholdstypen

Vi setter schemaet vårt klart for innholdstypen «Kategori» med denne informasjonen:

//  rssdatabase/schemas/kategori.js

export default {
    title: "Kategori",
    name: "kategori",
    type: "document",
    fields: [
        //Felter kommer her
    ]
}
Code language: JavaScript (javascript)

OBS: Hvis du prøver å lagre filen nå vil du få en feilmelding, siden fields-arrayen er tom. Vi skal straks lage feltet som skal ligge her, så hold ut…

I «Kategori» skal vi kun ha ett felt, kalt Tittel av typen String. På samme måte som Schemaet selv har felter typisk tre biter av informasjon vi inkluderer i objektet (name og type er obligatoriske):

  • name: navnet på feltet, som brukes i koden. VIKTIG: bruk kun små bokstaver og til nøds understrek. Ikke bruk æ, ø, å eller spesialtegn, ikke mellomrom eller bindestrek.
  • type: hvilken type feltet er. Det finnes mange ferdigdefinerte typer i Sanity allerede, og man kan lage sine egne selv. Sjekk dem ut i Sanitys dokumentasjon.
  • title: En tittel som synes i Sanitys grensesnitt der du administrerer innhold.

Vi oppretter et object i fields-arrayen med denne felt-informasjonen, som gir oss denne koden:

// rssdatabase/schemas/kategori.js

export default {
    title: "Kategori",
    name: "kategori",
    type: "document",
    fields: [
        {
            name: "title",
            type: "string",
            title: "Kategorinavn"
        }
    ]
}
Code language: JavaScript (javascript)

Flott! Nå kan vi lagre denne filen.

Det neste, viktige steget er å koble vårt schema til Sanity. I filutforskeren i VSCode, i samme mappe som du har laget kategori.js-filen, finn filen schema.js og åpne denne. Nederst i denne filen vil du finne en kommentar der det står /* Your types here! */ . Her må du legge inn dine schemas – og her er det viktig at du har kontroll på schemaets name (Se på koden over. Schemaets name der er «kategori», bare små bokstaver, ingen spesialtegn). Begynn å skrive «kategori» under kommentaren /* Your types here */. Sannsynligvis vil VSCode da foreslå et schema du skal legge til.

Klikk på forslaget, og VSCode legger til kategori, og importerer filen kategori.js vi lagde i forrige steg.

OBS: Dersom VSCode ikke foreslår noe schema, eller ikke lager en import-setning med kategori.js i, må du skrive «kategori» ferdig selv under kommentaren /* Your types here! */ og skrive import-setningen selv. Da skal du sitte igjen med denne koden:

// rssdatabase/schemas/schema.js

// First, we must import the schema creator
import createSchema from 'part:@sanity/base/schema-creator'

// Then import schema types from any plugins that might expose them
import schemaTypes from 'all:part:@sanity/base/schema-type'
import kategori from './kategori'

// Then we give our schema to the builder and provide the result to Sanity
export default createSchema({
  // We name our schema
  name: 'default',
  // Then proceed to concatenate our document type
  // to the ones provided by any plugins that are installed
  types: schemaTypes.concat([
    /* Your types here! */
    kategori
  ]),
})
Code language: JavaScript (javascript)

Lagre schema.js. PS: legg merke til linje 8 (import-setningen) og linje 18 (innhentingen av schema), dette er de to eneste – men viktige – endringene i schema.js så langt.

Hvis Sanity fortsatt kjører i prosjektet ditt, kan du nå åpne http://localhost:3333/desk. Dette er «studioet» Sanity lager hvor du kan administrere innholdet ditt. Når vi testkjørte dette etter installasjonen i sted var det rimelig tomt her, men nå ligger det en innholdstype kalt «Kategori» tilgjengelig, og vi kan klikke oss inn på denne og legge til et par kategorier til handlelisten vår:

PS: Husk å klikke «Publish»-knappen etter du har skrevet inn en ny kategori. Hvis du prøver å hente innhold senere som ikke er publisert, vil du ikke finne det…

Da er det klart for å lage neste Schema: Vare. Denne er veldig lik Kategori, men har et litt mer spesielt felt: kategori. For at vi skal kunne velge kategori blant de vi nettopp har laget klar i Sanity, må vi bruke felttypen «reference». Denne forteller Sanity at feltet skal være en relasjon til en annen innholdstype, og selvfølgelig hvilken innholdstype (se Sanitys dokumentasjon om reference).

Schemaet Vare begynner likt som Kategori, vi må gjøre klar title, name, type og fields. Dette gjør vi i mappen schemas, hvor vi lager en ny fil kalt vare.js:

// rssdatabase/schemas/vare.js

export default {
    title: "Vare",
    name: "vare", 
    type: "document",
    fields: [
        //Felter kommer her
    ]
}Code language: JavaScript (javascript)

I fields-arrayen lager vi nå tre objekter, to med typen string (varenavn og mengde), og et med typen reference til innhold av typen kategori:

// rssdatabase/schemas/vare.js

export default {
    title: "Vare",
    name: "vare", 
    type: "document",
    fields: [
        {
            name: "varenavn",
            title: "Varenavn",
            type: "string"
        },
        {
            name: "mengde",
            title: "Mengde/antall",
            type: "string"
        },
        {
            name: "kategori",
            title: "Kategori",
            type: "reference",
            to: {type: "kategori"}
        }
    ]
}
Code language: JavaScript (javascript)

I linje 21 og 22 viser vi hvordan vi setter opp felttypen som en reference, og hvordan vi forteller hvilken type innhold feltet skal være en reference til.

Nå må vi legge inn vare som schema i Sanitys schema-oversikt på samme måte som med kategori. Åpne schema.js igjen, og legg inn vare etter kategori (som du la inn i sted). Husk et komma mellom, og at du må sikre at vare.js blir importert. Da skal schema.js se slik ut:

// rssdatabase/schemas/schema.js

// First, we must import the schema creator
import createSchema from 'part:@sanity/base/schema-creator'

// Then import schema types from any plugins that might expose them
import schemaTypes from 'all:part:@sanity/base/schema-type'
import kategori from './kategori'
import vare from './vare'

// Then we give our schema to the builder and provide the result to Sanity
export default createSchema({
  // We name our schema
  name: 'default',
  // Then proceed to concatenate our document type
  // to the ones provided by any plugins that are installed
  types: schemaTypes.concat([
    /* Your types here! */
    kategori, vare
  ]),
})
Code language: JavaScript (javascript)

Endringene kan du se på linje 9 og 19.

Når vi nå har lagret schema.js igjen, og Sanity har kjørt gjennom endringene våre, kan vi gå tilbake til htts://localhost:3333/desk og se at vi har fått enda en innholdstype vi kan lage innhold i. La oss legge til et par varer i hver kategori:

I feltet Kategori ser vi at vi kan søke opp eksisterende kategorier fra innholdstypen vi lagde innhold av i sted. Dermed får vi en relasjon mellom innholdstypene Kategori og Vare, og kan gruppere varer i kategorier.

Nå har vi både opprettet innholdstyper og innhold, da er det på tide å gå tilbake til denne «clienten» vi snakket om tidligere, og se hvordan vi får tak i dette innholdet i react-appen vår.

Steg 5: Koble Sanity-databasen med React-appen (client)

Vi må få vår nye, friske React-applikasjon til å snakke med Sanity, som ligger et annet sted på internett enn det React-applikasjonen gjør. Dette hjelper klienten oss med. Men før vi lager denne skal vi avslutte Sanity-prosessen vår ved å trykke CTRL + C i terminalen i VSCode. Deretter må vi bevege oss en mappe opp i strukturen vår, så vi befinner oss i mappen rss_boilerplate (som inneholder React-appen vår). Dette gjør vi ved å skrive og kjøre følgende kode i terminalen:

cd ..

De to punktumene betyr nettopp dette: En mappe tilbake (høyere) i strukturen vår.

Så må vi installere en pakke som inneholder alle bakenforliggende funksjoner som lar oss kjøre Sanitys klient. I terminalen, skriv følgende kode:

npm install @sanity/clientCode language: CSS (css)

Når denne pakken er installert, kjører vi i gang React-prosjektet vårt igjen med følgende kommando i terminalen:

npm start

Nå starter React-appen vår igjen, og vi får åpnet en nettleserfane med URL-en http://localhost:3000, og vi ser (den tomme) handlelisten vår.

Det første vi skal gjøre er å fylle handlelisten vår med varer. For å få til det trenger vi å gjøre følgende:

  • Gi React-appen vår tilgang til Sanity
  • Koble React-appen til Sanity (klienten, you know…)
  • Spørre React om å få tilsendt litt innhold (kalles ofte en «service», og denne trenger klienten fra steget over)
  • Bruke servicen fra steget over i React til å vise innholdet på nettsiden

Det første vi må gjøre er å sørge for at appen vår for lov til å hente innhold fra Sanity! Dette gjør vi i administrasjonspanelet hos Sanity på sanity.io/manage. Åpne denne nettsiden, og gå inn på Sanity-prosjektet ditt (kalt rss_database i denne tutorialen). Under fanen «API», har du en seksjon kalt «CORS origins», som beskrivende nok forteller at dette er «Hosts that can connect to the project API» – akkurat det vi skal! Klikk knappen «Add CORS origin», og legg til «http://localhost:3000», som er den lokale URL-en vi kjører prosjektet vårt på. Du trenger ikke huke av valget «Allow credentials». Klikk knappen «Save», og bekreft at localhost:3000 nå ligger i listen over aksepterte URL-er som får tilgang til Sanitys API.

Bra – da får React-appen vår lov til å hente ting fra Sanity. Nå skal vi sette opp de tingene vi trenger i appen vår for å snakke med Sanity!

For ryddighetens skyld lager vi oss en mappe til Sanity-tingene i React-prosjektet. I VSCode, under mappen «src», lag en mappe kalt «sanity». I denne mappen, lag en fil vi kaller «client.js». Da har vi omtrent denne strukturen:

client.js er en fil vi som regel setter opp en gang, og deretter ikke trenger å bry oss for mye om. Denne trenger først at vi importerer sanityClient fra npm-pakken @sanity/client som vi installerte i steg 3.

// src/sanity/client.js

import sanityClient from '@sanity/client'
Code language: JavaScript (javascript)

Det neste vi trenger er å lage et object med options. I utgangspunktet trenger dette objektet to biter med informasjon: Sanitys prosjektid og datasettet appen skal bruke. Datasettet er greit, det valgte vi i steg 3. I denne tutorialen har vi brukt standard, som vil si «production». Men hvor finner vi prosjektid-en? Det er to muligheter:

  1. Finn filen sanity.json i rssdatabase-mappen din i filutforskeren i VSCode. Der vil du ha et felt som heter projectId. Tekststrengen der er projectId-en du skal bruke.
  2. Åpne sanity.io/manage, og gå inn på prosjektet ditt. Under prosjekttittelen vil du finne et felt kalt PROJECT ID.

Kopier med deg projectId-en, og lag en variabel kalt «options» i client.js. Denne skal inneholde to nøkler; projectId og dataset:

// src/sanity/client.js

import sanityClient from '@sanity/client'

const options = {
    projectId: "g84vjx02", //Bytt ut denne med din projectId
    dataset: "production"
}
Code language: JavaScript (javascript)

Det neste steget er å sette opp selve klienten. Denne bruker sanityClient vi importerte helt i starten av filen, som tar imot minimum tre parametere: options vi nettopp har satt opp, api-versjonen vi ønsker å bruke (her er det trygt å bruke standarden vi bruker i denne tutorialen. Alternativer kan du finne ved å starte Sanity-prosessen i prosjektet ditt, og åpne localhost:3333. Gå til Vision-fanen, så ser du andre api-versjoner oppe i verktøyslinjen der), og om du skal bruke Sanitys CDN (Hva er CDN: Content Delivery Network?). Det gir oss følgende kode:

// src/sanity/client.js

import sanityClient from '@sanity/client'

const options = {
    projectId: "g84vjx02", //Bytt ut denne med din projectId
    dataset: "production"
}

const client = sanityClient({
    ...options,
    apiVersion: '2021-08-31',
    useCdn: true
});

export default client;
Code language: JavaScript (javascript)

Avslutningsvis exporterer vi client, så vi kan bruke denne videre i React-appen vår for å snakke med Sanity.

Det neste steget er å lage en «service», eller en fil som inneholder funksjoner for å spørre Sanity om det kan levere litt innhold til oss. I mappen vi befinner oss i, «sanity», lag en ny fil kalt service.js. Start denne filen med å importere clienten vi nettopp har laget:

// src/sanity/service.js

import client from "./client";
Code language: JavaScript (javascript)

Det neste vi skal gjøre er å lage en asynkron funksjon som bruker Sanitys spørrespråk («query language», kalt GROQ, kort for Graph-Relational Object Queries).

Vi gjør klar en asynkron funksjon vi skal bruke til å hente ut alle matvarene vi har lagret i Sanity-databasen vår:

// src/sanity/service.js

import client from "./client";

export const hentAlleVarer = async () => {
    //GROQ kommer her
}
Code language: JavaScript (javascript)

I denne funksjonen skal vi bruke klienten vi laget tidligere for å hente innhold med GROQ-spørrespråket. Med spørrespråk mener vi hvordan vi formulerer såkalte «spørringer», hvor vi «spør» Sanity om å gi oss noe bestemt innhold.

GROQ følger en gitt formulering:

*[type innhold]{felter vi vil ha tilbake}

Stjernen før firkant-parentesen betyr «hent alle». De fleste spørringer starter slik. Videre følger firkant-parenteres som forteller hvilken type innhold. Firkantparentesene kan også inneholde flere begrensninger, for eksempel at vi bare ønsker å hente innhold av typen vare i en bestemt kategori. I klamme-parentesene bak firkant-parentesene forteller vi hvilke felter fra denne typen innhold Sanity skal gi oss tilbake.

Vi ønsker å hente alt innhold av typen Vare, med navnet på varen og mengden vi skal ha. Da får vi en slik spørring:

*[_type == "vare"]{varenavn,mengde}Code language: JavaScript (javascript)

Hva? Understrek foran type? Ja, fordi Sanity har noen faste felter som blir laget for hvert innhold vi oppretter. Vi kan få en full oversikt over disse (og de vi har bestemt selv i schemaet vårt) ved å inspisere et innhold. Dette gjør vi i Sanity-studioet. For å komme til studioet må Sanity kjøre i prosjektet vårt, og vi må gå til http://localhost:3333. Der klikker vi oss inn på et innhold, i dette tilfellet en vare. Øverst til høyre er en knapp med tre vertikale prikker. Klikk på denne og velg Inspect. Da får vi et oversiktsbilde over alle feltene som er tilknyttet dette innholdet, og hvilken verdi alle feltene har:

Her kjenner vi igjen _type, som er «vare». Dette tilsvarer det vi skrev i nøkkelen «name» i rssdatabase/schemas/vare.js under steg 4. Vi ser også feltene vi opprettet, «mengde» og «varenavn», som i dette tilfellet er «1 pose» og «Mexican fiesta».

Det skulle bety at spørringen vår over fungerer. Nå må vi koble denne sammen med klienten vår for at Sanity skal «bli spurt» om å hente dette innholdet. Vi lager oss en variabel, og ber denne vente på at klienten henter (med kommandoen fetch) resultatene av spørringen vår:

// src/sanity/service.js

import client from "./client";

export const hentAlleVarer = async () => {
    const varer = await client.fetch(`*[_type == "vare"]{varenavn,mengde}`)
    return varer
}
Code language: JavaScript (javascript)

OBS: tegnene rundt spørringen er såkalte backticks. Dette er moderne javascript-syntax for det som kalles template literals, som lar oss koble sammen tekst, variabler og funksjonskall i en streng.

Nå har vi en service kalt hentAlleVarer som forhåpentligvis vil gi oss en liste med alle varene vi har lagret. Det skal vi finne ut om funker nå! Gå tilbake til App.js (moder-filen i React-appen vår, den som bare har en <h1> med teksten Handleliste i). I App.js skal vi nå

  • Lage en state-variabel kalt handlelistevarer med React-hooken state
  • Importere services,js, og lage en funksjon som kjører servicen hentAlleVarer
  • Lagre resultatene fra hentAlleVarer i state-variabelen
  • Gå gjennom state-variabelen handlelistevarer og skrive ut alle varene og mengden vi skal kjøpe

La oss starte med det enkleste: å importere servicene våre. Under linje 1, hvor vi importerer App.css, skriv følgende:

import {hentAlleVarer} from './sanity/service'Code language: JavaScript (javascript)

Da har vi fortalt App.js at vi ønsker å bruke hentAlleVarer-servicen. Det neste blir å importere useState fra React, så vi kan bruke state-hooken. Skriv følgende import-setning under setningen vi nettopp har importert services med:

import {useState} from 'react'Code language: JavaScript (javascript)

Da har vi følgende kode i App.js så langt:

import './App.css';
import {hentAlleVarer} from './sanity/service'
import {useState} from 'react'

function App() {
  return (
    <h1>Handleliste</h1>
  );
}

export default App;
Code language: JavaScript (javascript)

Neste steg blir å lage state-variabelen vår. Her må vi lage en variabel på state-måten, hvor vi oppretter navnet på state-variabelen, sammen med funksjonen for å sette en verdi i denne variabelen. Rett under deklarasjonen function App() {, skriv følgende kode:

const [handlelistevarer, setHandlelistevarer] = useState([])Code language: JavaScript (javascript)

Firkant-parentesene i useState() betyr at vi i utgangspunktet, når Appen laster, setter state-variabelen handlelistevarer til å være en tom variabel. Men den skal vi forhåpentligvis fylle opp nå! Nå skal vi lage en asynkron funksjon som bruker servicen vår for å hente varene, og lagre denne i state-variabelen. Under opprettelsen av handlelistevarer, legger vi følgende kode:

const samleVarer = async () => {
    const alleVarer = await hentAlleVarer();
    setHandlelistevarer(alleVarer);
}Code language: JavaScript (javascript)

Koden over lager en asynkron funksjon kalt samleVarer. Denne kjører servicen hentAlleVarer(), som spør Sanity om innhold, og tar imot innholdet Sanity sender tilbake til appen vår. Dette innholdet lagrer vi i variabelen alleVarer. Deretter setter vi innholdet lagret i alleVarer inn i state-variabelen handlelistevarer ved hjelp av funksjonen setHandlielistevarer().

Da skal App.js se slik ut så langt:

// src/App.js

import './App.css';
import {hentAlleVarer} from './sanity/service'
import {useState} from 'react'

function App() {
  const [handlelistevarer, setHandlelistevarer] = useState([])

  const samleVarer = async () => {
    const alleVarer = await hentAlleVarer();
    setHandlelistevarer(alleVarer);
  }

  return (
    <h1>Handleliste</h1>
  );
}

export default App;
Code language: JavaScript (javascript)

Nå nærmer vi oss å få tak i og kunne vise innholdet. Men, det vår asynkrone funksjon og service returnerer, er det som kalles et «Promise», altså et løfte om at noe skal bli sendt tilbake. Vi må nå kjøre funksjonen samleVarer() og hente innhold på en måte som gjør at JavaScript klarer å sjekke om dette løftet er oppfylt. Hvis vi kjører funksjonen direkte i App.js, vil vi bare få beskjed om at vi har fått et «Promise» uten å oppfylle det.

Les mer om Promises i JavaScript hos MDN

En av måtene vi kan kjøre funksjonen på i det denne komponenten (i dette tilfelle App.js) lastes inn på, er ved hjelp av useEffect(). useEffect er en hook i React som lever så lenge komponenten er aktiv, og kjøres så fort DOMen er lastet inn.

useEffect ligger i node-pakken ‘react’, akkurat som useState. Vi må derfor importere useEffect på samme måte. Sammenlign med koden over, linje 5, og oppdater denne til å også importere useEffect:

DOM: Document Object Model – eller hele komplette HTML-en inkludert kilder (som bilder, css o.l.) som blir generert av appen vår, i dette tilfellet handlelisten vi ser på nettsiden.

Les mer om DOM hos MDN)

import {useState, useEffect} from 'react'Code language: JavaScript (javascript)

Nå, rett over return-setningen vår, under deklarasjonen av funksjonen samleVarer vi lagde i forrige steg, kan vi kjøre useEffect-hooken og kalle funksjonen samleVarer() for å oppfylle løftet om innhold vi får fra Sanity:

useEffect(() => {
    samleVarer();
}, [])Code language: JavaScript (javascript)

Det koden gjør er å kjøre useEffect-hooken, som når komponenten har lastet ferdig DOM kjører og oppfyller funksjonen samleVarer() for oss. Firkant-parentesene som er tomme skal være tomme. Denne brukes til å fortelle useEffect hvilke states den skal lytte etter endringer i for å kjøre på nytt. For nå trenger vi ikke kjøre useEffect annet enn ved innlasting, så vi lar denne stå tom.

Nå skal vi ha et oppfylt løfte om innhold fra Sanity. La oss se om vi har lykkes. Under useEffect-koden vi nettopp skrev, log ut state-variabelen handlelistevarer til konsollen:

console.log(handlelistevarer)Code language: JavaScript (javascript)

Når vi lagrer filen og React-appen kompilerer oppdateringene, skal vi kunne gå tilbake til webappen vår på http://localhost:3000, og forhåpentligvis se en array med innhold i konsollen (åpne konsollen med snarveien F12 eller høyreklikk på nettsiden og velg Inspect/Inspiser, og velg deretter fanen Console):

Veldig lovende – vi har fått tilbake en array med åtte varer (fordi jeg la inn 8 varer i Sanity i steg 4). Nå må vi løpe gjennom arrayen i return og skrive ut hver vare med tilhørende mengde. La oss tenke oss at vi skal bygge en responsiv tabell ved hjelp av en uordnet liste. Vi trenger et første listeelement med kolonne-headinger aller først, og deretter en liste for hver vare, hvor vi legger varenavn og mengde i hver sin <div> med henholdsvis klassen «vare» og «mengde».

Startkoden for en slik liste vil se noe ala dette ut (plasseres rett under <h1>-tagen i return-området:

<ul>
      <li>
        <div className="vare heading">Vare</div>
        <div className="mengde heading">Mengde</div>
      </li>
      <li>
        <div className="vare">Melk</div>
        <div className="mengde">3 Liter</div>
      </li>
      <li>
        <div className="vare">Egg</div>
        <div className="mengde">12stk</div>
      </li>
 </ul>Code language: HTML, XML (xml)

Her tenker vi oss at <div>-er med klassen «vare» blir en kolonne, og <div>-er med klassen «mengde» blir en annen kolonne. I det første listelementet har <div>-ene i tillegg fått klassen «heading», så vi senere med CSS kan stile disse noe annerledes enn de vanlige vare-radene.

OBS: Hvis du har plassert koden over rett under <h1>-tagen og lagret, vil du få en feilmelding både i terminalen og på nettsiden som forteller at «Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>…</>?» Denne feilmeldingen kommer fordi React leser HTML litt spesielt – den tillater React- og JavaScript-kode inne i HTMLen. For å få til dette, krever den at all HTML-en har en foreldretag. Rundt en <h1> og en <ul> kan dette for eksempel være en <section>. Men i noen tilfeller (som du sikkert vil se senere i videre tutorials ut fra denne) er det ikke ønskelig å legge til en ekstra HTML-tag bare for å samle de andre HTML-elementene våre. Da kan vi bruke JSX fragment, som rett og slett er en tom tag (<> og </>). Denne lar React lese HTML-elementene inni seg riktig.

For vårt app kan det være naturlig å samle hele handlelisten inne i en <section>, slik at vi kan stilsette denne med CSS senere. Da vil App.js se slik ut så langt:

// src/App.js

import './App.css';
import {hentAlleVarer} from './sanity/service'
import {useEffect, useState} from 'react'

function App() {
  const [handlelistevarer, setHandlelistevarer] = useState([])

  const samleVarer = async () => {
    const alleVarer = await hentAlleVarer();
    setHandlelistevarer(alleVarer);
  }

  useEffect(() => {
    samleVarer();
  }, [])

  console.log(handlelistevarer);

  return (
  <section>
    <h1>Handleliste</h1>
    <ul>
      <li>
        <div className="vare heading">Vare</div>
        <div className="mengde heading">Mengde</div>
      </li>

      <li>
        <div className="vare">Melk</div>
        <div className="mengde">3 Liter</div>
      </li>
      <li>
        <div className="vare">Egg</div>
        <div className="mengde">12stk</div>
      </li>
    </ul>
    </section>
  );
}

export default App;
Code language: JavaScript (javascript)

Som gjør at appen ser slik ut i nettleseren:

Nå skal vi bytte ut de hardkodede matvarene med de vi har fått fra Sanity! Vi vet at state-variabelen handlelistevarer inneholder en array med alle varene vi spurte Sanity om å hente til oss. Da må vi gå gjennom alle radene i denne arrayen, og skrive ut en liste for hver av dem. Da bruker vi metoden .map(). Denne metoden går gjennom alle elementene i arrayen, og lar oss gjøre noe med hver av dem. Vi skal ikke gjøre så mye med dem per nå annet enn å skrive dem ut i et liste-element. Se på følgende kode:

//Mappe ut handlelistevarer:
{handlelistevarer.map((vare) => (
    <li>
        <div className="vare">{vare.varenavn}</div>
        <div className="mengde">{vare.mengde}</div>
     </li>
  )
)}
Code language: JavaScript (javascript)

Her sier vi at vi skal «mappe» alle elementene i handlelistevare. For hvert element lager vi en midlertidig variabel vi kaller «vare». Denne bruker vi til å skrive ut {vare.varenavn} og {vare.mengde}, som peker på feltene vi har fått fra Sanity (sammenligne disse feltene med feltnavnene i arrayen vi skriver ut i konsollen). Rundt varenavn og mengde har vi samme HTML som vi satt opp tidligere. Det vil si at hele App.js ser slik ut nå:

// src/App.js

import './App.css';
import {hentAlleVarer} from './sanity/service'
import {useEffect, useState} from 'react'

function App() {
  const [handlelistevarer, setHandlelistevarer] = useState([])

  const samleVarer = async () => {
    const alleVarer = await hentAlleVarer();
    setHandlelistevarer(alleVarer);
  }

  useEffect(() => {
    samleVarer();
  }, [])

  console.log(handlelistevarer);

  return (
  <section>
    <h1>Handleliste</h1>
    <ul>
      <li>
        <div className="vare heading">Vare</div>
        <div className="mengde heading">Mengde</div>
      </li>
      {handlelistevarer.map((vare) => (
        <li>
          <div className="vare">{vare.varenavn}</div>
          <div className="mengde">{vare.mengde}</div>
          </li>
        )
      )}
    </ul>
    </section>
  );
}

export default App;
Code language: JavaScript (javascript)

Tøft! Nå skriver den ut både matvaren og mengden vi henter fra Sanity! Det betyr at både React og Sanity fungerer som forventet. Det neste vi skal gjøre da er å sette opp en SASS-kompilator, som gjør at vi kan skrive Sass og få noen klare fordeler ved produksjon av CSS i prosjektet vårt!

Steg 6: Sett opp CSS/SASS i prosjektet

Det første vi gjør for å forberede CSS-opplegget vårt er å gjøre klar en mappe under /src vi kaller css. Her skal vi samle sass-filene våre og gjøre klar hoved-filen vi skal kompilere til css. For å gjøre klar mappe- og filstrukturen gjør vi tre steg:

  1. I filutforskeren i VSCode, finn src-mappa under rss_boilerplate-mappa (det er viktig å fortsatt holde seg i React-prosjektet, så appen vår enkelt får tak i CSS-en). Lag en mappe kalt css.
  2. Inne i den nye css-mappen, lag en ny mappe kalt sass.
  3. I sass-mappen, lag en fil som kalles main.scss. Denne filen blir hoved-filen vår i sass-prosjektet

Da har vi en mappestruktur som ser slik ut:

Neste steg er å installere noen npm-pakker med ulik funksjonalitet. Til sammen bruker vi fem pakker for å lage et kraftig SASS-verktøy:

  • sass: pakken som tolker sass-syntaxen vi skriver i filene våre, og kompilerer sass til CSS.
  • autoprefixer: pakke som sørger for at alle CSS-egenskaper som trenger browser-spesifikke prefixer (eksempel: border-radius får automatisk også -webkit-border-radius og -moz-border-radius i den ferdige CSS-filen, selv om vi bare skriver border-radius, som sørger for at CSS-filen passer flest mulig nettlesere)
  • postcss-cli: Lar oss utføre funksjoner på CSS-filen. Brukes for å fortelle autoprefixer hvilken CSS-fil den skal autoprefixe.
  • css-minify: Minifiserer CSS-filen (fjerner alle unødvendige mellomrom, whitespaces og linjeskift) slik at filstørrelsen blir minst mulig
  • npm-run-all: Samlepakke som lar oss sette sammen og kjøre flere kommandoer i en sekvens. I verktøyet vi lager nå må vi ha en fast sekvens på ting (kompiler sass > autoprefix CSS-egenskaper > Minifiser CSS > Spytt CSS-filen ut til css-mappa), derfor må vi kjøre flere kommandoer når vi skal ha den ferdige CSS-filen klar.

Neste steg er å installere disse pakkene. Hvis prosjektet vårt kjører allerede, og vi ikke vil stoppe kjøringen, kan vi åpne et nytt terminalvindu ved å klikke på plusstegnet i verktøylinjen ved terminalen:

Når vi har åpnet en ny terminal, åpner denne rot-mappa til prosjektet vårt (RSS_boilerplate). Her ønsker vi IKKE å kjøre noe npm-kode, siden vi har egne mapper for React- og Sanity-prosjektene våre som holder kontroll på de nødvendige npm-tingene.

Gå først inn i mappen rss_boilerplate, som inneholder React-prosjektet, ved å kjøre følgende kommando:

cd rss_boilerplate

Deretter installerer vi alle pakkene. Vi inkluderer et såkalt flagg, –save-dev, for å legge til disse pakkene under avhengigheter i package.json, som gjør at disse pakkene automatisk blir hentet ned og installert hvis man installerer og kjører dette prosjektet på en annen PC:

npm install sass concat autoprefixer postcss-cli css-minify npm-run-all --save-dev

Med alle pakkene installert, åpner vi package.json-filen som ligger i rss_boilerplate-mappen. Her skal vi nå skrive noen «scripts»: konfigurerte kommandoer som prosjektet vårt kan kjøre for å bygge SASS-en vi skriver om til en CSS-fil.

I package.json ligger det allerede noen scripts. Disse kommer fra React, og brukes for å bygge og kjøre React-prosjektet vårt. Husker du av vi skriver npm start for å kjøre i gang React-prosjektet og se webapplikasjonen vår i en nettleser? Dette skjer fordi «start» er definert som et script i package.json:

Som vi ser er scripts lagt opp som en liste med objecter. Vi må for å legge til det første scriptet for CSS-verktøyet vårt skrive et komma bakerst på setningen for «eject»-scriptet, og trykke enter-tasten for å legge til et nytt script. Det første scriptet vi skal lage er en såkalt «watch»: vi ser konstant etter («watcher») endringer i sass-mappa, og kompilerer opp CSS-en på nytt for hver endring. Dette er nyttig dersom vi en periode skal jobbe mye med CSS-en, da kan vi kjøre watch-scriptet slik at vi slipper å manuelt bygge CSS-en for hver gang vi gjør en liten endring.

OBS: Det finnes flere watch-prosesser for andre ting enn CSS. Eksempelvis gjør React det samme – den følger med på endringer i prosjektet vårt, og bygger og laster webapplikasjonen i nettleseren på nytt når vi lagrer endringer. Det kan derfor være lurt å navngi script noe som gjør dem gjenkjennelig i forhold til hva vi skal kjøre. En måte å gjøre dette på, er å gi dem et felles «kodeord». I SASS-verktøyet vårt kan css være et gjenkjennelig ord for alle scriptene våre. Hvis vi skiller kodeordet og scriptnavnet med kolon, vil det første scriptet vårt hete css:watch. Da får vi følgende script vi kan legge i package.json:

"css:watch": "sass --watch src/css/sass/main.scss:src/css/main.css"Code language: JavaScript (javascript)

I denne koden sier vi at «når vi kjører css:watch i terminalen, skal du kjøre scriptet som bruker sass-pakken for å starte en –watch på filen src/css/sass/main.scss som kompilerer css til src/css/main.css-filen». Ganske rett fram!

Det neste scriptet er nesten likt. Det er ikke alltid vi ønsker at prosessen som watcher css-mappen skal kjøre, men vi vil fortsatt ha muligheten til å kjapt lage en kompilert css hvis vi har gjort en rask endring i sass-filene våre. Vi lager scriptet css:compile for å ha en manuell mulighet til å kompilere sassen vår:

"css:compile": "sass src/css/sass/main.scss:src/css/main.css"Code language: JavaScript (javascript)

Det eneste vi har gjort er å ta bort flagget –watch, slik at scriptet utføres en gang, og ikke begynner å følge med på sass-filene.

Neste script er å autoprefixe CSS-egenskapene våre. Her bruker vi to pakker sammen: postcss-cli for å kjøre en modifikasjon av css-filer, og autoprefixer som inneholder koden som behøves for å legge til browser-spesifikke prefixer på de egenskapene som krever det. Vi kaller dette scriptet css:prefix:

"css:prefix": "postcss --use autoprefixer -b \"last 4 versions\" src/css/main.css -o src/css/main.css"Code language: JavaScript (javascript)

Dette scriptet er litt mer komplekst. Vi bruker flagget –use for å fortelle postcss at den skal bruke funksjonaliteten i autoprefixer, og flagget -b for å gi en «browserlist», som forteller hvilke nettlesere vi skal inkludere prefixing for. Deretter forteller vi hvilken fil dette skal kjøres på (src/css/main.css), og hvilken fil som skal outputtes (i vårt prosjekt er det den samme css-filen, siden vi ikke har behov for en fil uten og en fil med prefixer).

Det neste scriptet skal komprimere CSS-filen, altså fjerne unødvendige kommentarer, mellomrom, linjeskift og så videre. Dette kaller vi css:compress:

"css:compress": "css-minify -f src/css/main.css -o css"Code language: JavaScript (javascript)

Dette er et relativt enkelt script igjen; vi bruker css-minify-pakken med flagget -f (forkortelse for -filename) for å fortelle hvilken fil som skal minifiseres, og flagget -o (forkortelse for output) for å fortelle hvilken mappe vi ønsker å plassere den ferdig minifiserte css-filen i.

Nå har vi script for alle stegene klare! Da mangler vi bare et script som gjør alle tingene for oss, slik at vi kan kjøre det scriptet når vi vil ha en helt ferdig CSS-fil vi kan bruke i prosjektet vårt. dette kaller vi css:build:

"css:build": "npm-run-all css:compile css:prefix css:compress"Code language: CSS (css)

Dette scriptet er veldig enkelt; vi bruker pakken npm-run-all for å fortelle at vi ønsker å kjøre en sekvens med andre scripts: de vi allerede har laget for ulike deler av SASS-verktøyet vårt. Kult! Nå ser package.jsons script-seksjon slik ut:

De to scriptene vi kommer til å bruke mest er css:watch, som brukes når vi skal jobbe konsentrert med større css-jobbing, og css:build, som brukes når vi skal kjøre ut den endelige CSS-filen.

PS: Husk å lagre package.json nå 😉

La oss teste om dette funker! Siden vi har main.scss-filen klar i sass-mappa vår, la oss legge inn en Google Font vi vil bruke i handlelisten vår og prøve å kompilere CSS-en! Gå til Google Fonts og finn en font du vil bruke. Klikk deg inn på fonten, velg de fontstilene du ønsker tilgjengelig i prosjektet ved å klikke «+ Select this style» til høyre for visningen av fonten, og finn seksjonen «use on the web» i høyrekolonnen (denne tutorialen bruker Poppins med vektene 300 og 600).

I «use on the web»-seksjonen, velg @import, og kopier @import-setningen som står mellom <style> og </style> i eksempelet som blir vist:

<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;600&display=swap');
</style>
Code language: HTML, XML (xml)

Nå, i VSCode, gå til main.scss-filen vi opprettet for litt siden. Lim denne inn i toppen av main.scss. Nå har vi importert fonten, og kan bruke den i CSS-en vår.

La oss legge til denne fonten som en font-familie i body og html med vekten 300, og overstyre heading-tager med samme font, men vekten 600:

html, body {
    font-family: 'Poppins', sans-serif;
    font-weight: 300;
}

h1, h2, h3 {
    font-weight: 600;
}
Code language: CSS (css)

Da ser hele main.scss slik ut:

//main.scss - the mother of our sass
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;600&display=swap');

html, body {
    font-family: 'Poppins', sans-serif;
    font-weight: 300;
}

h1, h2, h3 {
    font-weight: 600;
}
Code language: CSS (css)

Nå har vi litt sass vi kan prøve å kjøre scriptene våre på! Da går vi tilbake til terminalen i VSCode, og siden vi samler og kjører alle scriptene i css:build, er det dette vi prøver å kjøre for å kunne få tilbakemelding dersom et av scriptene feiler. I terminalen, skriv:

npm run css:buildCode language: CSS (css)

Nå kan vi se i terminalen at scriptene kjører i sekvensen vi satt dem opp i css:build-scriptet, og når de er ferdig kjørt finner vi en fil kalt main.css i css-mappa vår!

Lovende! Neste steg nå: Få webapplikasjonen til å bruke vår CSS! For å få til det må vi tilbake til App.js-filen. I toppen av denne ligger det en import-setning som henter App.css, filen som kommer med som standard fra create-react-app-pakken. Denne skal vi ikke bruke lenger, så vi gjør om referansen til ./css/main.css:

// src/App.js

import './css/main.css';
import {hentAlleVarer} from './sanity/service'
import {useEffect, useState} from 'react'

//resten av App.js-koden ligger under her...
Code language: JavaScript (javascript)

Hvis React-prosjektet vårt fortsatt kjører, vil webapplikasjonen vår lastes på nytt når vi lagrer App.js. Da skal vi forhåpentligvis ha en annen font på matvarene og overskriften:

Bra! Da fungerer CSS-importen også.

La oss se hvordan vi kan utnytte det nye sass-verktøyet vårt skikkelig. I VSCode, lag en mappe kalt «handleliste» inni sass-mappa. I mappen handeliste, lag en partial sass-fil kalt «_struktur.scss».

Da får vi følgende mappestruktur per nå:

Hva er en partial?

En partial er en sass-fil som inneholder deler av CSSen vi skriver. Disse brukes for å dele opp CSSen i mer oversiktlige biter, så vi ikke har et stort og langt CSS-dokument på mange 100 linjer vi må lete gjennom hver gang vi skal endre. Partials kan ikke bli egne CSS-filer, men må inkluderes i en egen scss-fil (vår main.scss)

Les mer om sass, import og partials hos W3Schools

I denne filen legger vi noen CSS-regler for å flytte hele handlelisten vår vekk fra ytterkanten av nettleseren:

//_struktur.scss

section {
    margin: 2rem auto;
    background: white;
    padding: 1rem;
    border: 1px solid #ccc;
    max-width: 25rem;
}
Code language: CSS (css)

Nå skal vi straks importere _struktur.scss inn i main.css for å inkludere den i den ferdige CSS-filen vår. Men siden vi nå skal jobbe litt med CSS, er det greit å la prosjektet vårt oppdatere CSSen for oss. Gå til terminalen, og sett i gang watch-scriptet vi laget for CSS med følgende kommando:

npm run css:watchCode language: CSS (css)

Nå vil alle endringer og importer vi gjør i sass-filene automatisk oppdateres og sendes til main.css, slik at alle endringene blir synlige på webapplikasjonen vår uten at vi trenger å gjøre noe manuelt.

Det neste steget blir å importere _struktur.scss inn i main.scss. Dette gjør vi ved å legge til følgende linje kode i bunnen av main.scss:

@import 'handleliste/struktur'Code language: JavaScript (javascript)

Da har vi fortalt main.scss at den også skal inkludere CSS-reglene vi har laget i _struktur.scss når den kompilerer. Når vi lagrer main.scss nå, vil css:watch-scriptet vårt kompilere CSS-en, og webapplikasjonen oppdateres:

Kult. La oss lage en partial til i handelistemappa, kalt «_vareliste.scss».

OBS: Importer den i main.scss på samme måte som med _struktur.scss, rett under importen av _struktur.scss.

I _vareliste.scss legger vi noen CSS-regler for å få på plass tabell-utseendet på listen vår:

//_vareliste.scss

ul {
    list-style-type: none;
    margin: 0;
    padding: 0;

    li {
        width: 100%;
        display: flex;

        flex-direction: row;
        &:nth-child(odd) { background-color: #eee;}
        &:nth-child(1) { background-color: #7c147c; color: #fff; }
    }
}
Code language: CSS (css)

Her ser vi noen flere fordeler med SASS: nesta css. Vi kan skrive CSS-regler for elementer som ligger inni elementer, og dermed sørge for at CSS-reglene bare gjelder for elementer som følger samme struktur. I tillegg kan vi knytte på pseudoklasser internt i elementet (eksempel: &:nth-child(), som vi i vanlig CSS måtte skilt med to setninger, en for li og en for li:nth-child() ).

Koden over fjerner listepunktet og marger fra selve listen, mens listeelementer inne i listen blir satt til full bredde og bruker CSS Flex for å plassere elementene inni listeelementet. I tillegg vil hvert listeelement som er et oddetall få en lysgrå bakgrunnsfarge, med mindre det er det første listeelementet, som vil få lilla bakgrunnsfarge og hvit tekst (siden dette er listen som inneholder det vi tenker oss er tabell-headerne).

Hvis du har lagret, vil CSS-en allerede være kompilert og du ser endringene i nettleseren. La oss legge til litt mer CSS inne i li-elementet for å få tabellradene fine:

div {
  box-sizing: border-box;
  padding: .5rem;

  &.vare {
    flex-grow: 2;
  }
  &.mengde {
    flex-grow: 1;
    text-align: right;
    font-size: .8rem;
  }
  &.heading {
    font-weight: 600;
  }
}
Code language: CSS (css)

Her sier vi at alle div-elementene inne i li-elementene skal ha box-sizing: border-box (dette er en av CSS-egenskapene som autoprefixer lager de resterende browserspesifikke reglene for) og 0.5rem padding. I tillegg, hvis div-en har klassen .vare, skal den oppta større plass i flex-strukturen enn .mengde. .mengde har i tillegg litt mindre tekst, justert mot høyre. Til sist har klassen .heading fått litt tykkere tekst.

Nå ser hele _vareliste.scss slik ut:

//_vareliste.scss

ul {
    list-style-type: none;
    margin: 0;
    padding: 0;

    li {
        width: 100%;
        display:flex;
        flex-direction: row;
        &:nth-child(odd) { background-color: #eee;}
        &:nth-child(1) { background-color: #7c147c; color: #fff; }

        div {
            box-sizing: border-box;
            padding: .5rem;

            &.vare {
                flex-grow: 2;
            }
            &.mengde {
               flex-grow: 1;
               text-align: right;
               font-size: .8rem;
            }
            &.heading {
                font-weight: 600;
            }
        }
    }
}
Code language: CSS (css)

Og vi har en handleliste som ser slik ut:

Det betyr at vi nå har et ferdig oppsatt React-prosjekt og Sanity-prosjekt, hvor React og Sanity snakker sammen, og vi kan bruke Sass for å lage CSS og stilsette webapplikasjonen vår! Målet er nådd!

Dette var veldig grunnleggende, og minimum av hva vi trenger for å kjøre i gang et prosjekt. Nå er det på tide å lære litt mer React og Sanity for å kunne lage enda mer funksjonalitet. Det kan du gjøre ved å sjekke ut React og Sanitys nettsider, eller følge tutorialen «Tutorial: Gruppere innhold fra Sanity basert på innholdstypen Kategori (handleliste, nivå 2)» [kommer snart] som et naturlig neste steg!

Lykke til!

PS: Hele handleliste-koden er tilgjengelig i dette Github-repoet. Dersom du kloner/forker dette, må du bytte ut projectId i rss_boilerplate/src/sanity/client.js til din egen prosjektId for å få det til å snurre.

Stikkord:

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *