← Voir tous les articlesLoïc Tardivel-LacombeLoïc Tardivel-Lacombe - 18 juil. 2022

Héberger gratuitement votre site avec un formulaire de contact

Ou comment créer une SPA avec Nuxt 3 et la déployer en utilisant les fonctionnalités serverless de Netlify

Il arrive souvent de devoir créer un site statique, mais avec un formulaire de contact. Cela peut être le cas pour un site vitrine, pour un CV en ligne, ou même seulement pour une page de site en cours de construction… Un site statique peut être hébergé à peu près n'importe où, mais ajouter un simple formulaire de contact y ajoute une contrainte supplémentaire : il faut valider le formulaire, récupérer les données saisies, et peut-être même envoyer un e-mail.

Heureusement, il est aujourd'hui très simple d'inclure cette fonctionnalité, sans avoir à la développer et sans payer le coût de l'hébergement d'un backend. Je vais vous présenter ici comment réaliser un projet sur Netlify, de la création au déploiement automatisé.

Pour cet exemple, le projet sera développé avec Nuxt 3, framework basé sur Vue.js 3. Mais pas d'inquiétude, vous pourrez sauter cette section si votre site statique est développé autrement.

A noter : la gratuité de ce service dépend de votre utilisation. Au-delà de 100 envois (hors spams) par mois, il vous sera facturé automatiquement, d'où notre utilisation comme formulaire de contact.

Création du projet et CI/CD

Pour commencer, créez votre projet sur votre gestionnaire Git préféré (Netlify accepte actuellement GitHub, GitLab et Bitbucket). Ici par exemple sur GitLab.

Une fois cela réalisé, et après avoir créé un compte sur Netlify, allez dans la partie « Sites », puis « Add new site » et « Import an existing project ».

Interface Netlify pour importer un projet existant

Ensuite, choisissez votre provider Git, ainsi que votre branche de déploiement. Comme nous n'avons fait aucun paramétrage dans GitLab, notre branche sera main. Il est toujours possible de la changer en cours de route.

Vous pouvez spécifier le dossier racine, la commande de build, le dossier de publication, et d'autres choses selon votre besoin. Laissons tout par défaut.

Interface Netlify qui indique que le site est en cours de déploiement

… Et voilà, votre site est prêt à être mis en ligne ! A chaque commit sur la branche sélectionnée, la nouvelle version sera déployée. Vous n'avez rien eu à faire, votre CI est déjà en place.

Vous êtes maintenant prêt à développer votre site !

Génération statique avec Nuxt 3

Si vous n'utilisez pas Nuxt, vous pouvez passer au chapitre suivant. Sinon, voici la méthode pour créer un site statique… Avec des données dynamiques.

Création du projet

Créons notre projet avec Nuxt 3 (cf. Quick Start) : npx nuxi init demo-app

Vous devriez avoir une arborescence similaire à celle-ci :

Arborescence à l'initialisation du projet

Personnellement, je déplace ensuite le contenu du dossier demo-app dans le répertoire du dessus.

A noter : Nuxt 3 est à ce jour encore en développement (release candidate 5), et j'ai fait mes tests sur la rc 3. J'ai rencontré quelques soucis avec d'anciennes versions, qui m'empêchaient de générer le projet correctement, mais cela a fonctionné à partir de la version 3.0.0-rc.3-27550969.a4a3cff. Si vous rencontrez des erreurs lors du build, vous pouvez donc modifier la version comme suit dans le fichier package.json :

"devDependencies": {
"nuxt": "npm:nuxt3@3.0.0-rc.3-27550969.a4a3cff"
}

Nous pouvons maintenant installer les dépendances avec npm install, puis lancer le projet avec npm run dev. Il devrait être accessible après quelques instants sur http://localhost:3000.

Génération statique

Pour générer un site statique avec Nuxt, il faut lancer la commande generate. Cependant, il faut auparavant configurer le projet pour autoriser la génération statique en modifiant le fichier nuxt.config.ts.

Github code

A présent, exécutez la commande npm run generate. Vous devriez voir apparaître les dossiers .output et dist (que vous pouvez ajouter au .gitignore).

Arborescence du projet avec les nouveaux dossiers .output et dist

Sur Netlify, allez dans les paramètres de build de votre projet et spécifiez la commande de build (npm run generate) le dossier d'output (dist).

Interface Netlify pour les paramètres de build

Vous pouvez commit / push, et regarder Netlify déployer votre site tout neuf !

Interface Netlify avec les logs de déploiement

Formulaire Netlify

Maintenant que votre site est créé, il est temps d'y ajouter quelques fonctionnalités… En commençant par un formulaire.

