Att bygga en Full Stack Serverlösa Ansökan med Cloudflare Arbetstagare

0
23

En av mina favorit utveckling i utveckling av programvara har varit tillkomsten av serverlösa. Som en utvecklare som har en tendens att fastna i detaljer för distribution och DevOps, det är uppfriskande att ges ett läge av att bygga webb-applikationer som helt enkelt abstracts skalning och infrastruktur bort från mig. Serverlösa har gjort mig bättre på att faktiskt frakt projekt!

Som sagt, om du är ny till serverlösa, det kan vara oklart hur man översätter saker som du redan känner till ett nytt paradigm. Om du är en front-end utvecklare, du kanske inte har någon erfarenhet av vad serverlösa utger sig för att abstrakt bort från dig – så hur kan du ens komma igång?

Idag ska jag försöka hjälpa till att avmystifiera den praktiska delen av att arbeta med serverlösa genom att ta ett projekt från idé till produktion, med Cloudflare Arbetstagare. Vårt projekt kommer att vara en daglig leaderboard, som kallas “Repo Jaga” inspirerad av webbplatser som Produkt Jaga och Reddit, där användarna kan skicka in och upvote cool open-source-projekt från GitHub och GitLab. Du kan se den slutliga versionen av webbplatsen, som publiceras här.

Arbetstagare är en serverlösa ansökan plattform byggd på toppen av Cloudflare nätverk. När du publicerar ett projekt för att Cloudflare Arbetstagare, det är direkt fördelade över 180 (och växande) städer runt om i världen, vilket innebär att oavsett var användarna befinner sig, dina anställda ansökan kommer att serveras från en närliggande Cloudflare server med extremt låg fördröjning. På toppen av det, Arbetstagare laget har gått all-in på utvecklarens erfarenhet: våra nyaste versionen, i början av denna månad, som infördes en fullt utrustad kommandoraden verktyg som kallas Wrangler, som förvaltar byggnaden, ladda upp och publicera din serverlösa program med ett par enkla att lära sig och kraftfulla kommandon.

Slutresultatet är en plattform som gör att du enkelt skriva JavaScript och distribuera den till en URL – inga mer oroande om vad “Hamnarbetare” innebär, eller om din ansökan kommer att falla över när det gör det till den främre sidan av Hacker News!

Om du är typen som vill se projektet i förväg, innan du hoppar in i en lång tutorial, du har tur! Källan för detta projekt är tillgänglig på GitHub. Låt oss hoppa in till kommandoraden och bygga något i rad.

Installera Wrangler och förbereda vår arbetsyta

Wrangler är kommandoraden verktyg för att skapa, bygga och publicera Cloudflare Arbetstagare projekt. Vi har gjort det super lätt att installera, särskilt om du har arbetat med npm innan:

npm install-g @cloudflare/wrangler

När du har installerat Wrangler, kan du använda kommandot generera för att göra ett nytt projekt. Wrangler projekt använder sig av “mallar” vilken är koden förråd byggt för vidareutnyttjande av utvecklare att bygga med Arbetstagare. Vi har en växande lista av mallar för att hjälpa dig att bygga alla typer av projekt inom Arbetstagare: kolla in vår Mall Galleri för att komma igång!

I den här guiden kommer vi att använda “Router” – mall, som gör att du kan bygga URL-baserade projekt på toppen av Arbetstagare. Skapa kommando tar två argument: för det första, namnet på ditt projekt (som jag kommer att använda repo-hunt), och en Git-URL. Detta är min favorit del av att generera kommando: du kan använda alla typer av mallar genom att peka Wrangler på GitHub URL, så dela, gaffel, och samarbetar på mallar är super enkelt. Låt oss köra kommandot generera nu:

wrangler generera repo-jakten https://github.com/cloudflare/worker-template-router
cd-repo-jakten

Routern mallen innehåller stöd för att bygga projekt med webpack, så att du kan lägga till npm-moduler till ditt projekt, och använda alla JavaScript-verktyg som du vet och älskar. Dessutom, som du kanske tror, mallen innehåller en Router klass, vilket gör att du kan hantera rutter i din Arbetstagare, och binda dem till en funktion. Låt oss titta på ett enkelt exempel: att sätta upp en instans av Routern, hantering av en begäran om att FÅ / och skicka tillbaka ett svar till klienten:

