Erstellung eines E-Mail-Anmelde-Widgets mit Netlify Forms und Netlify Functions

Avatar of Matthew Ström
Matthew Ström am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der Aufbau und die Pflege einer eigenen Website ist eine großartige Idee. Sie besitzen nicht nur Ihre Plattform, sondern können auch mit Webtechnologien experimentieren. Kürzlich habe ich mich mit dem Konzept der serverlosen Funktionen beschäftigt, angefangen mit meiner eigenen Website. Ich möchte die Ergebnisse und meine dabei gewonnenen Erkenntnisse teilen, damit Sie sich ebenfalls damit auseinandersetzen können!

Aber zuerst: eine 1-minütige Einführung in serverlose Funktionen

Eine serverlose Funktion (manchmal auch Lambda-Funktion oder Cloud-Funktion genannt) ist ein Code-Snippet, das Sie unabhängig von Ihrer Website, App oder anderem Code schreiben, hosten und ausführen können. Trotz des Namens laufen serverlose Funktionen tatsächlich auf einem Server; aber es ist ein Server, den Sie nicht erstellen oder warten müssen. Serverlose Funktionen sind spannend, weil sie viel Arbeit bei der Erstellung leistungsfähiger, skalierbarer Anwendungen abnehmen.

Es gibt viele großartige Informationen zu serverlosen Funktionen, und ein guter Startpunkt ist der eigene Leitfaden von CSS Tricks: Die Macht von serverlosen Front-End-Entwicklern.

Die Herausforderung: Erstellen eines Anmeldeformulars für eine Mailingliste

Ich begann meine Reise mit einer Herausforderung: Ich wollte ein Anmeldeformular für meine E-Mail-Liste auf meiner Website haben. Die Regeln lauten wie folgt:

  • Es sollte ohne JavaScript funktionieren. Ich möchte sehen, wie weit ich nur mit CSS und HTML komme. Progressive Verbesserungen sind in Ordnung.
  • Es sollten keine externen Abhängigkeiten erforderlich sein. Dies ist ein Lernprojekt, daher möchte ich, wenn möglich, 100% des Codes selbst schreiben.
  • Es sollten serverlose Funktionen verwendet werden. Anstatt Daten clientseitig an meinen E-Mail-Listen-Dienst zu senden, machen wir es server(less)-seitig!

Lernen Sie das Team kennen: 11ty, Netlify und Buttondown

Meine Website ist mit einem Static-Site-Framework namens 11ty aufgebaut. 11ty ermöglicht es mir, Vorlagen und Komponenten in HTML zu schreiben, also werden wir unser E-Mail-Formular so erstellen. (Chris hat kürzlich einen großartigen Artikel über seine Erfahrungen mit 11ty geschrieben, falls Sie mehr erfahren möchten.)

Die Website wird dann mit einem Dienst namens Netlify bereitgestellt und ist der Schlüsselspieler in unserem Team hier: der Point Guard, der Quarterback, der Kapitän. Das liegt daran, dass Netlify drei Funktionen hat, die zusammenarbeiten, um serverlose Exzellenz zu erzielen.

  • Netlify kann automatisch aus einem GitHub-Repository bereitstellen. Das bedeutet, ich kann meinen Code schreiben, einen Pull-Request erstellen und sofort sehen, ob mein Code funktioniert. Obwohl es Tools gibt, um serverlose Funktionen lokal zu testen, macht Netlify es super einfach, live zu testen.
  • Netlify Forms verarbeitet alle Formularübermittlungen meiner Website. Dies ist ein Teil der serverlosen Gleichung: Anstatt Code zu schreiben, um Übermittlungen zu sammeln, konfiguriere ich das HTML mit ein paar einfachen Attributen und lasse Netlify den Rest erledigen.
  • Netlify Functions ermöglicht es mir, mit den Daten aus meinen Formularen Aktionen durchzuführen. Ich schreibe etwas Code, um E-Mails an meinen E-Mail-Listen-Anbieter zu senden und sage Netlify, wann dieser Code ausgeführt werden soll.

Schließlich verwalte ich meine E-Mail-Liste mit einem Dienst namens Buttondown. Es ist ein schnörkelloser E-Mail-Newsletter-Anbieter mit einer einfach zu bedienenden API.

Bonus: Für persönliche Websites wie meine sind 11ty, Netlify und Buttondown *kostenlos*. Das ist unschlagbar.

Das Formular

Das HTML für mein E-Mail-Abonnementformular ist sehr minimalistisch, mit ein paar Extras, damit Netlify Forms funktioniert.

<form class="email-form" name="newsletter" method="POST" data-netlify="true" netlify-honeypot="bot-field">
  <div hidden aria-hidden="true">
    <label>
      Don’t fill this out if you're human: 
      <input name="bot-field" />
    </label>
  </div>
  <label for="email">Your email address</label>
  <div>
    <input type="email" name="email" placeholder="Email"  id="email" required />
    <button type="submit">Subscribe</button>
  </div>