Netlify permet de créer gratuitement un formulaire complètement fonctionnel et sécurisé. La documentation complète se trouve sur cette page, mais voici les étapes à retenir :

  1. Créer un formulaire HTML classique
  2. Ajouter au formulaire quelques balises spécifiques à Netlify
  3. Sécuriser le formulaire
  4. Configurer l'envoi de mail dans Netlify

Création du formulaire

Commençons par créer un formulaire simple en remplaçant le contenu du fichier app.vue. Pour l'exemple, nous ne garderons qu'un input "email", mais vous pouvez créer un formulaire complet avec autant de champs que vous voulez.

Github code

Ensuite, ajoutons le tag netlify qui permet de dire à Netlify que nous voulons qu'il traite ce formulaire automatiquement.

<form name="myForm" method="post" netlify >

En principe, c'est tout ce dont on a besoin pour que le formulaire fonctionne sur Netlify. Cependant, si comme moi vous utilisez Nuxt, vous aurez un problème : le formulaire n'est pas détecté par Netlify, car le contenu de notre page est créé via JavaScript : il suffit de générer notre projet pour se rendre compte que le fichier dist/index.html ne contient pas notre formulaire.

Formulaire avec Nuxt

Pour palier à ce problème, une méthode simple consiste à créer un fichier html brut décrivant notre formulaire. Cette solution décrite ici est peu élégante, car il faudra mettre à jour le formulaire dans les deux fichiers en même temps. Elle reste cependant la plus simple à mettre en oeuvre.

Dans le dossier public, on crée un formulaire hidden avec les champs utilisés

Arborescence pour l'ajout de my-form.html
<form name="myForm" netlify hidden>
  <input name="email" type="email" />
</form>

Pour que Netlify reçoive les données, le formulaire de notre fichier app.vue doit maintenant contenir un champ input form-name hidden contenant comme valeur le nom de notre formulaire. Plus besoin de name ni netlify sur la balise <form>, car Netlify analysera le fichier .html créé précédemment.

Modifications effectuées sur le formulaire dans app.vue

Et voilà ! Lors du prochain commit du code, le formulaire sera en ligne et prêt à être utilisé.

Message de confirmation de l'envoi du formulaire

Après vaidation du formulaire

Interface Netlify pour consulter les données reçues depuis les formulaires

Sécurisation du formulaire

Il est vivement recommandé de sécuriser un minimum le formulaire contre les spams. Netlify utilise déjà le service Akismet pour cela, mais permet d'ajouter une sécurité supplémentaire, ce qui est toujours bienvenue pour cette problématique importante. Deux solutions sont proposées :

  • Ajouter un reCaptcha Google
  • Ajouter un champ honeypot afin de leurrer les bots

Le champ honeypot pose quelques contraintes supplémentaires mais a l'avantage de ne pas imposer l'utilisation de cookies et d'être moins invasif pour les utilisateurs. Il est aussi un peu moins efficace pour filtrer les bots, mais peut être suffisant en combinaison avec Akismet. Cependant, gardez à l'esprit qu'il est nécessaire de respecter certaines règles afin de garder un honeypot utile.

Configurer l'envoi de mails

Maintenant que notre formulaire est en ligne, nous pouvons configurer certains paramètres dans Netlify pour qu'un mail soit envoyé automatiquement.

Interface Netlify pour configurer les notifications d'envoi de mails

Rendre le site dynamique avec Nuxt

Notre page statique fonctionne, mais il est aussi possible d'avoir un site multi-pages dont les données sont dynamiques.

SPA et Routing Nuxt

Il est relativement commun d'avoir plusieurs pages sur un site web… Cependant, étant donné que nous n'avons pas de backend pour gérer les routes, il est nécessaire d'indiquer à Netlify que nous voulons nous comporter comme une Single Page Application avec un routing côté front.

Première étape : modifier notre exemple pour ajouter une seconde page, "About us". Il suffit de créer un dossier pages et de créer deux fichiers, index.vue, qui correspond à la page d'accueil (et qui contiendra maintenant notre formulaire), et about.vue, qui sera notre nouvelle page. Le fait de créer un fichier .vue dans un dossier pages active le routing Nuxt au prochain build.

Nouvelle structure pour le projet

Le fichier app.vue va également changer, pour que l'application Nuxt affiche le contenu de chaque page via la balise <NuxtPage />. En mode développement (npm run dev), pensez à relancer votre serveur.

Nouveau contenu pour le fichier app.vue

Seconde étape : Si nous déployons le site tel quel, l'url http://localhost:3000/about sera accessible en local, mais l'équivalent déployé sur Netlify ne le sera pas. Il faut spécifier à Netlify que toutes les url doivent mener à la racine, via un fichier _redirects.