// index.js
const Routern = require(‘./router’)

addEventListener (“hämta”, event => {
händelsen.respondWith(handleRequest(händelse.begäran))
})

asynkron funktion handleRequest(begäran) {
try {
const r = ny Router()
r.get(‘/’, () => nya Svar(“Hello, world!”))
const resp = väntar r.route(på begäran)
avkastning resp
} catch (err) {
återgå nya Svar(err)
}
}

Alla Arbetstagare program börja med att lyssna till och hämta händelse, som är en förfrågan från en klient till din ansökan. Inne i den händelse lyssnare, det är vanligt att kalla en handleRequest funktion, som ser på inkommande begäran och bestämmer hur de ska svara. När hantering av inkommande hämta händelse, vilket indikerar ett inkommande begäran, en Arbetstagare skriptet ska alltid returnera ett Svar tillbaka till användaren: det är en liknande begäran/svar-mönster att många webben ramar, som Express, så om du har arbetat med webb ramar innan, det ska kännas ganska bekant!

I vårt exempel kommer vi att få användning av några vägar: en “root” – rutt (/), som kommer att göra hemsidan på vår hemsida, ett formulär för att lämna in nya repor, vid /efter, och en speciell rutt för att ta emot POST önskemål, när en användare skickar ett repo från den form, i /repo.

Att bygga en väg och gör en mall

Den första vägen som vi ska ställa upp är “root” – väg, på väg /. Detta kommer att vara där repor lämnats av gemenskapen kommer att bli. För nu, låt oss få lite träning definiera en rutt, och återvänder vanlig HTML. Detta mönster är tillräckligt vanligt för Arbetstagare i program som det är vettigt att förstå det först, innan vi gå vidare till lite mer intressanta bitarna!

Till att börja, vi kommer att uppdatera index.js att ställa upp en instans av en Router hanterar någon begär att FÅ / och anropa funktionen index, från handlers/index.js (mer om det inom kort):

// index.js
const Routern = require(‘./router’)
const index = require(‘./handlers/index’)

addEventListener (“hämta”, event => {
händelsen.respondWith(handleRequest(händelse.begäran))
})

funktion handleRequest(begäran) {
try {
const r = ny Router()
r.get(‘/’, index)
avkastning r.route(på begäran)
} catch (err) {
återgå nya Svar(err)
}
}

Som med exempel index.js i föregående avsnitt, vår kod lyssnar för att hämta en händelse, och reagerar genom att ringa handleRequest funktion. Den handleRequest funktion inrättas en instans av Routern, som kommer att kräva index-funktionen på några FÅ förfrågningar till /. Med router setup, vi dirigera inkommande begäran, med hjälp av r.väg, och lämna tillbaka det som svar till klienten. Om något går fel, vi har helt enkelt svepa innehållet av funktionen i ett try/catch-block, och återgå err till klienten (en kommentar här: i produktionen program, du kanske vill ha något mer robust här, som att logga in på ett undantag övervakning verktyg).

Att fortsätta sätta upp vår rutt handler, ska vi skapa en ny fil, handlers/index.js som kommer att ta inkommande begäran och returnera en HTML-svar till klienten:

// handlers/index.js
const rubriker = { ‘Content-Type: text/html”}
const hanterare = () => {
återgå nya Svar(“Hello, world!”, { rubriker })
}
modulen.exporten = handler

Vår handler funktionen är enkel: den returnerar en ny instans av Svar med texten “Hello, world!” samt en rubriker objekt som anger Content-Type text/html – detta talar om för webbläsaren att göra den inkommande svar som ett HTML-dokument. Detta innebär att när en kund gör en GET-förfrågan till väg /, en ny HTML-svar kommer att byggas med texten “Hello, world!” och returneras till användaren.

Wrangler har en preview-funktion, perfekt för att testa HTML-utdata av vår nya funktion. Låt oss köra den nu och se till att våra program fungerar som förväntat:

wrangler förhandsgranska

Förhandsvisning kommandot ska öppna upp en ny flik i din webbläsare, efter att bygga din Arbetstagare ansökan och ladda upp den till våra tester lekplats. I fliken Förhandsgranska, bör du se din renderade HTML-svar:

Med vår HTML-svar visas i webbläsaren, låt oss göra vår handler-funktionen lite mer spännande genom att återvända vissa snygg HTML. För att göra detta, ska vi ställa upp ett motsvarande index “mall” för vår rutt handler: när en begäran kommer in i index handler, det kommer att ringa mall och returnera en HTML-sträng, för att ge klienten en korrekt användar-gränssnitt som svar. För att starta, låt oss uppdatera handlers/index.js för att returnera ett svar med hjälp av vår mall (och, dessutom, ställ upp en try/catch-block för att fånga eventuella fel och returnerar dem som svar):

// handlers/index.js
const rubriker = { ‘Content-Type: text/html”}
const template = require(‘../templates/index’)

const hanterare = asynkron () => {
try {
återgå nya Svar(mall(), { rubriker })
} catch (err) {
återgå nya Svar(err)
}
}

modulen.exporten = handler

Som ni kanske förstår så behöver vi sätta upp en motsvarande mall! Vi ska skapa en ny fil, templates/index.js och returnera en HTML-sträng med hjälp av ES6 mall strängar:

// templates/index.js
const template = () => {
återgå <code><h1>Hej världen!</h1>`
}

modulen.exporten = mallen

Vår mall-funktionen returnerar en enkel HTML-sträng, som är satt till kroppen för våra insatser, i handlers/index.js. För vår sista snutten av mallar för vår första sträckan, låt oss göra något lite mer intressant: att skapa en templates/layout.js fil, som kommer att vara basen “layout” för att alla våra mallar kommer att göra i. Detta kommer att tillåta oss att ställa några konsekventa styling och formatering för alla mallar. I templates/layout.js:

// templates/layout.js
const layout = organet => `
<!doctype html>
<html>
<head>
<meta charset=”UTF-8″>
<title>Repo Jakt</title>
<meta name=”viewport” content=”width=device-width, initial-scale=1″>
<link rel=”stylesheet” href=”https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css”>
</head>
<body>
<div class=”container”>
<div class=”navbar”>
<div class=”navbar-brand”>
Reporäntan Jaga
Hitta coola projekt med öppen källkod dagligen
</div>
<div class=”navbar-meny”>
<div class=”navbar-end”>
<div class=”navbar-post”>
Efter ett arkiv
</div>
</div>
</div>
</div>
<div class=”section”>
${kropp}
</div>
</div>
</body>
</html>
`
modulen.exporten = layout

Detta är en stor bit av HTML-kod, men att bryta ner det, det är bara några viktiga saker att notera: för det första, denna layout variabel är en funktion! En kropp med variabel är passerade, som är avsedda att ingå i en div rätt i mitten av HTML-snutt. Dessutom inkluderar vi Bulmahttps://bulma.io) CSS frameworkhttps://bulma.io), för lite för lätt styling i vårt projekt, och en navigation bar, för att berätta för användarna *vad* denna webbplats är, med en länk för att skicka in nya förråd.

Att använda vår mall, vi ska importera den i templates/index.js och linda våra HTML-sträng med det:

// templates/index.js
const layout = require(‘./layout”)

const template = () => {
tillbaka layout(`<h1>Hej världen!</h1>`)
}

modulen.exporten = mallen

Med den kan vi köra wrangler förhandsgranska igen för att se våra fint renderade HTML-sida, med lite styling hjälp från Bulma:

Lagra och hämta data med Arbetstagare KV

De flesta web-program är inte mycket användbara utan någon form av data persistens. Arbetstagare KV är en nyckel-värde-butik byggd för användning med Arbetstagare – tänk på det som en super-snabbt och globalt distribuerade Åt. I vår ansökan, vi kommer att använda KV för att lagra alla uppgifter om våra program: varje gång en användare skickar ett nytt arkiv, det kommer att lagras i KV, och vi kommer också att generera en daglig mängd arkiv att göra på hemsidan.

En snabb anteckning: i skrivande stund, användning av Arbetstagare KV kräver en avlönad Arbetstagare plan. Läs mer under “Priser” avsnitt av Arbetstagare dokument här.

Insidan av en Arbetstagare ansökan, kan du hänvisa till en fördefinierad KV namespace, som vi kommer att skapa insidan av Cloudflare UI, och binder till vår ansökan när den har sänts ut till de Arbetstagare ansökan. I den här guiden kommer vi att använda en KV namespace som heter REPO_HUNT, och som en del av utbyggnaden, vi ska se till att bifoga det till vår ansökan, så att alla hänvisningar i koden för att REPO_HUNT kommer att korrekt lösa till KV-namnområdet.

Innan vi hoppar in i att skapa data på insidan av våra namespace, låt oss titta på grunderna av att arbeta med KV insidan av din Arbetstagare ansökan. Med tanke på ett namnområde (t ex REPO_HUNT), kan vi ange en nyckel med ett visst värde, med hjälp sätta:

const string = “Hello, world!”
REPO_HUNT.put(“myString” string)

Vi kan också hämta värdet för nyckeln, med hjälp av asynkron/väntar och väntar på att de lovar att lösa:

const getString = asynkron () => {
const string = väntar REPO_HUNT.få(“myString”)
konsolen.log(sträng) // “Hello, world!”
}

API är super enkelt, vilket är bra för webbutvecklare som vill börja bygga applikationer med Arbetstagare plattform, utan att behöva dyka in i relationsdatabaser eller någon form av extern data service. I vårt fall, vi ska lagra uppgifterna för vår ansökan genom att spara:

  1. En repo objekt som lagras på nyckeln repor:$id, där $id är ett genereras UUID för en nyligen lämnades reporäntan.
  2. En dag array, som lagras på key $datum (t.ex. “6/24/2019”), som innehåller en förteckning av repo-Id, som visar fram repor för den dagen.

Vi kommer att börja med att implementera stöd för att lämna förråd och gör vår första skriver att våra KV namnområdet genom att spara arkivet data i objektet vi som anges ovan. Längs vägen kommer vi att skapa en enkel JavaScript-klass för samverkan med vår butik – vi kommer att göra bruk av den klassen igen, när vi rör på att göra en hemsida, där vi ska hämta arkivet data, bygga ett gränssnitt, och avsluta vårt exempel ansökan.

Så användarinmatad data

Oavsett vad som står i ansökan är, det verkar som webbutvecklare alltid sluta med att skriva former. I vårt fall kommer vi att bygga en enkel form för användare att lämna in förråden.

I början av denna handledning, satte vi upp index.js för att hantera inkommande FÅ förfrågningar till roten rutt (`/). För att stödja användare att lägga till nya förråden, vi kommer att lägga till en annan rutt, GET /post, som kommer att göra en formulärmall till användare. I index.js:

// index.js

// …

const post = require(‘./handlers/post”)

// …

funktion handleRequest(begäran) {
try {
const r = ny Router()
r.get(‘/’, index)
r.get (‘/- post, post)
avkastning r.route(på begäran)
} catch (err) {
återgå nya Svar(err)
}
}

Förutom en ny rutt handler i index.js vi kommer även att lägga till handlers/post.js en ny funktion-hanterare som kommer att göra en tillhörande mall som en HTML-svar till användaren:

// handlers/post.js
const rubriker = { ‘Content-Type: text/html”}
const template = require(‘../templates/post”)

const handler = request => {
try {
återgå nya Svar(mall(), { rubriker })
} catch (err) {
återgå nya Svar(err)
}
}

modulen.exporten = handler

Den sista pusselbiten är en HTML-mall i sig – precis som vår tidigare mall exempel kommer vi att åter använda den mall som vi har byggt upp, och linda en enkel tre-fältet form med det, exportera HTML-sträng från templates/post.js:

// templates/post.js
const layout = require(‘./layout”)

const template = () =>
layout(`
<div>
<h1> – lägga till ett nytt repo</h1>
<form action=”/repo” method=”post”>
<div class=”field”>
<etiketten class=”label” för=”namn”>Namn</label>
<input class=”ingång” id=”namn” name=”namn” type=”text” platshållare=”Namn” som krävs></input>
</div>
<div class=”field”>
<etiketten class=”label” för=”description”>Beskrivning</label>
<input class=”ingång” id=”description” name=”description” type=”text” platshållare=”Description”></input>
</div>
<div class=”field”>
<etiketten class=”label” för=”url”>URL</label>
<input class=”ingång” id=”url” name=”adress” type=”text” platshållare=”URL” som krävs></input>
</div>
<div class=”field”>
<div class=”control”>
<knappen class=”knappen-link” type=”submit”>Skicka</button>
</div>
</div>
</form>
</div>
<kod>)

modulen.exporten = mallen

Med hjälp av wrangler förhandsgranska, vi kan navigera till sökvägen /inlägg och se våra utförda form:

Om du tittar på definitionen av den faktiska form-taggen i vår mall, kommer du att märka att vi gör en POST-begäran till sökvägen /repo. För att ta emot data, och fortsätter det i vår KV butik, vi kommer att gå igenom processen av att lägga till en annan handler. I index.js:

// index.js

// …

const skapar = require(‘./handlers/skapa’)

// …

funktion handleRequest(begäran) {
try {
const r = ny Router()
r.get(‘/’, index)
r.get (‘/- post, post)
r.inlägg(‘/repo’, skapa)
avkastning r.route(på begäran)
} catch (err) {
återgå nya Svar(err)
}
}

När ett formulär skickas till en slutpunkt, det skickas som en frågesträng. För att göra våra liv enklare, vi kommer att innehålla qs bibliotek i vårt projekt, som kommer att tillåta oss att helt enkelt tolka inkommande frågesträng som en JS-objekt. I kommandoraden, så lägger vi till qs helt enkelt genom att använda npm. Medan vi är här, låt oss även att installera node-uuid-paketet, som vi kommer att använda senare för att generera Id för nya inkommande data. För att installera dem båda, använd npm: s installera –spara underkommandot:

npm install –spara qs uuid

Med den kan vi genomföra motsvarande handler funktion för POST /repo. I handlers/create.js:

// handlers/create.js
const qs = require(‘här’)

const hanterare = asynkron begäran => {
try {
const kroppen = väntar på begäran.text()

if (!kroppen) {
kasta nytt Fel (“Felaktig data”)
}

const data = qs.parse(kroppen)

// TODOs:
/ / Skapa reporäntan
// – Spara reporäntan
/ / Lägg till dagens repor på hemsidan

återgå nya Svar(‘ok’, { rubriker: { Location: ‘/’ }, status: 301 })
} catch (err) {
återgå nya Svar(err, { status: 400 })
}
}

modulen.exporten = handler

Vår handler funktion är ganska enkelt — det kräver text på begäran), som väntar på löften om att lösa för att få tillbaka våra query string kroppen. Om ingen body-element är försedd med begäran, föraren kastar ett fel (som returnerar en statuskod på 400 tack vare vårt try/catch-block). Med tanke på en giltig kroppen, vi kallar tolka på importerade qs-paketet, och att få vissa data tillbaka. För nu har vi stubbed ut våra avsikter för återstoden av denna kod: för det första, vi kommer skapa en repo, baserad på data. Vi kommer att spara mycket som reporäntan, och sedan lägga till den uppsjö av dagens repor, ska återges på hemsidan.

Att skriva vårt repo data i KV, kommer vi att bygga två enkla ES6 klasser, för att göra lite ljus validering och definiera några uthållighet metoder för våra data typer. Medan du bara kunde ringa REPO_HUNT.sätta direkt, om du arbetar med stora mängder av liknande uppgifter, det kan vara trevligt att göra något som nya Reporäntan(data).spara() – i själva verket, kommer vi genomföra något nästan exakt som denna, så att arbeta med en Repa är otroligt enkel och konsekvent.

Låt oss definiera store/repo.js som kommer innehålla ett Repo klass. Med denna klass kan vi initiera nya Reporäntan objekt och använda konstruktorn, och vi kan passera i data, och bekräfta den, innan du fortsätter använda det i vår kod.

// store/repo.js
const uuid = require(‘uuid/v4’)

klass Repo {
konstruktör({ id, beskrivning, namn, submitted_at, url }) {
detta.id = id || uuid()
detta.beskrivning = beskrivning

if (!namn) {
kasta nytt Error(`Saknas namn på data”)
} else {
detta.namn = namn
}

