Site icon Blog ARC Optimizer

Créer une application de bookmarking avec FaunaDB, Netlify et 11ty


À propos de l'auteur

Bryan est un concepteur, développeur et éducateur passionné de CSS et de sites statiques. Il travaille activement à encadrer et à enseigner aux développeurs et concepteurs la valeur…
Plus d'informations sur
Bryan
Robinson

Dans cet article, nous allons créer un site de bookmarking personnel à l'aide de FaunaDB, de Netlify Functions et de 11 fichiers de données.

La révolution JAMstack (JavaScript, les API et les balises) bat son plein. Les sites statiques sont sécurisés, rapides, fiables et amusants. Au cœur du JAMstack se trouvent des générateurs de sites statiques (SSG) qui stockent vos données sous forme de fichiers à plat: Markdown, YAML, JSON, HTML, etc. Parfois, gérer les données de cette manière peut être excessivement compliqué. Parfois, nous avons toujours besoin d’une base de données.

Dans cet esprit, Netlify – un hôte de site statique et FaunaDB – une base de données en nuage sans serveur – ont collaboré pour faciliter la combinaison des deux systèmes.

Pourquoi un site de bookmarking?

Le JAMstack convient à de nombreuses utilisations professionnelles, mais l'un de mes aspects préférés de cet ensemble de technologies est sa faible barrière d'accès aux outils et projets personnels.

de bons produits sur le marché pour la plupart des applications que je pourrais proposer, mais aucun ne serait exactement configuré pour moi. Personne ne me donnerait un contrôle total sur mon contenu. Aucun ne viendrait sans coût (monétaire ou informatif).

Dans cet esprit, nous pouvons créer nos propres mini-services à l'aide des méthodes JAMstack. Dans ce cas, nous allons créer un site pour stocker et publier tous les articles intéressants que je lis dans mes lectures technologiques quotidiennes.

Je passe beaucoup de temps à lire des articles qui ont été partagés sur Twitter. Quand j'en aime un, je clique sur l'icône «cœur». Ensuite, en quelques jours, il est presque impossible de trouver des nouveaux favoris. Je veux construire quelque chose d'aussi proche de la facilité du «cœur», mais je le possède et le contrôle.

Comment allons-nous faire cela? Je suis heureux que vous ayez demandé.

Vous souhaitez obtenir le code? Vous pouvez le saisir sur Github ou simplement le déployer directement sur Netlify à partir de ce référentiel! Jetez un coup d’œil au produit fini ici .

Nos technologies

Fonctions d’hébergement sans serveur: Netlify

Pour les fonctions d’hébergement et sans serveur, nous utiliserons Netlify. En prime, avec la nouvelle collaboration mentionnée ci-dessus, la CLI de Netlify – «Netlify Dev» – se connectera automatiquement à FaunaDB et stockera nos clés d'API en tant que variables d'environnement.

Base de données: FaunaDB

FaunaDB est un NoSQL «sans serveur». base de données. Nous allons l’utiliser pour stocker nos données de marque-pages.

Static Site Generator: 11ty

Je suis un fervent partisan de HTML. De ce fait, le didacticiel n’utilisera pas le JavaScript frontal pour restituer nos signets. Au lieu de cela, nous utiliserons 11ty comme générateur de site statique. 11ty intègre une fonctionnalité de données qui permet d'extraire des données d'une API aussi facilement que d'écrire quelques fonctions JavaScript courtes.

Raccourcis iOS

Nous avons besoin d'un moyen simple de publier des données dans notre base de données. Dans ce cas, nous utiliserons l’application Raccourcis d’iOS. Cela pourrait également être converti en bookmarklet JavaScript sous Android ou sur un ordinateur de bureau.

Configuration de FaunaDB via Netlify Dev

Que vous soyez déjà inscrit à FaunaDB ou que vous deviez créer un nouveau compte, le moyen le plus simple de créer un compte. un lien entre FaunaDB et Netlify se fait via la CLI de Netlify: Netlify Dev. Vous pouvez trouver toutes les instructions de FaunaDB ici ou les suivantes:

Netlify Dev s'exécutant dans le projet final avec nos noms de variable d'environnement projection ( Grand aperçu )