</form>

Zuerst setze ich das `data-netlify`-Attribut auf `true`, um Netlify mitzuteilen, dass dieses Formular behandelt werden soll.

Das erste Eingabefeld im Formular heißt `bot-field`. Dies entlarvt Roboter: Ich weise Netlify an, auf verdächtige Übermittlungen zu achten, indem ich das Attribut `netlify-honeypot` auf `bot-field` setze. Dann verstecke ich das Feld vor Menschen, indem ich die HTML-Werte `hidden` und `aria-hidden` verwende – Benutzer mit und ohne assistierende Technologie können das gefälschte Eingabefeld nicht ausfüllen.

Wenn das Formular mit etwas im `bot-field`-Eingabefeld übermittelt wird, weiß Netlify, dass es von einem Roboter stammt, und ignoriert die Eingabe. Zusätzlich zu dieser Schutzschicht filtert Netlify automatisch verdächtige Übermittlungen mit Askimet. Ich muss mich nicht um Spam kümmern!

Das nächste Eingabefeld im Formular heißt `email`. Hier wird die E-Mail-Adresse eingegeben! Ich habe den input-Typ als `email` angegeben und `required` gesetzt; das bedeutet, dass der Browser die gesamte Validierung für mich durchführt und den Benutzern nichts anderes als eine gültige E-Mail-Adresse gestattet.

Progressive Verbesserung mit JavaScript

Eine nette Funktion von Netlify Forms ist die Möglichkeit, Benutzer nach der Formularübermittlung automatisch auf eine "Danke"-Seite umzuleiten. Aber idealerweise möchte ich meine Benutzer *auf* der Seite behalten. Ich habe eine kurze Funktion geschrieben, um das Formular ohne Umleitung zu übermitteln.

const processForm = form => {
  const data = new FormData(form)
  data.append('form-name', 'newsletter');
  fetch('/', {
    method: 'POST',
    body: data,
  })
  .then(() => {
    form.innerHTML = `<div class="form--success">Almost there! Check your inbox for a confirmation e-mail.</div>`;
  })
  .catch(error => {
    form.innerHTML = `<div class="form--error">Error: ${error}</div>`;
  })
}

Wenn ich die Inhalte meines E-Mail-Formulars über den Wert `form` an diese Funktion übergebe, wird das Formular über die integrierte Fetch API von JavaScript gesendet. Wenn die Funktion erfolgreich war, wird dem Benutzer eine angenehme Nachricht angezeigt. Wenn die Funktion auf ein Problem stößt, wird den Benutzern mitgeteilt, dass etwas schief gelaufen ist.

Diese Funktion wird jedes Mal aufgerufen, wenn ein Benutzer auf die Schaltfläche "Senden" des Formulars klickt.

const emailForm = document.querySelector('.email-form')
if (emailForm) {
  emailForm.addEventListener('submit', e => {
    e.preventDefault();
    processForm(emailForm);
  })
}

Dieser Listener *verbessert progressiv* das Standardverhalten des Formulars. Das bedeutet, dass das Formular auch dann funktioniert, wenn JavaScript des Benutzers deaktiviert ist!

Die serverlose Funktion

Nachdem wir nun ein funktionierendes Formular zur E-Mail-Übermittlung haben, ist es Zeit für etwas Automatisierung mit einer serverlosen Funktion.

So funktionieren Netlify-Funktionen:

  1. Schreiben Sie die Funktion in einer JavaScript-Datei in Ihrem Projekt.
  2. Teilen Sie Netlify über die Datei `netlify.toml` in Ihrem Projekt mit, wo es nach Ihrer Funktion suchen soll.
  3. Fügen Sie alle benötigten Umgebungsvariablen über die Admin-Oberfläche von Netlify hinzu. Eine Umgebungsvariable ist etwas wie ein API-Schlüssel, den Sie geheim halten müssen.

Das war's! Beim nächsten Bereitstellen Ihrer Website ist die Funktion einsatzbereit.

Die Funktion für meine Website wird sich im Ordner `functions` befinden, daher habe ich Folgendes in meiner `netlify.toml`-Datei:

[build]
  base = "."
  functions = "./functions"

Dann füge ich eine Datei im Ordner `functions` namens `submission-created.js` hinzu. Es ist wichtig, die Datei *submission-created* zu nennen, damit Netlify weiß, dass sie jedes Mal ausgeführt werden soll, wenn eine neue Formularübermittlung stattfindet. Eine vollständige Liste der Ereignisse, gegen die Sie Skripte schreiben können, finden Sie in der Dokumentation von Netlify. Wenn Sie Ihre Funktion korrekt benannt und konfiguriert haben, sollten Sie sie im Functions-Dashboard von Netlify sehen.

Das Netlify Functions Dashboard zeigt, dass ich meine submission-created Funktion korrekt konfiguriert habe.

Der Inhalt von `submission-created.js` sieht wie folgt aus:

require('dotenv').config()
const fetch = require('node-fetch')
const { EMAIL_TOKEN } = process.env
exports.handler = async event => {
  const email = JSON.parse(event.body).payload.email
  console.log(`Recieved a submission: ${email}`)
  return fetch('https://api.buttondown.email/v1/subscribers', {
    method: 'POST',
    headers: {
      Authorization: `Token ${EMAIL_TOKEN}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ email }),
  })
    .then(response => response.json())
    .then(data => {
      console.log(`Submitted to Buttondown:\n ${data}`)
    })
    .catch(error => ({ statusCode: 422, body: String(error) }))
}

Lassen Sie uns dies Zeile für Zeile betrachten.

Zeile 1 enthält eine Bibliothek namens `dotenv`. Dies wird mir helfen, **Umgebungsvariablen** zu verwenden. Umgebungsvariablen sind nützlich, um Informationen zu speichern, die ich nicht öffentlich machen möchte, wie z. B. einen API-Schlüssel. Wenn ich mein Projekt lokal ausführe, setze ich meine Umgebungsvariablen mit einer `.env`-Datei im Repository und stelle sicher, dass sie in meiner `.gitignore`-Datei aufgeführt ist. Um auf Netlify bereitzustellen, richte ich auch Umgebungsvariablen in der Weboberfläche von Netlify ein.

In Zeile 2 füge ich eine kleine Bibliothek namens `node-fetch` hinzu. Dies ermöglicht mir die Verwendung der Fetch API von Javascript in Node, was der Weg ist, wie wir Daten an Buttondown senden werden. Netlify bindet diese Abhängigkeit automatisch ein, solange sie in der `package.json`-Datei meines Projekts aufgeführt ist.

In Zeile 3 importiere ich meinen API-Schlüssel aus dem Umgebungsvariablenobjekt, `process.env`.

Zeile 4 ist, wo die Funktion definiert ist. Der Wert `exports.handler` ist dort, wo Netlify unsere Funktion erwartet, also definieren wir sie dort. Die einzige Eingabe, die wir benötigen, ist der `event`-Wert, der alle Daten aus der Formularübermittlung enthält.

Nachdem ich die E-Mail-Adresse aus dem `event`-Wert mithilfe von `JSON.parse` extrahiert habe, bin ich bereit, sie an Buttondown zu senden. Hier verwende ich die zuvor importierte `node-fetch`-Bibliothek: Ich sende eine POST-Anfrage an `https://api.buttondown.email/v1/subscribers` und füge meinen API-Schlüssel in den Header ein. Die API von Buttondown hat nicht viele Funktionen, daher dauert es nicht lange, die Dokumentation zu lesen, wenn Sie mehr erfahren möchten.

Der Body meiner POST-Anfrage besteht aus der extrahierten E-Mail-Adresse.

Dann (mithilfe der cleveren `.then()`-Syntax) sammle ich die Antwort vom Server von Buttondown. Das mache ich, um Probleme, die während des Prozesses auftreten, zu diagnostizieren – Netlify macht es einfach, die Protokolle Ihrer Funktion zu überprüfen, also verwenden Sie `console.log` oft!

Bereitstellung der Funktion

Nachdem ich meine Funktion geschrieben, meine `netlify.toml`-Datei konfiguriert und meine Umgebungsvariablen hinzugefügt habe, ist alles bereit. Die Bereitstellung ist schmerzfrei: Richten Sie einfach die GitHub-Integration von Netlify ein, und Ihre Funktion wird bereitgestellt, wenn Ihr Projekt hochgeladen wird.

Netlify-Projekte können auch lokal mit Netlify Dev getestet werden. Je nach Komplexität Ihres Codes kann die lokale Entwicklung schneller sein: Führen Sie einfach `npm i netlify -g` und dann `netlify dev` aus. Netlify Dev verwendet die `netlify.toml`-Datei, um das Projekt lokal zu konfigurieren und auszuführen, einschließlich aller serverlosen Funktionen. Praktisch, oder? Eine Einschränkung: Netlify Dev kann derzeit keine serverlosen Funktionen bei Formularübermittlungen auslösen, daher müssen Sie dies mithilfe von Vorschau-Builds testen.

Eine Idee für die Zukunft

Die API von Buttondown hat einige mögliche Antworten, wenn ich eine neue E-Mail übermittle. Wenn ein Benutzer zum Beispiel eine E-Mail übermittelt, die bereits auf der Liste abonniert ist, würde ich ihm das gerne sofort mitteilen, wenn er das Formular absendet.

Fazit

Alles in allem musste ich nur etwa 50 Zeilen Code schreiben, um ein funktionierendes Anmeldeformular für den E-Mail-Newsletter auf meiner Website zu haben. Ich habe alles in HTML, CSS und JavaScript geschrieben, ohne mich um die Serverseite kümmern zu müssen. Das Formular behandelt Spam, und meine Leser erhalten eine gute Erfahrung, unabhängig davon, ob JavaScript aktiviert ist oder nicht.