detta.submitted_at = submitted_at || Antalet(new Date())

try {
const urlObj = nya URL: en(webbadressen)
const vitlista = [‘github.com’, ‘gitlab.com’]

if (!vitlista.vissa(giltigt => giltiga === urlObj.värd)) {
kasta nytt Error(‘URL, som tillhandahålls är inte en förvaringsplats’)
}
} catch (err) {
kasta nytt Error(‘URL, som tillhandahålls är inte giltigt”)
}

detta.url = url
}

spara() {
tillbaka REPO_HUNT.put (“repoavtal:${detta.id}`, JSON.stringify(denna))
}
}

modulen.exporten = Repo

Även om du inte är super bekant med konstruktören funktion i en ES6 klass, är detta exempel bör fortfarande vara ganska lätt att förstå. När vi vill skapa en ny instans av en Repo, vi vidarebefordra relevanta uppgifter till konstruktören som ett objekt, med hjälp av ES6 s omstrukturering av valutan uppdraget att dra varje värde ut i sin egen nyckel. Med dessa variabler, vi går igenom var och en av dem, tilldela detta.$nyckel (t ex den här.namn, detta.beskrivning, etc) för att de fallit i värde.

Många av dessa värden har en “standard” – värde: till exempel, om ingen ID skickas till konstruktören, vi kommer skapa en ny, med hjälp av våra tidigare sparade uuid paket v4 variant för att generera en ny UUID, med uuid(). För submitted_at, vi kommer skapa en ny instans av Datum och konvertera det till en Unix-tidsstämpel, och för url, vi försäkra att URL: en är båda giltiga *och* är från github.com eller gitlab.com för att säkerställa att användare skickar in äkta repor.

Med att spara-funktion, som kan kallas en instans av Reporäntan, skär en JSON-sträng version av Reporäntan exempel i KV, inställning av knapp som repor:$id. Tillbaka handlers/create.js vi kommer att importera Repo klass, och spara en ny Repa med hjälp av våra tidigare analyserad data:

// handlers/create.js

// …

const Repo = require(‘../store/repo’)

const hanterare = asynkron begäran => {
try {
// …

const data = qs.parse(kroppen)
const repo = nya Reporäntan(data)
väntar repo.spara()

// …
} catch (err) {
återgå nya Svar(err, { status: 400 })
}
}

// …

Med att ett nytt Repo baserat på inkommande data i formulär borde egentligen ha bestått i att Arbetstagare KV! Medan reporäntan är att vara frälst, så vill vi också inrätta en annan datamodell, Dag, vilken innehåller en enkel lista över de arkiv som lämnades in av användare för en specifik dag. Låt oss skapa en annan fil, store/day.js och köttet det ut:

// store/day.js
const idag = () => new Date().toLocaleDateString()
const todayData = asynkron () => {
const date = today()
const kvarstod = väntar REPO_HUNT.få(datum)
tillbaka funnits ? JSON.parse(sparade) : []
}

modulen.exporten = {
lägg till: asynkron funktion(id) {
const date = today()
låt id = väntar todayData()
id = id-nummer.concat(id)
tillbaka REPO_HUNT.sätta(datum, JSON.stringify(id))
}
}

Observera att koden för detta är inte ens en klass — det är ett objekt med nyckel-värde-par, där värdena är funktioner! Vi kommer att lägga till mer om detta snart, men den enda funktion som vi har definierat, lägga till, massor befintliga repor från dagens datum (med hjälp av funktionen idag för att generera en dag string, som används som nyckel i KV), och lägger till en ny Repa, baserad på id argument förs in i funktionen. Tillbaka inne i handlers/create.js vi ska se till att importera och kallar denna nya funktion, så att alla nya repor läggs omedelbart till dagens lista av repor:

// handlers/create.js

// …

const Dag = require(‘../store/dag)

// …

const hanterare = asynkron begäran => {
try {

// …

väntar repo.spara()
väntar på Dagen.lägg till(repo.id -)

återgå nya Svar(‘ok’, { rubriker: { Location: ‘/’ }, status: 301 })
} catch (err) {
återgå nya Svar(err, { status: 400 })
}
}

// …

Vårt repo data som nu kvarstår i KV och den läggs till i en lista över de repor som lämnas av användare för dagens datum. Låt oss gå vidare till den tredje och sista delen av vår handledning, att ta dessa uppgifter, och gör det på hemsidan.

Rendering data

Vid denna punkt, har vi implementerat rendering av HTML-sidor i en Arbetstagare ansökan, liksom att ta av inkommande data och kvarstående det att Arbetstagare KV. Det borde inte förvåna dig att lära dig att med att data från KV, och gör en HTML-sida med det, vår hemsida, är ganska likt allt vi har gjort fram till nu. Minns att vägen är bundna till vår index handler: i den filen, vi vill ladda repor för dagens datum, och föra dem in i mallen, för att kunna göras. Det är några bitar som vi behöver genomföra för att få det att fungera – till att börja med, låt oss titta på handlers/index.js:

// handlers/index.js

// …
const Dag = require(‘../store/dag)

const hanterare = asynkron () => {
try {
låt repor = väntar på Dagen.getRepos()
återgå nya Svar(mall(repor), { rubriker })
} catch (err) {
återgå nya Svar (“Fel! ${err} för ${JSON.stringify(repor)}`)
}
}