Si ce n'est déjà fait, vous pouvez exécuter la commande suivante dans le terminal:

 npm install netlify-cli -g 

Depuis votre projet répertoire, exécutez les commandes suivantes:

 netlify init // Ceci connectera votre projet à un projet Netlify.

additifs netlify: créer une faune // Ceci installera "l'addon" de FaunaDB

netlify addons: auth fauna // Cette commande vous permettra de vous connecter ou de créer un compte.

Une fois tout cela connecté, vous pouvez exécuter netlify dev dans votre projet. Ceci exécutera tous les scripts de construction que nous avons configurés, mais se connectera également aux services Netlify et FaunaDB et récupérera les variables d'environnement nécessaires.

Création de nos premières données

À partir de là, nous allons nous connecter à FaunaDB et créer notre premier jeu de données. Nous allons commencer par créer une nouvelle base de données appelée "signets". Dans une base de données, nous avons Collections, Documents et Index.

Une capture d'écran de la console FaunaDB avec données ( Grand aperçu )

Une collection est un groupe de données catégorisé. Chaque donnée prend la forme d’un document. Un document est un "enregistrement unique et modifiable dans une base de données FaunaDB", selon la documentation de Fauna. Vous pouvez considérer les collections comme une table de base de données traditionnelle et un document comme une rangée.

Pour notre application, nous avons besoin d'une collection, que nous appellerons «liens». Chaque document de la «liens» Collection sera simple. Objet JSON avec trois propriétés. Pour commencer, nous allons ajouter un nouveau document que nous utiliserons pour créer notre première extraction de données.

 {
"url": "https://css-irl.info/debugging-css-grid-part-2- what-the-fraction/",
"pageTitle": "CSS {Dans la vraie vie} | Débogage de la grille CSS - Partie 2: Qu'est-ce que le Fr (action)?",
"description": "CSS In Real Life est un blog couvrant des sujets CSS et des extraits utiles de la plus belle langue du Web. Publié par Michelle Barker, développeur front-end chez Ordoo et CSS superfan."
} 

Cela crée la base des informations que nous devons extraire de nos signets et nous fournit également notre premier ensemble de données à intégrer à notre modèle.

Si vous êtes comme moi, vous souhaitez voyez tout de suite les fruits de votre travail. Obtenons quelque chose sur la page!

Installation de 11ty et extraction des données dans un modèle

Comme nous voulons que les signets soient restitués au format HTML et non récupérés par le navigateur, nous avons besoin de quelque chose pour le rendre. Il existe de nombreuses façons de le faire, mais pour la facilité et la puissance, j'aime utiliser le générateur de site statique 11ty.

Comme 11ty est un générateur de site statique JavaScript, nous pouvons l'installer via NPM.

 npm install - save @ 11ty / eleventy 

À partir de cette installation, nous pouvons exécuter onze ou onze --serve dans notre projet de devenir opérationnel.

Netlify Dev détectera souvent 11ty comme une exigence et exécutez la commande pour nous. Pour avoir ce travail – et vous assurer que vous êtes prêt à être déployé, nous pouvons également créer des commandes "servir" et "construire" dans notre package.json .

 "scripts": {
    "build": "npx eleventy",
    "servir": "npx eleventy --serve"
  } 

Fichiers de données de 11ty

La plupart des générateurs de sites statiques ont une idée d’un «fichier de données» intégré. Généralement, ces fichiers sont des fichiers JSON ou YAML qui vous permettent d'ajouter des informations supplémentaires sur votre site.

Dans 11ty, vous pouvez utiliser des fichiers de données JSON ou des fichiers de données JavaScript. En utilisant un fichier JavaScript, nous pouvons réellement effectuer nos appels d'API et renvoyer les données directement dans un modèle.

Le fichier sera un module JavaScript. Donc, pour que tout fonctionne, nous devons exporter nos données ou une fonction. Dans notre cas, nous allons exporter une fonction.

 module.exports = async function () {
    const data = mapBookmarks (attendez getBookmarks ());

    retourne data.reverse ()
} 

Décomposons cela. Notre travail principal ici a deux fonctions: mapBookmarks () et getBookmarks () .

La fonction getBookmarks () ira chercher nos données dans notre base de données FaunaDB et mapBookmarks () prendra un tableau de signets et le restructurera pour mieux fonctionner pour notre modèle. 19659005] Nous allons approfondir getBookmarks () .

