Article original : You can't get there from here: how Netlify Lambda and Firebase led me to a serverless dead end

Par Jeff M Lowery

[Mise à jour : Apparemment, on peut y arriver d'ici ! C'est-à-dire, si vous utilisez firebase-admin au lieu de @google-cloud/firestore. J'aurai plus d'informations à ce sujet dans le futur, mais l'essentiel est résumé ici.]

Il y a quelque temps, j'explorais le support de Netlify pour FaunaDB : une base de données NoSQL orientée documents avec des fonctionnalités spéciales pour gérer les transactions sur des serveurs de base de données dispersés. J'ai décidé de l'essayer car c'était un choix pratique, puisque il y avait du code exemple avec lequel je pouvais commencer. L'exemple utilisait des fonctions lambda comme interface pour la base de données.

fauna avec lambda

J'ai modifié les fonctions lambda originales pour qu'elles communiquent avec l'API GraphQL de FaunaDB (au lieu de FQL). Bien que cela ait fonctionné, j'ai finalement estimé que le support de GraphQL par Fauna n'était pas tout à fait mûr, alors j'ai cherché des alternatives.

J'ai finalement opté pour Cloud Firestore. J'ai basé ce nouveau projet sur l'exemple Fauna, en remplaçant le module faunadb par apollo-server-lambda, afin de pouvoir écrire ma propre API GraphQL et mes résolveurs.

L'une des améliorations que j'ai dû apporter a été de déplacer toutes mes dépendances de fonction Netlify vers le dossier /functions dans mon projet (séparé et au même niveau que le dossier /src qui contient mon client React). Pour ce faire, j'ai exécuté npm init dans le dossier functions, j'ai déplacé un ensemble de dépendances du fichier package.json de niveau supérieur vers le nouveau /functions/package.json, j'ai ajouté un webpack.functions.js, puis j'ai exécuté yarn install pour extraire les packages dans un nouveau dossier node_modules.

Le résultat était le suivant :

Image

Je parlerai des sous-dossiers plus tard ; la principale chose à remarquer est qu'il y a des fichiers yarn, plus package.json, un dossier node_modules, un dossier schema, et quelques fichiers .js pour les tests.

Le projet original utilisait netlify_lambda pour construire, qui utilise webpack et babel. J'ai rencontré certains problèmes, je les ai résolus, puis je les ai rencontrés à nouveau plus tard.

Frustré, j'ai décidé de ne pas utiliser netlify-lambda et j'ai choisi Netlify Dev pour construire et déployer depuis la ligne de commande. L'inconvénient était que je n'avais pas la possibilité de lancer un serveur local, mais je pouvais déployer des candidats sur Netlify et les tester sans d'abord vérifier la source dans github ou déployer directement en production.

Il y avait moins de pièces mobiles puisque webpack et babel n'étaient plus nécessaires. En empruntant cette voie, vous définissez probablement la variable d'environnement AWS_LAMBDA_JS_RUNTIME sur nodejs10.x dans les paramètres Build & deploy pour vos fonctions.

Les choses ne sont pas toujours ce qu'elles semblent être

Plus familier avec les clients et serveurs GraphQL qu'avec les fonctions lambda dans le cloud, j'avais quelques hypothèses naïves sur la manière dont les choses étaient déployées dans Netlify. Je pensais que les fonctions étaient plus ou moins copiées et que les scripts de construction étaient exécutés sur le serveur, où tout serait heureux et mes fonctions seraient appelables via des URLs.

Ce n'est pas du tout ce qui se passe.

Lorsque j'ai commencé avec netlify_lambda, il utilisait webpack pour créer un fichier de sortie functions_build. Ma configuration netlify.toml avait cela comme emplacement des fonctions.

[build]
  functions = "functions-build"
  # Cela sera exécuté lors de la construction du site
  command = "yarn build"
  # Ce répertoire est publié sur le CDN de Netlify
  publish = "build"

Lorsque je suis passé à l'utilisation de Netlify Dev, j'ai abandonné le dossier de sortie et j'ai simplement déployé la source "non regroupée" /functions. Ce n'est pas la fin de l'histoire, cependant.

Problèmes d'authentification

Dans le projet FaunaDB, l'authentification se faisait via une variable d'environnement dont la valeur était un simple jeton. Un mécanisme similaire est utilisé par Firebase, mais au lieu d'un jeton, la valeur de la variable est un chemin vers un fichier d'identifiants que vous générez via la console FireBase. Les fonctions lambda créent une instance Firebase, et cette instance recherche la variable d'environnement pour localiser le fichier d'identifiants pour l'authentification.

Il semble que, peu importe où je plaçais ce fichier d'identifiants ou quel chemin j'utilisais, le client Firebase ne parvenait pas à le trouver. Au cours de mes recherches, je suis tombé sur une mention de l'utilitaire zip-it-and-ship-it de Netlify, que d'autres personnes avec d'autres problèmes recommandaient pour regrouper les fonctions dans des fichiers zip.

Je l'ai essayé, en modifiant le processus de construction pour appeler un script NodeJS qui compressait mes fonctions dans un dossier functions-dist (en modifiant la configuration netlify.toml pour qu'elle ne pointe pas vers ce dossier au lieu du dossier source functions). Bien que cela n'ait pas immédiatement résolu mes problèmes avec le fichier d'identifiants, j'ai remarqué certaines choses.