// …

Medan den allmänna strukturen av funktionen föraren ska hålla samma, nu är vi redo att sätta några verkliga data till vår ansökan. Vi borde importera Dagen modul, och insidan av föraren, samtal väntar Dag.getRepos för att få en lista av repor tillbaka (oroa dig inte, vi kommer att implementera motsvarande funktioner snart). Med denna uppsättning av repor, vi går förbi dem in i vår mall-funktion, vilket betyder att vi kommer att kunna att faktiskt göra dem inne på HTML.

Inne i Dag.getRepos, vi behöver för att ladda listan av repo-Id: n från insidan KV, och för var och en av dem, ladda motsvarande reporäntan data från KV. I store/day.js:

// store/day.js

const Repo = require(‘./repo’)

// …

modulen.exporten = {
getRepos: asynkron function() {
const id = väntar todayData()
tillbaka ids.längd ? Repo.findMany(ids) : []
},

// …
}

Den getRepos funktion återanvänder våra tidigare definierade todayData funktion, som returnerar en lista med id-handlingar. Om denna listan har *alla* IDs, vill vi faktiskt att hämta dessa förråd. Igen, kommer vi att anropa en funktion som vi inte är helt definierad ännu, importera Repo klass och ringer Repo.findMany, som går i vår lista över Id: n. Som ni kan föreställa er, vi ska hoppa över till store/repo.js och genomföra de kompletterande funktion:

// store/repo.js

klass Repo {
statisk findMany(id) {
tillbaka Löftet.alla(ids.karta(Repo.hitta))
}

statisk asynkron hitta(id) {
const kvarstod = väntar REPO_HUNT.get(`repor:${id}`)
const repo = JSON.parse(sparade)
tillbaka funnits ? nya Reporäntan({ …repo }) : null
}

// …
}

Till stöd för att hitta alla repor är en av IDs, vi definiera två klass-nivå eller statiska funktioner, hitta och findMany som använder Lovar.allt för att ringa hitta för varje ID i set, och väntar på dem alla för att avsluta innan att lösa de lovar. Huvuddelen av logik, inuti hittar, ser upp repo av dess ID (med hjälp av den tidigare definierade nyckel, repor:$id), tolkar JSON-sträng och returnerar en nyligen instansieras instans av Reporäntan.

Nu som vi kan se upp förråd från KV, vi bör ta dessa uppgifter och faktiskt göra det i vår mall. I handlers/index.js vi gick i repor array-funktionen mall som definieras i templates/index.js. I den filen, vi tar som repor array, och göra bitar av HTML-kod för varje repa inne på det:

// templates/index.js

const layout = require(‘./layout”)
const dateFormat = submitted_at =>
nya Datum(submitted_at).toLocaleDateString (“en-us”)

const repoTemplate = ({ beskrivning, namn, submitted_at, url }) =>
`<div class=”media” ->
<div class=”media-content”>
<p>
${name}
</p>
<p>
${beskrivning}
</p>
<p>

Lämnas in ${dateFormat(submitted_at)}
</p>
</div>
</div>
`

const template = repor => {
const renderedRepos = repor.karta(repoTemplate)

tillbaka layout(`
<div>
${
repor.längd
? renderedRepos.gå med(“)
: `<p>det finns Inga repor har lagts fram ändå!</p>`
}
</div>
`)
}

modulen.exporten = mallen