getBookmarks ()

Premièrement, nous devrons installer et initialiser une instance du pilote JavaScript FaunaDB.

 npm install --save faunadb 

Maintenant que nous l'avons installé, ajoutons-le en haut de notre fichier de données. Ce code est directement issu de la documentation de Fauna .

 // Nécessite le module Fauna et configure le module de requête, que nous pouvons utiliser pour créer des requêtes personnalisées.
const faunadb = require ('faunadb'),
      q = faunadb.query;

// Une fois requis, nous avons besoin d'une nouvelle instance avec notre secret
var adminClient = new faunadb.Client ({
   secret: process.env.FAUNADB_SERVER_SECRET
});

Après cela, nous pouvons créer notre fonction. Nous allons commencer par créer notre première requête en utilisant des méthodes intégrées sur le pilote. Ce premier bit de code renverra les références de base de données que nous pouvons utiliser pour obtenir les données complètes de tous nos liens marqués d'un signet. Nous utilisons la méthode Paginate pour nous aider à gérer l’état du curseur si nous décidions de paginer les données avant de les transmettre à 11ty. Dans notre cas, nous allons simplement renvoyer toutes les références.

Dans cet exemple, je suppose que vous avez installé et connecté FaunaDB via l'interface de ligne de commande Netlify Dev. En utilisant ce processus, vous obtenez des variables d’environnement local des secrets de FaunaDB. Si vous ne l'avez pas installé de cette façon ou si vous n'avez pas exécuté netlify dev dans votre projet, vous aurez besoin d'un package tel que dotenv pour créer les variables d'environnement. Vous devrez également ajouter vos variables d’environnement à la configuration de votre site Netlify pour que les déploiements fonctionnent plus tard.

 adminClient.query (q.Paginate (
q.Match (// correspond à la référence ci-dessous
q.Ref ("indexes / all_links") // Référence pour faire correspondre, dans ce cas, notre index all_links
)
))
.then (response => {...}) 

Ce code renverra un tableau de tous nos liens sous forme de référence. Nous pouvons maintenant créer une liste de requêtes à envoyer à notre base de données.

 adminClient.query (...)
    .then ((response) => {
        const linkRefs = response.data; // Obtient uniquement les références pour les liens de la réponse
        const getAllLinksDataQuery = linkRefs.map ((ref) => {
        return q.Get (ref) // Retourne une requête Get basée sur la référence transmise
})

retourne adminClient.query (getAllLinksDataQuery) .then (ret => {
    return ret // Retourne un tableau de tous les liens avec toutes les données
})
}). catch (...) 

À partir de là, il suffit de nettoyer les données renvoyées. C'est là que mapBookmarks () entre en jeu!

mapBookmarks ()

Dans cette fonction, nous traitons deux aspects des données.

Premièrement, nous obtenons une dateTime gratuite dans FaunaDB. Pour toute donnée créée, il existe une propriété timestamp ( ts ). Il n’est pas formaté de manière à rendre le filtre de date par défaut de Liquid plus facile, alors corrigeons-le.

 function mapBookmarks (data) {
    retourne data.map (bookmark => {
        const dateTime = new Date (bookmark.ts / 1000);
        ...
    })
} 

Cela fait, nous pouvons créer un nouvel objet pour nos données. Dans ce cas, il aura une propriété time et nous utiliserons l'opérateur Spread pour déstructurer notre objet data afin de les faire vivre tous à un niveau.

 mapBookmarks (Les données) {
    retourne data.map (bookmark => {
        const dateTime = new Date (bookmark.ts / 1000);

        return {time: dateTime, ... bookmark.data}
    })
} 

Voici nos données avant notre fonction:

 {
  ref: Ref (Collection ("links"), "244778237839802888"),
  ts: 1569697568650000,
  
  Les données: {
    URL: 'https://sample.com',
    pageTitle: 'Sample title',
    description: 'Une description échappée va ici'
  }
}

Voici nos données après notre fonction:

 {
    temps: 1569697568650,
    URL: 'https://sample.com',
    pageTitle: 'Sample title'
    description: 'Une description échappée va ici'
}

