Démo en direct : lien
Sauter à quoi de neuf?
Un chauffe-plaque pour les applications Web Node.js.
Si vous avez assisté à des hackathons dans le passé, vous savez combien de temps il faut pour démarrer un projet: décidez quoi construire, choisissez un langage de programmation, choisissez un cadre Web, choisissez un cadre CSS. Un peu plus tard, vous pourriez avoir un projet initial sur GitHub, et ce n'est qu'alors que les autres membres de l'équipe peuvent commencer à contribuer. Ou que diriez-vous de faire quelque chose d'aussi simple que de vous connecter avec l'authentification Facebook ? Vous pouvez y passer des heures si vous n'êtes pas familier avec le fonctionnement d'Oauth 2.0.
Lorsque j'ai commencé ce projet, je me concentre sur la simplicité et la facilité d'utilisation . J'ai également essayé de le rendre aussi générique et réutilisable que possible pour couvrir la plupart des cas d'utilisation d'applications Web Hackathon, sans être trop spécifique. Dans le pire des cas, vous pouvez l'utiliser comme guide d'apprentissage pour vos projets, si par exemple, vous êtes seulement intéressé à vous connecter avec l'authentification Google et rien d'autre.
"Bien! Ce réadme seul est déjà or!"
- Adrian Le Bas
"Génial. Tout simplement génial."
- Steven Rueter
«Je l'utilise depuis un an maintenant et de nombreux projets, c'est une tablette de passerelle géniale et le projet est bien entretenu!»
- Kevin Granger
"Small World avec le projet de Sahat. Nous utilisons son démarreur de hackathon pour notre hackathon le week-end dernier et avons obtenu des prix. Re vraiment pratique!"
- Entretien candidat pour l'une des entreprises avec lesquelles je travaillais.
MongoDB (installation locale ou hébergée)
Node.js 18+
Outils de ligne de commande
Mac OS X: Xcode (ou OS X 10.9+ : xcode-select --install )
Windows: Visual Studio Code + Sous-système Windows pour Linux - Ubuntu ou Visual Studio
Ubuntu / Linux Mint: sudo apt-get install build-essential
Fedora : sudo dnf groupinstall "Development Tools"
OpenSUSE: sudo zypper install --type pattern devel_basis
Remarque: Si vous êtes nouveau dans Node ou Express, vous pouvez trouver Node.js & Express à partir de la série Scratch utile pour apprendre les bases de Node et Express. Alternativement, voici un autre excellent tutoriel pour les débutants complets - démarrer avec Node.js, express, mongodb.
Étape 1: Le moyen le plus simple de commencer est de cloner le référentiel:
# Get the latest snapshot
git clone https://github.com/sahat/hackathon-starter.git myproject
# Change directory
cd myproject
# Install NPM dependencies
npm install
# Then simply start your app
node app.js Remarque: Je recommande fortement d'installer Nodemon. Il regarde toute modification de votre application Node.js et redémarre automatiquement le serveur. Une fois installé, au lieu de node app.js , utilisez nodemon app.js Cela vous fera gagner beaucoup de temps à long terme, car vous n'aurez pas besoin de redémarrer manuellement le serveur chaque fois que vous apportez un petit changement de code. Pour installer, exécutez sudo npm install -g nodemon .
Étape 2: Obtenez des touches API et modifiez les configurations si nécessaire après avoir terminé l'étape 1 et installant localement MongoDB, vous devriez pouvoir accéder à l'application via un navigateur Web et utiliser des comptes utilisateur locaux. Cependant, certaines fonctions comme les intégrations d'API peuvent ne pas fonctionner correctement tant que vous n'obtenez pas de clés spécifiques auprès des fournisseurs de services. Les clés fournies dans le projet servent d'espaces réservés, et vous pouvez les conserver pour les fonctionnalités que vous n'utilisez pas actuellement. Pour intégrer les clés acquises dans l'application, vous avez deux options:
export comme ceci: export FACEBOOK_SECRET=xxxxxx . Cette méthode est considérée comme une meilleure pratique car elle réduit le risque d'inclure accidentellement vos secrets dans un référentiel de code..env.example : ouvrez le fichier .env.example et mettez à jour les clés d'espace réservé par les touches nouvellement acquises. Cette méthode a le risque de l'enregistrement accidentel de vos secrets aux références de code.Que faire et configurer:
Smtp
recaptcha
Oauth pour les connexions sociales (connecter avec / connecter avec)
Clés API pour les fournisseurs de services dans les exemples de l'API si vous prévoyez de les utiliser.
MongoDB Atlas
Adresse email
NGROK et HTTPS Si vous souhaitez utiliser une API qui a besoin de HTTPS pour fonctionner (par exemple Pinterest ou Facebook), vous devrez télécharger Ngrok. Démarrez Ngrok, définissez votre base_url sur l'adresse de transfert (c'est-à-dire https://3ccb-1234-abcd.ngrok-free.app ) et utilisez l'adresse de transfert pour accéder à votre application. Si vous utilisez un proxy comme Ngrok, vous pouvez obtenir une erreur de non-correspondance CSRF si vous essayez d'accéder à l'application sur http://localhost:8080 au lieu de l'adresse https: //...ngrok-libre.app.
Après avoir installé ou téléchargé le client Ngrok autonome, vous pouvez démarrer NGROK pour intercepter les données échangées sur le port 8080 avec ./ngrok http 8080 dans Linux ou ngrok http 8080 dans Windows.
Étape 3: Développez votre application et personnalisez l'expérience
Étape 4: Facultatif - Déployer vers la production Voir:
Vous devrez obtenir des informations d'identification appropriées (ID client, secret client, clé API ou nom d'utilisateur et mot de passe) pour l'API et le service. Voir l'étape 2 dans la section de démarrage pour plus d'informations.
Obtenez des informations d'identification SMTP auprès d'un fournisseur pour les e-mails transactionnels. Définissez les variables d'environnement SMTP_USER, SMTP_PASSWORD et SMTP_HOST. Lors de la sélection de l'hôte SMTP, gardez à l'esprit que l'application est configurée pour utiliser des transmissions SMTP sécurisées sur le port 465 de la boîte. Vous avez la flexibilité de sélectionner tout fournisseur qui convient à vos besoins ou de profiter de l'un des fournisseurs suivants, chacun offrant un niveau gratuit pour votre commodité.
| Fournisseur | Niveau gratuit | Site web |
|---|---|---|
| Sendgrid | 100 e-mails / jour gratuitement | https://sendgrid.com |
| Smtp2go | 1000 e-mails / mois gratuitement | https://www.smtp2go.com |
| Breve | 300 e-mails / jour gratuitement | https://www.brevo.com |
.env . Ces clés seront accessibles dans les paramètres, les clés recaptcha se déroulent si vous en avez à nouveau besoin plus tardhttp://localhost:8080 , etc.)http://localhost:8080/auth/google/callback ).envhttp://localhost:8080/auth/snapchat/callback ).env.env.env.envlocalhost dans les domaines de l'applicationhttp://localhost:8080 , etc.) sous URL du sitehttp://localhost:8080/auth/facebook/callback ) sous les uris de redirection OAuth valides Remarque: Après une connexion réussie avec Facebook, un utilisateur sera redirigé vers la page d'accueil avec un hachage annexe #_=_ dans l'URL. Ce n'est pas un bug. Voir cette discussion de débordement de pile pour les façons de le gérer.
http://localhost:8080 , etc.) comme URL de page d'accueil.http://localhost:8080/auth/github/callback ).envhttp://localhost:8080 , etc.).http://localhost:8080/auth/twitter/callback ).envhttp://localhost:8080/auth/linkedin/callback )http://localhost:8080 , etc.).r_basicprofile.env.env.envhttp://localhost:8080/auth/foursquare/callback ).envhttp://localhost:8080/auth/tumblr/callback ).env.envhttp://localhost:8080/auth/twitch/callback ).env.env.env ..env | Nom | Description |
|---|---|
| config /passport.js | Stratégies locales et OAuth du passeport, plus le middleware de connexion. |
| contrôleurs /api.js | Contrôleur pour / API Route et tous les exemples d'API. |
| contrôleurs /Contact.js | Contrôleur pour le formulaire de contact. |
| contrôleurs /home.js | Contrôleur pour la page d'accueil (index). |
| contrôleurs /user.js | Contrôleur pour la gestion des comptes d'utilisateurs. |
| modèles / user.js | Schéma de mangouste et modèle pour l'utilisateur. |
| publique / | Actifs statiques (polices, CSS, JS, IMG). |
| public / js /application.js | Spécifiez les dépendances JavaScript côté client. |
| public / js /app.js | Placez votre JavaScript côté client ici. |
| public / css /main.scss | Feuille de style principale pour votre application. |
| vues / compte / | Modèles de connexion, réinitialisation du mot de passe, inscription, profil . |
| vues / api / | Modèles pour des exemples d'API. |
| vues / partiels /flash.pug | Erreur, informations et succès Flash Notifications. |
| vues / partiels /headader.pug | Modèle partiel Navbar. |
| vues / partiels /footer.pug | Modèle partiel de pied de page. |
| vues /layout.pug | Modèle de base. |
| vues /home.pug | Modèle de page d'accueil. |
| .Dockagerignore | Dossier et fichiers ignorés par l'utilisation de Docker. |
| .env.example | Vos clés API, jetons, mots de passe et uri de base de données. |
| .eslintrc | Règles pour Eslint Linter. |
| .gitignore | Dossier et fichiers ignorés par Git. |
| app.js | Le fichier d'application principal. |
| docker-compose.yml | Docker composé le fichier de configuration. |
| Dockerfile | Fichier de configuration Docker. |
| package.json | Dépendances NPM. |
| package-lock.json | Contient des versions exactes des dépendances NPM dans package.json. |
Remarque: il n'y a aucune préférence sur la façon dont vous nommez ou structurez vos vues. Vous pouvez placer tous vos modèles dans un répertoire views de niveau supérieur sans avoir une structure de dossier imbriquée si cela vous facilite les choses. N'oubliez pas de mettre à jour extends ../layout et les chemins correspondants res.render() dans les contrôleurs.
| Emballer | Description |
|---|---|
| @ Fortawesome / Fontawesome-Free | Symbole et bibliothèque d'icônes. |
| @ googleapis / drive | Bibliothèque d'intégration de l'API Google Drive. |
| @ googleapis / feuilles | Bibliothèque d'intégration de l'API Google Sheets. |
| @ ladjs / bootstrap-social | Bibliothèque de boutons sociaux. |
| @ lob / lob-typescript-sdk | LOB (USPS Mailing / Physical Mailing Service) Bibliothèque. |
| @ Node-RS / Bcrypt | Bibliothèque pour hachage et salting des mots de passe utilisateur. |
| @ octokit / repos | Bibliothèque API GitHub. |
| @ Passport-js / Passport-Twitter | X (Twitter) Assistance de connexion (OAuth 2). |
| @ popperjs / noyau | Bibliothèque Frontend JS pour poppers et info-bullets. |
| axios | Client HTTP. |
| carrosserie | Nœud.js Analyse du corps middleware. |
| amorce | Framework CSS. |
| chai | Bibliothèque d'assurance BDD / TDD. |
| rafale | Scrapez les pages Web à l'aide de la syntaxe de style jQuery. |
| compression | Middleware de compression Node.js. |
| connexion-mongo | MongoDB Session Store pour Express. |
| dotenv | Charge les variables d'environnement du fichier .env. |
| ErrorHandler | Handler d'erreur de développement uniquement Middleware. |
| eslint | Linter JavaScript. |
| Eslint-Config-Airbnb-base | Configuration Eslint par Airbnb. |
| Eslint-Plugin-chai-amical | Rend Eslint amical avec les déclarations de chai.js «attendre» et «devraient». |
| Eslint-Plugin-Import | Plugin Eslint avec des règles qui aident à valider les importations appropriées. |
| exprimer | Framework Web Node.js. |
| flash express | Fournit des messages flash pour express. |
| limite de taux express | Taux limitant les middleware pour la protection contre les abus. |
| session expresse | Middleware de session simple pour Express. |
| rauque | Git Hook Manager pour automatiser les tâches avec GIT. |
| jquery | Bibliothèque JS frontale pour interagir avec les éléments HTML. |
| dernier | Last.FM API Library. |
| étape de charpie | Utilitaire aux fichiers de peluches mis en scène par GIT. |
| lob | Bibliothèque API LOB. |
| loger | Une bibliothèque utilitaire pour travailler avec des tableaux, des nombres, des objets, des chaînes. |
| lusque | Middleware CSRF. |
| cache-cocheur | Vérifie qu'une adresse e-mail est valide et non une adresse jetable. |
| moka | Framework de test. |
| moment | Analyse, valider, calculer les dates et les heures. |
| mongodbmemoryserver | MongoDB en mémoire (pour exécuter des tests sans DB en cours d'exécution). |
| mangouste | MongoDB ODM. |
| Morgan | Http Demande Logger Middleware pour Node.js. |
| mousse | Node.js middleware pour gérer multipart/form-data . |
| nodemaileur | Bibliothèque Node.js pour envoyer des e-mails. |
| New York | Test de couverture. |
| passeport | Bibliothèque d'authentification simple et élégante pour node.js. |
| Passeport-Facebook | Connexion avec le plugin Facebook. |
| passeport-github2 | Connexion avec le plugin GitHub. |
| passeport-google-oauth | Connexion avec le plugin Google. |
| Passport-Linkedin-OAuth2 | Connexion avec le plugin LinkedIn. |
| passeport-local | Connexion avec le nom d'utilisateur et le plugin de mot de passe. |
| passeport-oauth | Vous permet de configurer vos propres stratégies OAuth 1.0a et OAuth 2.0. |
| Passport-oauth2-reresh | Une bibliothèque pour actualiser les jetons d'accès OAuth 2.0 à l'aide de jetons de rafraîchissement. |
| passeport-snapchat | Connexion avec le plugin Snapchat. |
| pasport-steam-openide | Plugin à vapeur OpenID 2.0. |
| patch | Correction des modules de nœuds cassés avant les correctifs par les mainteneurs. |
| PayPal-Rest-Sdk | Bibliothèque API PayPal. |
| carlin | Moteur de modèle pour express. |
| toupet | Compilateur SASS pour générer des CSS avec des superpuissances |
| sinon | Testez des espions, des talons et des simulations pour JavaScript. |
| bande | Bibliothèque API à bande officielle. |
| super-test | Bibliothèque d'assurance HTTP. |
| twilio | Bibliothèque API Twilio. |
| switch-passport | Connexion avec le plugin Twitch. |
| validateur | Une bibliothèque de validateurs de cordes et de désinfectants. |
filesize(265318); // "265.32 kB" .var token = _.find(req.user.tokens, { kind: 'twitter' }); , où le 1er paramètre est un tableau, et un 2ème paramètre est un objet à rechercher. 403 Error: Forbidden lors de la soumission d'un formulaire?Vous devez ajouter l'élément d'entrée caché suivant à votre formulaire. Cela a été ajouté dans la demande de traction n ° 40 dans le cadre de la protection CSRF.
input(type='hidden', name='_csrf', value=_csrf)
Remarque: il est désormais possible de la liste blanche certaines URL. En d'autres termes, vous pouvez spécifier une liste des itinéraires qui devraient contourner la vérification de vérification CSRF.
Remarque 2: Aux URL dynamiques de liste blanche, utilisez des tests d'expression réguliers à l'intérieur du middleware CSRF pour voir si req.originalUrl correspond à votre modèle souhaité.
C'est un message d'erreur personnalisé défini dans app.js pour indiquer qu'il y avait un problème à se connecter à MongoDB:
mongoose . connection . on ( 'error' , ( err ) => {
console . error ( err ) ;
console . log ( '%s MongoDB connection error. Please make sure MongoDB is running.' , chalk . red ( '✗' ) ) ;
process . exit ( ) ;
} ) ; Vous devez avoir un serveur MongoDB en cours d'exécution avant de lancer app.js Vous pouvez télécharger MongoDB ici ou l'installer via un gestionnaire de packages. Utilisateurs de Windows, lisez Installer MongoDB sur Windows.
Astuce: Si vous êtes toujours connecté à Internet, vous pouvez simplement utiliser MongoDB Atlas au lieu de télécharger et d'installer MongoDB localement. Vous n'aurez besoin que de mettre à jour les informations d'identification de la base de données dans le fichier .env .
Il y a de fortes chances que vous n'ayez pas modifié la base de données URI dans .env . Si MONGODB est défini sur localhost , cela ne fonctionnera que sur votre machine tant que MongoDB fonctionne. Lorsque vous vous déploiez pour rendre, opensift ou un autre fournisseur, vous n'aurez pas MongoDB en cours d'exécution sur localhost . Vous devez créer un compte avec MongoDB Atlas, puis créer une base de données de niveau libre. Voir le déploiement pour plus d'informations sur la création d'un compte et une nouvelle base de données étape par étape avec MongoDB Atlas.
Par souci de simplicité. Bien qu'il puisse y avoir une meilleure approche, comme passer le contexte app à chaque contrôleur, comme indiqué dans ce blog, je trouve qu'un tel style est déroutant pour les débutants. Il m'a fallu beaucoup de temps pour saisir le concept d' exports et module.exports , et encore moins d'avoir une référence app globale dans d'autres fichiers. Pour moi, c'est en arrière. L' app.js est le "cœur de l'application", ce devrait être celui qui référence des modèles, des routes, des contrôleurs, etc. Lorsque vous travaillez en solo sur de petits projets, je préfère avoir tout dans app.js . comme c'est le cas avec ce serveur API REST.
Cette section est destinée à vous donner une explication détaillée du fonctionnement d'une fonctionnalité particulière. Peut-être que vous êtes juste curieux de savoir comment cela fonctionne, ou peut-être que vous êtes perdu et confus en lisant le code, j'espère que cela vous fournit quelques conseils.
HTML5 UP a de nombreux modèles magnifiques que vous pouvez télécharger gratuitement.
Lorsque vous téléchargez le fichier zip, il sera livré avec des dossiers index.html , images , CSS et JS . Alors, comment l'intégrez-vous avec Hackathon Starter? Hackathon Starter utilise le framework Bootstrap CSS, mais ces modèles ne le font pas. Essayer d'utiliser les deux fichiers CSS en même temps entraînera probablement des effets indésirables.
Remarque: En utilisant l'approche des modèles personnalisés, vous devez comprendre que vous ne pouvez pas réutiliser les vues que j'ai créées: mise en page, page d'accueil, navigateur API, connexion, inscription, gestion du compte, contact. Ces vues ont été construites à l'aide de la grille et des styles bootstrap. Vous devrez mettre à jour manuellement la grille à l'aide d'une syntaxe différente fournie dans le modèle. Cela dit, vous pouvez mélanger et assortir si vous voulez le faire: utilisez Bootstrap pour l'interface d'application principale et un modèle personnalisé pour une page de destination.
Commençons par le début. Pour cet exemple, j'utiliserai le modèle de vitesse d'échappement:
Remarque: Par souci de simplicité, je ne considérerai index.html et sauterai left-sidebar.html , no-sidebar.html , right-sidebar.html .
Déplacez tous les fichiers JavaScript de html5up-escape-velocity/js vers public/js . Ensuite, déplacez tous les fichiers CSS de html5up-escape-velocity/css vers public/css . Et enfin, déplacez toutes les images de html5up-escape-velocity/images en public/images . Vous pouvez le déplacer vers le dossier IMG existant, mais cela nécessiterait de changer manuellement chaque référence img . Saisissez le contenu de index.html et collez-le dans HTML à PUG.
Remarque: n'oubliez pas de mettre à jour tous les chemins CSS et JS en conséquence.
Créez un nouveau fichier escape-velocity.pug et collez le dossier PUG BUNKUP dans views . Chaque fois que vous voyez le code res.render('account/login') - cela signifie qu'il recherchera views/account/login.pug .
Voyons à quoi ça ressemble. Créez un nouveau contrôleur EscapeVelocity à l'intérieur controllers/home.js :
exports . escapeVelocity = ( req , res ) => {
res . render ( 'escape-velocity' , {
title : 'Landing Page'
} ) ;
} ; Puis créer une route dans app.js Je l'ai placé juste après le contrôleur d'index:
app . get ( '/escape-velocity' , homeController . escapeVelocity ) ; Redémarrez le serveur (si vous n'utilisez pas NODEMON ); Ensuite, vous devriez voir le nouveau modèle sur http://localhost:8080/escape-velocity
Je m'arrêterai ici, mais si vous souhaitez utiliser ce modèle comme plus qu'une seule page, jetez un œil à la façon dont ces modèles de carburant fonctionnent: layout.pug - Modèle de base, index.pug - Page d'accueil, partials/header.pug - Bootstrap Navbar, partials/footer.pug footer. Vous devrez le séparer manuellement en petits morceaux. Déterminez quelle partie du modèle que vous souhaitez conserver sur toutes les pages - c'est votre nouvelle layout.pug . Ensuite, chaque page qui change, que ce soit index.pug , about.pug , contact.pug sera intégré dans votre nouvelle layout.pug via block content . Utilisez des modèles existants comme référence.
Il s'agit d'un processus assez long, et les modèles que vous obtenez d'ailleurs pourraient avoir un autre système de grille. C'est pourquoi j'ai choisi Bootstrap pour le démarreur de hackathon. Beaucoup de gens connaissent déjà Bootstrap , et il est facile de commencer avec cela si vous n'avez jamais utilisé Bootstrap . Vous pouvez également acheter de nombreux thèmes de bootstrap magnifiquement conçus à Themeforest, et les utiliser en remplacement de hackathon. Cependant, si vous souhaitez aller avec un design HTML / CSS complètement personnalisé, cela devrait vous aider à démarrer!
Les messages flash vous permettent d'afficher un message à la fin de la demande et d'y accéder à la demande suivante et uniquement la demande suivante. Par exemple, lors d'une tentative de connexion ratée, vous afficheriez une alerte avec un message d'erreur, mais dès que vous actualirez cette page ou visitez une autre page et revenez à la page de connexion, ce message d'erreur sera parti. Il n'est affiché qu'une seule fois. Ce projet utilise un module express-flash pour les messages flash. Et ce module est construit sur Connect-Flash , ce que j'ai utilisé dans ce projet initialement. Avec Express-Flash, vous n'avez pas à envoyer explicitement un message Flash à chaque vue dans res.render() . Tous les messages Flash sont disponibles dans vos vues via l'objet messages par défaut, grâce à Express-Flash .
Les messages flash ont un processus en deux étapes. Vous utilisez req.flash('errors', { msg: 'Error messages goes here' } pour créer un message flash dans vos contrôleurs, puis les afficher dans vos vues:
if messages . errors
.alert.alert-danger.fade.in
for error in messages . errors
div = error . msg Dans la première étape, 'errors' sont le nom d'un message flash, qui devrait correspondre au nom de l'objet de la propriété sur messages dans vos vues. Vous placez des messages d'alerte à l'intérieur if message.errors car vous ne voulez pas leur montrer des messages flash sont présents. La raison pour laquelle vous passez une erreur comme { msg: 'Error message goes here' } au lieu d'une simple chaîne - 'Error message goes here' , est pour la cohérence. Pour clarifier que le module express-validator qui est utilisé pour valider et désinfecter l'entrée de l'utilisateur, renvoie toutes les erreurs en tant que tableau d'objets, où chaque objet a une propriété msg avec un message pour lesquels une erreur s'est produite. Voici un exemple plus général de ce que le validateur express renvoie lorsqu'il y a des erreurs présents:
[
{ param : "name" , msg : "Name is required" , value : "<received input>" } ,
{ param : "email" , msg : "A valid email is required" , value : "<received input>" }
] Pour rester cohérent avec ce style, vous devez transmettre tous les messages Flash en tant que { msg: 'My flash message' } au lieu d'une chaîne. Sinon, vous verrez une boîte d'alerte sans message d'erreur. En effet, dans le modèle partiels / flash.pug, il essaiera de sortir error.msg (c'est-à-dire "My flash message".msg ), en d'autres termes, il essaiera d'appeler une méthode msg sur un objet String , qui renverra indéfini . Tout ce que je viens de mentionner sur les erreurs, s'applique également aux messages flash "info" et "succès", et vous pourriez même en créer un nouveau vous-même, comme:
Contrôleur d'utilisation des données (exemple)
req.flash('warning', { msg: 'You have exceeded 90% of your data usage' });
Page de compte utilisateur (exemple)
if messages . warning
.alert.alert-warning.fade.in
for warning in messages . warning
div = warning . msg partials/flash.pug est un modèle partiel qui contient la façon dont les messages flash sont formatés. Auparavant, les messages flash étaient dispersés dans chaque vue qui utilisait des messages flash (contact, connexion, inscription, profil), mais maintenant, heureusement, il utilise une approche sèche .
Le modèle partiel des messages flash est inclus dans la layout.pug , ainsi que le pied de page et la navigation.
body
include partials/header
.container
include partials/flash
block content
include partials/footerSi vous avez d'autres questions sur les messages Flash, n'hésitez pas à ouvrir un problème, et je mettrai à jour ce mini-guide en conséquence, ou envoyez une demande de traction si vous souhaitez inclure quelque chose que j'ai manqué.
Une façon plus correcte de dire que ce serait "Comment créer un nouvel itinéraire?" Le fichier principal app.js contient tous les itinéraires. Each route has a callback function associated with it. Sometimes you will see three or more arguments for a route. In a case like that, the first argument is still a URL string, while middle arguments are what's called middleware. Think of middleware as a door. If this door prevents you from continuing forward, you won't get to your callback function. One such example is a route that requires authentication.
app . get ( '/account' , passportConfig . isAuthenticated , userController . getAccount ) ; It always goes from left to right. A user visits /account page. Then isAuthenticated middleware checks if you are authenticated:
exports . isAuthenticated = ( req , res , next ) => {
if ( req . isAuthenticated ( ) ) {
return next ( ) ;
}
res . redirect ( '/login' ) ;
} ; If you are authenticated, you let this visitor pass through your "door" by calling return next(); . It then proceeds to the next middleware until it reaches the last argument, which is a callback function that typically renders a template on GET requests or redirects on POST requests. In this case, if you are authenticated, you will be redirected to the Account Management page; otherwise, you will be redirected to the Login page.
exports . getAccount = ( req , res ) => {
res . render ( 'account/profile' , {
title : 'Account Management'
} ) ;
} ; Express.js has app.get , app.post , app.put , app.delete , but for the most part, you will only use the first two HTTP verbs, unless you are building a RESTful API. If you just want to display a page, then use GET , if you are submitting a form, sending a file then use POST .
Here is a typical workflow for adding new routes to your application. Let's say we are building a page that lists all books from the database.
Step 1. Start by defining a route.
app . get ( '/books' , bookController . getBooks ) ;Note: As of Express 4.x you can define your routes like so:
app . route ( '/books' )
. get ( bookController . getBooks )
. post ( bookController . createBooks )
. put ( bookController . updateBooks )
. delete ( bookController . deleteBooks )And here is how a route would look if it required an authentication and an authorization middleware:
app . route ( '/api/twitter' )
. all ( passportConfig . isAuthenticated )
. all ( passportConfig . isAuthorized )
. get ( apiController . getTwitter )
. post ( apiController . postTwitter ) Use whichever style makes sense to you. Either one is acceptable. I think that chaining HTTP verbs on app.route is a very clean and elegant approach, but on the other hand, I can no longer see all my routes at a glance when you have one route per line.
Step 2. Create a new schema and a model Book.js inside the models directory.
const mongoose = require ( 'mongoose' ) ;
const bookSchema = new mongoose . Schema ( {
name : String
} ) ;
const Book = mongoose . model ( 'Book' , bookSchema ) ;
module . exports = Book ; Step 3. Create a new controller file called book.js inside the controllers directory.
/**
* GET /books
* List all books.
*/
const Book = require ( '../models/Book.js' ) ;
exports . getBooks = ( req , res ) => {
Book . find ( ( err , docs ) => {
res . render ( 'books' , { books : docs } ) ;
} ) ;
} ; Step 4. Import that controller in app.js .
const bookController = require ( './controllers/book' ) ; Step 5. Create books.pug template.
extends layout
block content
.page-header
h3 All Books
ul
for book in books
li = book . nameC'est ça! I will say that you could have combined Step 1, 2, 3 as following:
app . get ( '/books' , ( req , res ) => {
Book . find ( ( err , docs ) => {
res . render ( 'books' , { books : docs } ) ;
} ) ;
} ) ; Sure, it's simpler, but as soon as you pass 1000 lines of code in app.js it becomes a little challenging to navigate the file. I mean, the whole point of this boilerplate project was to separate concerns, so you could work with your teammates without running into MERGE CONFLICTS . Imagine you have four developers working on a single app.js , I promise you it won't be fun resolving merge conflicts all the time. If you are the only developer, then it's okay. But as I said, once it gets up to a certain LoC size, it becomes difficult to maintain everything in a single file.
That's all there is to it. Express.js is super simple to use. Most of the time you will be dealing with other APIs to do the real work: Mongoose for querying database, socket.io for sending and receiving messages over WebSockets, sending emails via Nodemailer, form validation using validator.js library, parsing websites using Cheerio, etc.
Dan Stroot submitted an excellent pull request that adds a real-time dashboard with socket.io. And as much as I'd like to add it to the project, I think it violates one of the main principles of the Hackathon Starter:
When I started this project, my primary focus was on simplicity and ease of use. I also tried to make it as generic and reusable as possible to cover most use cases of hackathon web apps, without being too specific .
When I need to use socket.io, I really need it, but most of the time - I don't. But more importantly, WebSockets support is still experimental on most hosting providers. Due to past provider issues with WebSockets, I have not include socket.io as part of the Hackathon Starter. For now... If you need to use socket.io in your app, please continue reading.
First, you need to install socket.io:
npm install socket . io Replace const app = express(); avec le code suivant:
const app = express ( ) ;
const server = require ( 'http' ) . Server ( app ) ;
const io = require ( 'socket.io' ) ( server ) ; I like to have the following code organization in app.js (from top to bottom): module dependencies, import controllers, import configs, connect to database, express configuration, routes, start the server, socket.io stuff. That way I always know where to look for things.
Add the following code at the end of app.js :
io . on ( 'connection' , ( socket ) => {
socket . emit ( 'greet' , { hello : 'Hey there browser!' } ) ;
socket . on ( 'respond' , ( data ) => {
console . log ( data ) ;
} ) ;
socket . on ( 'disconnect' , ( ) => {
console . log ( 'Socket disconnected' ) ;
} ) ;
} ) ;One last thing left to change:
app . listen ( app . get ( 'port' ) , ( ) => {à
server . listen ( app . get ( 'port' ) , ( ) => {At this point, we are done with the back-end.
You now have a choice - to include your JavaScript code in Pug templates or have all your client-side JavaScript in a separate file - in app.js . I admit, when I first started with Node.js and JavaScript in general, I placed all JavaScript code inside templates because I have access to template variables passed in from Express right then and there. It's the easiest thing you can do, but also the least efficient and harder to maintain. Since then I almost never include inline JavaScript inside templates anymore.
But it's also understandable if you want to take the easier road. Most of the time you don't even care about performance during hackathons, you just want to "get shit done" before the time runs out. Well, either way, use whichever approach makes more sense to you. At the end of the day, it's what you build that matters, not how you build it.
If you want to stick all your JavaScript inside templates, then in layout.pug - your main template file, add this to head block.
script ( src = '/socket.io/socket.io.js' )
script .
let socket = io . connect ( window . location . href );
socket . on ( ' greet ' , function ( data ) {
console . log (data);
socket . emit ( ' respond ' , { message : ' Hey there, server! ' });
}); Note: Notice the path of the socket.io.js , you don't actually have to have socket.io.js file anywhere in your project; it will be generated automatically at runtime.
If you want to have JavaScript code separate from templates, move that inline script code into app.js , inside the $(document).ready() function:
$ ( document ) . ready ( function ( ) {
// Place JavaScript code here...
let socket = io . connect ( window . location . href ) ;
socket . on ( 'greet' , function ( data ) {
console . log ( data ) ;
socket . emit ( 'respond' , { message : 'Hey there, server!' } ) ;
} ) ;
} ) ;And we are done!
Declares a read-only named constant.
const name = 'yourName' ;Declares a block scope local variable.
let index = 0 ; Using the `${}` syntax, strings can embed expressions.
const name = 'Oggy' ;
const age = 3 ;
console . log ( `My cat is named ${ name } and is ${ age } years old.` ) ; To import functions, objects, or primitives exported from an external module. These are the most common types of importing.
const name = require ( 'module-name' ) ; const { foo , bar } = require ( 'module-name' ) ;To export functions, objects, or primitives from a given file or module.
module . exports = { myFunction } ; module . exports . name = 'yourName' ; module . exports = myFunctionOrClass ; The spread operator allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) are expected.
myFunction ( ... iterableObject ) ; < ChildComponent { ... this . props } /> A Promise is used in asynchronous computations to represent an operation that hasn't completed yet but is expected in the future.
var p = new Promise ( function ( resolve , reject ) { } ) ; The catch() method returns a Promise and deals with rejected cases only.
p . catch ( function ( reason ) { /* handle rejection */ } ) ; The then() method returns a Promise. It takes two arguments: callback for the success & failure cases.
p . then ( function ( value ) { /* handle fulfillment */ } , function ( reason ) { /* handle rejection */ } ) ; The Promise.all(iterable) method returns a promise that resolves when all of the promises in the iterable argument have resolved or rejects with the reason of the first passed promise that rejects.
Promise . all ( [ p1 , p2 , p3 ] ) . then ( function ( values ) { console . log ( values ) } ) ; Arrow function expression. Shorter syntax & lexically binds the this value. Arrow functions are anonymous.
singleParam => { statements } ( ) => { statements } ( param1 , param2 ) => expression const arr = [ 1 , 2 , 3 , 4 , 5 ] ;
const squares = arr . map ( x => x * x ) ; The class declaration creates a new class using prototype-based inheritance.
class Person {
constructor ( name , age , gender ) {
this . name = name ;
this . age = age ;
this . gender = gender ;
}
incrementAge ( ) {
this . age ++ ;
}
}? Credits : DuckDuckGo and @DrkSephy.
? back to top
Math . floor ( Date . now ( ) / 1000 ) ; moment().unix();
var now = new Date ( ) ;
now . setMinutes ( now . getMinutes ( ) + 30 ) ; moment().add(30, 'minutes');
// DD-MM-YYYY
var now = new Date ( ) ;
var DD = now . getDate ( ) ;
var MM = now . getMonth ( ) + 1 ;
var YYYY = now . getFullYear ( ) ;
if ( DD < 10 ) {
DD = '0' + DD ;
}
if ( MM < 10 ) {
MM = '0' + MM ;
}
console . log ( MM + '-' + DD + '-' + YYYY ) ; // 03-30-2016 console.log(moment(new Date(), 'MM-DD-YYYY'));
// hh:mm (12 hour time with am/pm)
var now = new Date ( ) ;
var hours = now . getHours ( ) ;
var minutes = now . getMinutes ( ) ;
var amPm = hours >= 12 ? 'pm' : 'am' ;
hours = hours % 12 ;
hours = hours ? hours : 12 ;
minutes = minutes < 10 ? '0' + minutes : minutes ;
console . log ( hours + ':' + minutes + ' ' + amPm ) ; // 1:43 am console.log(moment(new Date(), 'hh:mm A'));
var today = new Date ( ) ;
var nextWeek = new Date ( today . getTime ( ) + 7 * 24 * 60 * 60 * 1000 ) ; moment().add(7, 'days');
var today = new Date ( ) ;
var yesterday = date . setDate ( date . getDate ( ) - 1 ) ; moment().add(-1, 'days');
? back to top
User . find ( ( err , users ) => {
console . log ( users ) ;
} ) ; let userEmail = '[email protected]' ;
User . findOne ( { email : userEmail } , ( err , user ) => {
console . log ( user ) ;
} ) ; User
. find ( )
. sort ( { _id : - 1 } )
. limit ( 5 )
. exec ( ( err , users ) => {
console . log ( users ) ;
} ) ; Let's suppose that each user has a votes field and you would like to count the total number of votes in your database across all users. One very inefficient way would be to loop through each document and manually accumulate the count. Or you could use MongoDB Aggregation Framework instead:
User . aggregate ( { $group : { _id : null , total : { $sum : '$votes' } } } , ( err , votesCount ) => {
console . log ( votesCount . total ) ;
} ) ;? back to top
You will need to install docker and docker-compose on your system. If you are using WSL, you will need to install Docker Desktop on Windows and docker-compose on WSL.
Docker installation
Common problems setting up docker
After installing docker, start the application with the following commands :
# To build the project while supressing most of the build messages
docker-compose build web
# To build the project without supressing the build messages or using cached data
docker-compose build --no-cache --progress=plain web
# To start the application (or to restart after making changes to the source code)
docker-compose up web
To view the app, find your docker IP address + port 8080 ( this will typically be http://localhost:8080/ ). To use a port other than 8080, you would need to modify the port in app.js, Dockerfile, and docker-compose.yml.
Once you are ready to deploy your app, you will need to create an account with a cloud platform to host it. These are not the only choices, but they are my top picks. Additionally, you can create an account with MongoDB Atlas and then pick one of the providers below. Again, there are plenty of other choices, and you are not limited to just the ones listed below.
Render provides free nodejs hosting for repos on Github and Gitlab.
0.0.0.0/0 . Click SAVE to save the 0.0.0.0/0 whitelist..env.example with this URI string. Make sure to replace the with the db User password that you created under the Security tab.We are deploying your changes . You will need to wait for the deployment to finish before using the DB in your application.sudo gem install rhc ?rhc login and enter your OpenShift credentialsrhc app create MyApp nodejs-0.10git remote add openshift YOUR_GIT_REMOTE Add these two lines to app.js , just place them anywhere before app.listen() :
var IP_ADDRESS = process . env . OPENSHIFT_NODEJS_IP || '127.0.0.1' ;
var PORT = process . env . OPENSHIFT_NODEJS_PORT || 8080 ; Then change app.listen() to:
app . listen ( PORT , IP_ADDRESS , ( ) => {
console . log ( `Express server listening on port ${ PORT } in ${ app . settings . env } mode` ) ;
} ) ; Add this to package.json , after name and version . This is necessary because, by default, OpenShift looks for server.js file. And by specifying supervisor app.js it will automatically restart the server when node.js process crashes.
"main" : "app.js" ,
"scripts" : {
"start" : "supervisor app.js"
} ,git push -f openshift master-f (force) flag because OpenShift creates a dummy server with the welcome page when you create a new Node.js app. Passing -f flag will override everything with your Hackathon Starter project repository. Do not run git pull as it will create unnecessary merge conflicts.git remote add azure [Azure Git URL]git push azure masterNOTE At this point it appears that Bluemix's free tier to host NodeJS apps is limited to 30 days. If you are looking for a free tier service to host your app, Render might be a better choice at this point
Create a Bluemix Account
Sign up for Bluemix, or use an existing account.
Download and install the Cloud Foundry CLI to push your applications to Bluemix.
Create a manifest.yml file in the root of your application.
applications:
- name: <your-app-name>
host: <your-app-host>
memory: 128M
services:
- myMongo-db-name
The host you use will determinate your application URL initially, eg <host>.mybluemix.net . The service name 'myMongo-db-name' is a declaration of your MongoDB service. If you are using other services like Watson for example, then you would declare them the same way.
$ cf login -a https://api.ng.bluemix.net
$ cf create-service mongodb 100 [your-service-name]
Note: this is a free and experiment verion of MongoDB instance. Use the MongoDB by Compose instance for production applications:
$ cf create-service compose-for-mongodb Standard [your-service-name]'
Push the application
$ cf push
$ cf env <your-app-name >
(To view the *environment variables* created for your application)
Done , now go to the staging domain ( <host>.mybluemix.net ) and see your app running.
Be sure to check out the full list of Watson services to forwarder enhance your application functionality with a little effort. Watson services are easy to get going; it is simply a RESTful API call. Here is an example of a Watson Toner Analyzer to understand the emotional context of a piece of text that you send to Watson.
Virtual Assistant - Deliver consistent and intelligent customer care across all channels and touchpoints with conversational AI.
Natural Language Understanding - Analyze text to extract meta-data from content such as concepts, entities, keywords and more.
Discovery - Accelerate business decisions and processes with an AI-powered intelligent document understanding and content analysis platform.
Orchestrate - Hand off tedious tasks to Watson and never work the same way again.
List of Watson Services.
Download and install Node.js
Select or create a Google Cloud Platform Console project
Enable billing for your project (there's a $300 free trial)
Install and initialize the Google Cloud SDK
Create an app.yaml file at the root of your hackathon-starter folder with the following contents:
runtime : nodejs
env : flex
manual_scaling :
instances : 1 Make sure you've set MONGODB_URI in .env.example
Run the following command to deploy the hackathon-starter app:
gcloud app deployMonitor your deployed app in the Cloud Console
View the logs for your app in the Cloud Console
If you are starting with this boilerplate to build an application for prod deployment, or if after your hackathon you would like to get your project hardened for production use, see prod-checklist.md.
You can find the changelog for the project in: CHANGELOG.md
If something is unclear, confusing, or needs to be refactored, please let me know. Pull requests are always welcome, but due to the opinionated nature of this project, I cannot accept every pull request. Please open an issue before submitting a pull request. This project uses Airbnb JavaScript Style Guide with a few minor exceptions. If you are submitting a pull request that involves Pug templates, please make sure you are using spaces , not tabs.
The MIT License (MIT)
Copyright (c) 2014-2023 Sahat Yalkabov
L'autorisation est accordée gratuitement à toute personne qui obtient une copie de ce logiciel et des fichiers de documentation associés (le "logiciel"), pour traiter le logiciel sans restriction, y compris sans limiter les droits d'utilisation, de copie, de modification, de fusion, de publication, de distribution, de sublince et / ou de vendre des copies des conditions suivantes.
L'avis de droit d'auteur ci-dessus et le présent avis d'autorisation sont inclus dans toutes les copies ou des parties substantielles du logiciel.
Le logiciel est fourni "tel quel", sans garantie d'aucune sorte, express ou implicite, y compris, mais sans s'y limiter, les garanties de qualité marchande, d'adéquation à un usage particulier et de non-contrefaçon. En aucun cas, les auteurs ou les détenteurs de droits d'auteur ne seront pas responsables de toute réclamation, dommage ou autre responsabilité, que ce soit dans une action de contrat, de délit ou autre, découlant de, hors du logiciel ou de l'utilisation ou d'autres relations dans le logiciel.