# The following redirect is intended for use with most SPAs that handle routing internally.
/*   /index.html   200

Cela permet de rediriger tous les chemins vers index.html. Il faut aussi que ce fichier soit copié dans le répertoire de destination du build. Ici par exemple à l'aide du package copyfile avec la modification du package.json.

Modifications effectuées sur le package.json

J'ai utilisé ici le script postbuild qui est automatiquement appelé à la fin d'une commande npm run build. J'ai donc supprimé la commande generate pour utiliser la commande build à la place, et il m'a fallu mettre à jour la commande de build dans Netlify avant de faire le commit.

Interface Netlify avec la modification des paramètres de build

Notre SPA fonctionne maintenant lorsqu'elle est déployée sur Netlify. Vous pouvez aller sur la page /contact et rafraîchir sans problème.

Appels APIs

Notre site est statique, mais il est tout à fait possible de le rendre dynamique en faisant appel à des APIs externes.

Pour que cela fonctionne, il faut qu'elles acceptent les requêtes CORS. Si vous développez vos propres APIs, je vous conseille plutôt de configurer celles-ci pour accepter exclusivement les appels depuis l'URL de votre frontend, pour des raisons de sécurité.

Exemple de requête à une API

Formulaires dynamiques

Nous avons vu précédemment comment créer un formulaire fixe dans Vue.js, et comment le faire reconnaître par Netlify. Nous avons ainsi dû définir chaque champ à envoyer manuellement.

Il existe cependant une technique pour créer des formulaires dynamiques dans vue. Cela nécessite de coder soi-même l'envoi du formulaire à Netlify. Ce sujet nécessiterait un article à lui tout seul, je vous conseille donc de jeter un coup d'œil au lien précédent.

Important : comme précédemment, n'oubliez pas le champ caché form-name nécessaire pour que Netlify comprenne de quel formulaire il s'agit.

axios.post(
"/",
this.encode({
"form-name": "myForm",
...this.form
}),
axiosConfig
);

Bonus : fonctions serverless

Nous avons créé un site qui appelle des APIs externes. Il est aussi possible de créer des fonctions serverless dans Netlify ! Ces fonctions sont des morceaux de codes (JavaScript, TypeScript ou Go) qui seront appelés à la volée sans avoir à maintenir votre propre serveur.

Netlify limite la durée des fonctions à 10 secondes. Il est possible de faire des traitements plus longs (jusqu'à 15 minutes) avec les fonctions asynchrones (background functions). Il y a aussi une limite du nombre de requêtes et de la durée de traitement.

Interface Netlify avec les limites d'utilisations des fonctions serverless

Vous avez la possibilité d'appeler gratuitement votre fonction un certain nombre de fois avant de passer à l'abonnement suivant

Toutes les fonctions doivent correspondre à des fichiers déposés dans le dossier netlify/functions. Une fonction hello peut être sauvée de plusieurs manières :

  • netlify/functions/hello.js
  • netlify/functions/hello/hello.js
  • netlify/functions/hello/index.js

Le résultat sera dans tous les cas une API exposée sur /.netlify/functions/hello. Pour créer une fonction asynchrone, il suffit de rajouter le suffixe -background.

Nous allons par exemple créer une fonction synchrone qui nous renverra le résultat N de la suite de Fibonacci.

Arborescence du projet avec le fichier pour l'ajout de la fonction

Votre fichier .js devra exporter une méthode handler, qui prend en paramètres event et context qui contiennent les données de la requête entrante (voir ici pour les détails).

Github code

Notre fonction renvoie un code OK 200, et le résultat en body. Le body doit être une string valide, donc nous avons transformé notre objet de retour en JSON, qui devra être décodé côté client. Pour les fonctions asynchrones, on ne renvoie rien.

Ajoutons maintenant une nouvelle page Vue qui fera appel à notre API.

Nouveau fichier /pages/fibonacci.vue

Pour simplifier au maximum mon exemple, je n'ai pas vraiment sécuriser le JSON.parse : en local, la page restera blanche (erreur dans la console).

Lors de notre prochain déploiement, notre API sera appelée côté client. Vous avez créé votre propre fonction serverless !

Vous pouvez retrouver d'autres exemples de fonctions serverless sur cette page.

Pour aller plus loin…

Il reste bien sûr beaucoup de choses intéressantes à voir avec Netlify ! Je vous invite à fouiller dans la documentation et dans les paramètres de votre projet.

Exemples :

  • Vous pouvez paramétrer la page de retour du formulaire, mais pensez à modifier l'action dans les deux formulaires si vous utilisez Nuxt.
  • L'upload de fichier est aussi possible, avec une limite assez basse.
  • Dans les paramètres "Build & deploy" de votre site, il existe une section "Asset optimization". Il existe aussi une partie "Deploy Previews" pour faire tester vos branches de développement.

Good Luck & Have Fun!