Nous disposons maintenant de données correctement formatées et prêtes pour notre modèle!

Écrivons un modèle simple. Nous allons parcourir nos signets et valider qu’ils ont chacun un pageTitle et un url afin que nous n’ayons pas l’air ridicule.

{% for link in bookmarks%}        {% if link.url et link.pageTitle%} // confirme que le titre ET l’URL de sécurité         

{{link.pageTitle}}

Enregistré le {{link.time | date: "% b% d,% Y"}}

            {% if link.description! = ""%}                 

{{link.description}}

            {% fin si %}         
       {% fin si %}    {% endfor%}

Nous sommes en train d’obtenir et d’afficher les données de FaunaDB. Prenons un instant pour réfléchir à la beauté du rendu HTML pur et à l’inutilité de récupérer des données côté client!

Mais cela n’est pas suffisant pour en faire une application utile pour nous. Trouvons un meilleur moyen que d’ajouter un signet dans la console FaunaDB.

Entrée des fonctions Netlify

Le module complémentaire Fonctions de Netlify est l’un des moyens les plus simples de déployer des fonctions AWS lambda. Comme il n'y a pas d'étape de configuration, il est parfait pour les projets de bricolage pour lesquels vous souhaitez simplement écrire le code.

Cette fonction utilisera une URL de votre projet ressemblant à ceci: https://myproject.com/. netlify / functions / bookmarks en supposant que le fichier créé dans notre dossier de fonctions est bookmarks.js .

Basic Flow

  1. Transmettez une URL en tant que paramètre de requête à notre URL de fonction.
  2. ] Utilisez la fonction pour charger l'URL et gratter le titre et la description de la page, le cas échéant.
  3. Formater les détails pour FaunaDB
  4. Transférer les détails dans notre collection FaunaDB.
  5. Reconstruire le site.

Configuration requise