Image

J'ai commencé à réaliser que, lorsque chaque fichier .js de fonction lambda était regroupé dans un fichier zip, il contenait également son propre dossier node_modules. De plus, le dossier node_modules était "personnalisé" pour contenir uniquement les dépendances explicitement requises par chaque fonction.

Astucieux, mais pas assez

Cela a nécessité quelques réflexions, mais j'ai décidé que si j'ajoutais mon fichier .json dans un projet local, puis en faisais une dépendance pour chaque fonction lambda, il serait intégré dans le dossier node_modules. À ce moment-là, j'aurais un chemin : ./creds/mycred.json. Hourra !

Cela n'a pas tout à fait fonctionné—lorsque j'ai examiné les fichiers zip, les fichiers d'identifiants étaient là dans chaque archive zip, mais le client Firebase ne pouvait toujours pas y accéder.

J'ai avoué mon échec total sur le forum de support de Netlify, disant que je prévoyais de rejoindre une commune pour apprendre à tisser des hamacs.

À l'aide !

Image _Photo par [Unsplash](https://unsplash.com/@jonnysplsh?utm_source=ghost&utm_medium=referral&utm_campaign=api-credit">Jonny Caspari / <a href="https://unsplash.com/?utm_source=ghost&utm_medium=referral&utmcampaign=api-credit)

J'ai dû évoquer quelque pitié, car Dennis de Netlify a bientôt répondu et m'a fait savoir que les fonctions lambda ne peuvent pas réellement accéder au système de fichiers. Ce que je tentais (charger les identifiants via un chemin de fichier) était impossible. Il a suggéré d'importer le fichier dans chaque lambda .js (ce que j'avais déjà fait). Il ne semble pas, cependant, que le client Firebase vous permette de charger les identifiants via une importation.

Mis à part cela, Dennis a plus ou moins suggéré que ce n'était peut-être pas vraiment l'approche que je devrais prendre, de toute façon. Il avait raison. La seule raison pour laquelle je suis passé par cette voie était que je suivais l'un des exemples de Netlify, mais remplacer le package faunadb par apollo-server-lambda aurait peut-être ajouté beaucoup plus de poids aux fonctions lambda ; si c'est le cas, cela aurait probablement un impact sur les temps de démarrage lors des démarrages à froid.

Abandonner les fonctions lambda

Les fonctions lambda ne sont pas une solution pour tout. Dans mon cas, je voulais simplement un magasin de données simple avec une interface GraphQL, sans exposer les requêtes GraphQL dans la console du navigateur.

Je peux atteindre les mêmes objectifs en ayant un processus Node héberger à la fois un client React et un serveur GraphQL. Je suis (presque) certain que je ne rencontrerai aucun problème d'accès au système de fichiers, et si c'est le cas, je passerai à une autre méthode d'authentification.