Att bryta denna fil ner, vi har två primära funktioner: mall (en uppdaterad version av vår ursprungliga exporteras funktion), som tar en array av repor, kartor genom dem, ringer repoTemplate, för att generera en rad HTML-strängar. Om repor är en tom array, den funktion som helt enkelt returnerar en p-tagg med en tom stat. Den repoTemplate funktion använder omstrukturering av valutan i uppdrag att ställa in variabler beskrivning, namn, submitted_at, och webbadress från insidan av repo-objektet som skickas till funktionen, och gör var och en av dem i ganska enkel HTML, stödd på Bulma CSS-klasser för att snabbt definiera ett medieobjekt layout.

Och med att vi är klar med att skriva kod för vårt projekt! Efter kodning en ganska omfattande full stack ansökan på toppen av Arbetstagare, är vi på det sista steget: att distribuera programmet till Arbetstagare plattform.

Distribuera din webbplats för att arbetstagare.dev

Varje Arbetstagare användaren kan göra anspråk på en fri Arbetare.dev underdomän, efter undertecknande upp för en Cloudflare konto. I Wrangler, vi har gjort det super lätt att göra anspråk på och konfigurera din underdomän, med hjälp av den underdomän underkommandot. Varje konto får en Arbetstagare.dev underdomän, så välj klokt!

wrangler underdomän min-cool-underdomän

Med en konfigurerad underdomän, kan vi nu använda vårt kod! Egenskapen namn på wrangler.toml kommer att ange den slutliga URL att vår ansökan kommer att användas för att: i min kodbasen, namnet är satt till repa-jakt, och min underdomän är signalnerve.arbetstagare.dev, så min sista URL för mitt projekt kommer att vara repo-jakt.signalnerve.arbetstagare.dev. Låt oss distribuera projektet, med hjälp av kommandot publicera för:

wrangler publicera

Innan vi kan visa projektet i webbläsaren, har vi ytterligare ett steg för att slutföra: gå in på Cloudflare UI, skapa en KV-namnrymden, och binda det till vårt projekt. Till att börja denna process, logga in på ditt Cloudflare dashboard och välj “Arbetare” – fliken på högra sidan av sidan.

Insidan av Arbetstagare avsnitt i översikten hitta “KV” i menyn och skapa en ny namnrymd, matchande namnrymd som du använde i din kodbas (om du följt koden prover, detta kommer att vara REPO_HUNT).

I listningen av KV namnrymder, kopiera ditt namespace-ID. Tillbaka i vårt projekt ska vi lägga till ett `kv-namnområden` nyckeln till vår `wrangler.toml”, för att använda vårt nya namespace i kodbasen:

# wrangler.toml
[[kv-namnområden]]
bindande = “REPO_HUNT”
id = “$yourNamespaceId”

För att se till att era projekt är att använda den nya KV-namnrymden, publicera ditt projekt en sista gång:

wrangler publicera

Med att din ansökan ska kunna läsa och skriva från KV-namnområdet. Öppna mitt projekt URL bör visa den slutliga versionen av vårt projekt — en komplett, datadrivna program utan att behöva hantera några servrar, helt byggd på de Arbetstagare som plattform!

Vad är nästa steg?

I den här guiden, vi byggde en full stack serverlösa ansökan på toppen av Arbetstagare plattform, med hjälp av Wrangler, Cloudflare command-line verktyg för att bygga och driftsätta Arbetstagare program. Det finns massor av saker som du kan göra för att fortsätta att lägga till denna ansökan: till exempel möjligheten att upvote inlagor, eller ens att tillåta kommentarer och andra typer av data. Om du vill se det färdiga kodbasen för detta projekt, kolla in GitHub-repo!

Arbetarna laget upprätthåller en ständigt växande lista av nya mallar för att börja bygga projekt med – om du vill se vad ni kan bygga, se till att kolla in vår Mall Galleri. Dessutom, se till att kolla in några av handledning i de Arbetstagare dokumentation, till exempel att bygga en Slack bot, eller en QR-kod generator.

Om du gått igenom hela guiden (eller om du håller på att bygga coola saker du vill dela med dig), jag skulle älska att höra om hur det gick . Om du är intresserad av serverlösa och vill hänga med i alla nya tutorials jag publicera, se till att gå med i mitt nyhetsbrev och prenumerera på min YouTube-kanal!