19659015] Nous avons besoin de quelques paquets pour le construire. Nous allons utiliser la CLI netlify-lambda pour créer nos fonctions localement. request-promise est le package que nous utiliserons pour formuler des demandes. Cheerio.js est le package que nous allons utiliser pour extraire des éléments spécifiques de la page demandée (pensez à jQuery for Node). Enfin, nous aurons besoin de FaunaDb (qui devrait déjà être installé.
 npm install --save netlify-lambda request-promise cheerio 

Une fois l’installation terminée, configurons notre projet pour créer et servir les fonctions localement. [19659005] Nous allons modifier nos scripts "build" et "serve" dans notre package.json pour qu'ils se présentent comme suit:

 "scripts": {
    "build": "npx netlify-lambda build lambda --config ./webpack.functions.js && npx eleventy",
    "servir": "npx netlify-lambda construire lambda --config ./webpack.functions.js && npx eleventy --serve"
}

Avertissement: Lors de la compilation avec Webpack, une erreur est survenue avec le pilote NodeJS de Fauna, que les fonctions de Netlify utilisent pour créer. Pour contourner ce problème nous devons définir un fichier de configuration pour Webpack. Vous pouvez enregistrer le code suivant dans un nouveau ou un existant webpack.config.js .

 const webpack = require ('webpack');

module.exports = {
  plugins: [ new webpack.DefinePlugin({ "global.GENTLY": false }) ]
}; 

Une fois que ce fichier existe, lorsque vous utilisez la commande netlify-lambda nous devons lui indiquer de fonctionner à partir de cette configuration. C’est pourquoi nos scripts «serve» et «build» utilisent la valeur - config pour cette commande.

Function Housekeeping

Afin de garder notre fichier de fonction principal aussi propre que possible, nous ' Nous allons créer nos fonctions dans un répertoire de signets séparé et les importer dans notre fichier de fonctions principal.

 import {getDetails, saveBookmark} depuis "./bookmarks/create"; 

getDetails (url) [url)

La fonction getDetails () prendra une URL, transmise par notre gestionnaire exporté. À partir de là, nous contacterons le site à cette URL et saisirons les parties pertinentes de la page à stocker en tant que données pour notre signet.

Nous commençons par exiger les packages NPM dont nous avons besoin:

 const rp = require ( «demande-promesse»);
const cheerio = require ('cheerio'); 

Ensuite, nous utiliserons le module requête-promesse pour renvoyer une chaîne HTML pour la page demandée et la transférer dans cheerio pour nous donner une interface très jQuery-esque.

 const getDetails = async function (url) {
    const données = rp (url) .then (function (htmlString) {
        const $ = cheerio.load (htmlString);
        ...
} 

À partir de là, nous devons obtenir le titre de la page et une méta-description. Pour ce faire, nous utiliserons des sélecteurs comme vous le feriez dans jQuery.

Note: Dans ce code, nous utilisons 'tête> titre' comme sélecteur pour obtenir le titre de la page. Si vous ne spécifiez pas cela, vous risquez de finir par avoir balises à l'intérieur de tous les SVG de la page, ce qui n'est pas idéal.

 const getDetails = fonction asynchrone (url ) {
  const données = rp (url) .then (function (htmlString) {
    const $ = cheerio.load (htmlString);
    const title = $ ('head> title'). text (); // Récupère le texte dans la balise
    const description = $ ('meta [name="description"]'). attr ('contenu'); // Récupère le texte de l'attribut content

// Retourne les données dans la structure attendue
    revenir {
      pageTitle: titre,
      description: description
    };
  });
  retourne les données // retourne à notre fonction principale
} 

Les données en main, il est temps d'envoyer notre marque-page à notre collection dans FaunaDB!

saveBookmark (détails)

Pour notre fonction de sauvegarde, nous souhaitons transmettre les informations que nous avons acquises. de getDetails ainsi que de l'URL en tant qu'objet singulier. L'opérateur Spread frappe à nouveau!

 const saveResponse = wait saveBookmark ({url, ... details}); 

Dans notre fichier create.js nous avons également besoin d'exiger et de configurer notre FaunaDB. chauffeur. Cela devrait sembler très familier dans notre fichier de données 11ty.

 const faunadb = require ('faunadb'),
      q = faunadb.query;

const adminClient = new faunadb.Client ({
   secret: process.env.FAUNADB_SERVER_SECRET
});

Une fois que nous avons résolu le problème, nous pouvons coder.

Premièrement, nous devons formater nos détails dans une structure de données que Fauna attend pour notre requête. Fauna attend un objet avec une propriété data contenant les données que nous souhaitons stocker.

 const saveBookmark = fonction asynchrone (détails) {
const data = {
données: détails
};

...

} 

Ensuite, nous ouvrirons une nouvelle requête à ajouter à notre collection. Dans ce cas, nous utiliserons notre assistant de requête et utiliserons la méthode Create. Create () prend deux arguments. La première est la collection dans laquelle nous voulons stocker nos données et la seconde, les données elles-mêmes.

Après la sauvegarde, nous renvoyons le succès ou l'échec à notre gestionnaire.

 const saveBookmark = fonction asynchrone (détails) {
const data = {
   données: détails
};

retourne adminClient.query (q.Create (q.Collection ("links"), data))
   .then ((response) => {
        /* Succès! renvoyer la réponse avec statusCode 200 * /
        revenir {
             statusCode: 200,
             body: JSON.stringify (réponse)
         }
     }). catch ((error) => {
        /* Erreur! renvoyer l'erreur avec statusCode 400 * /
        revenir  {
             statusCode: 400,
             body: JSON.stringify (erreur)
         }
     })
} 

Jetons un coup d’œil au fichier de fonction complet.

 import {getDetails, saveBookmark} de "./bookmarks/create";
importer {rebuildSite} à partir de "./utilities/rebuild"; // Pour reconstruire le site (plus de détails dans une minute)

exports.handler = fonction async (événement, contexte) {
    essayer {
        const url = event.queryStringParameters.url; // récupère l'URL

        const details = wait getDetails (url); // Récupère les détails de la page
        const savedResponse = wait saveBookmark ({url, ... details}); // Sauvegarder l'URL et les détails dans la faune

        if (savedResponse.statusCode === 200) {
            // En cas de succès, renvoie le résultat et déclenche une construction Netlify
            attendez rebuildSite ();
            return {statusCode: 200, body: savedResponse.body}
         } autre {
            return savedResponse // sinon renvoie l'erreur
         }
     } catch (err) {
        return {statusCode: 500, body: `Erreur: $ {err}`};
     }
};

rebuildSite ()

L'oeil averti remarquera que nous avons une fonction supplémentaire importée dans notre gestionnaire: rebuildSite () . Cette fonction utilisera la fonctionnalité Déployer le crochet de Netlify pour reconstruire notre site à partir des nouvelles données chaque fois que nous soumettons une nouvelle sauvegarde de signet réussie.

Dans les paramètres de votre site dans Netlify, vous pouvez accéder à vos paramètres de création et de déploiement et créer un nouveau. «Construire le crochet». Les crochets ont un nom qui apparaît dans la section Déployer et une option pour une branche non maîtresse à déployer si vous le souhaitez. Dans notre cas, nous l'appelons «new_link» et déployons notre branche principale.

Référence visuelle pour la configuration du crochet de construction de Netlify Admin ( Grand aperçu )

À partir de là, il suffit d'envoyer une demande POST à ​​l'URL fournie.

Nous avons besoin d'un moyen de faire des demandes et depuis que nous avons déjà installé demande-promesse nous continuerons d'utiliser ce paquet en l'exigeant en haut de notre fichier.

 const rp = require ('request-promise');

const rebuildSite = fonction async () {
    var options = {
         méthode: 'POST',
         uri: 'https://api.netlify.com/build_hooks/5d7fa6175504dfd43377688c',
         corps: {},
         json: true
    };

    const retourné = wait rp (options) .then (function (res) {
         console.log ('Accédez avec succès à webhook', res);
     }). catch (function (err) {
         console.log ('Erreur:', err);
     });

    retour rendu
}
Une démonstration de la configuration de la fonction Netlify et de la configuration du raccourci iOS combinées

Configuration d'un raccourci iOS

Nous avons donc une base de données, un moyen d'afficher des données et une fonction pour ajouter des données, mais nous

Netlify fournit des URL pour nos fonctions Lambda, mais elles ne sont pas amusantes à saisir sur un appareil mobile. Nous devons également lui passer une URL en tant que paramètre de requête. C’est BEAUCOUP d’effort. Comment pouvons-nous faire cela aussi peu d'effort que possible?

Une référence visuelle pour la configuration de notre fonctionnalité de raccourci ( Grand aperçu )

L'application Raccourcis d'Apple permet de créer des éléments personnalisés dans votre feuille de partage. À l'intérieur de ces raccourcis, nous pouvons envoyer différents types de demandes de données collectées dans le processus de partage.

Voici le raccourci pas à pas:

  1. Acceptez tous les éléments et stockez-les dans un bloc de "texte". ] Transmettez ce texte dans un bloc «Scripting» en code d’URL (au cas où).
  2. Passez cette chaîne à un bloc d’URL avec l’URL de notre fonction Netlify et un paramètre de requête de url .
  3. Dans "Réseau", utilisez un bloc "Obtenir le contenu" pour envoyer à notre URL une requête POST vers JSON.
  4. Facultatif: à partir de "Script", affichez le contenu de la dernière étape (pour confirmer les données que nous envoyons). [19659153] Pour y accéder depuis le menu de partage, nous ouvrons les paramètres de ce raccourci et basculons sur l’option «Afficher dans la feuille de partage».

    Depuis iOS13, ces «Actions» de partage peuvent être favorisées et déplacées vers un position haute dans le dialogue.

    Nous avons maintenant une application qui permet de partager des signets sur plusieurs plates-formes!

    Si vous êtes tenté d’essayer vous-même, il existe de nombreuses autres possibilités d’ajout de fonctionnalités. Le bricolage sur le Web a le plaisir de pouvoir utiliser ce type d’applications pour vous. Voici quelques idées:

    1. Utilisez une fausse «clé API» pour une authentification rapide, afin que les autres utilisateurs ne publient pas sur votre site (le mien utilise une clé API, alors n'essayez pas de la publier!). 19659088] Ajoutez une fonctionnalité de balise pour organiser les signets.
    2. Ajoutez un flux RSS pour votre site afin que d'autres puissent s'abonner.
    3. Envoyez un courrier électronique hebdomadaire par programme aux liens que vous avez ajoutés.

    Vraiment, le ciel est la limite, alors commencez à expérimenter!

    (dm, yk)




Source link
Quitter la version mobile