Leçons tirées du déploiement de ma première application Web full-stack

J'ai récemment atteint l'un de mes objectifs à long terme: déployer ma première application Web full-stack.

Dans cet article, je partagerai les leçons que j'ai apprises du point de vue d'un débutant, ainsi que quelques tutoriels utiles que j'ai suivis, les principaux obstacles que j'ai dû surmonter et les erreurs que j'ai commises en cours de route. Je souhaite aider d'autres développeurs à comprendre ce qu'implique le déploiement d'une application Web.

Après avoir passé plus de six semaines à rechercher sur Google, à essayer, à échouer et à réessayer, j'ai finalement réussi à déployer mon application Web. Il était composé d'un backend Node.js avec un frontend React vers une machine virtuelle Amazon Web Services (AWS) EC2.

C'était tout un défi mais c'était vraiment satisfaisant, car au final l'application a été déployée avec succès et est maintenant accessible via un nom de domaine public.

La plus grande difficulté pour moi a été de trouver les informations. Je n'ai pas compris ce qu'impliquait le déploiement. J'ai donc eu du mal à trouver des réponses efficaces sur le web. Je n'ai pas réussi à trouver un seul guide pour l'ensemble du processus.

J'espère que je pourrai simplifier la courbe d'apprentissage du déploiement pour la personne suivante en rassemblant toutes les informations que j'ai apprises en un seul endroit.

Alors voilà…

Que signifie déployer une application?

Une application Web est divisée en deux parties.

  • Code côté client: il s'agit de votre code d'interface utilisateur frontend. Ce sont des fichiers statiques qui ne changent pas tout au long de la vie de votre application. Les fichiers statiques doivent exister quelque part pour que vos utilisateurs puissent les télécharger et les exécuter dans leur navigateur côté client. J'irai plus en détail sur ce que cela pourrait être quelque part plus tard.
  • Code côté serveur: il traite de toute la logique de votre application. Il doit être exécuté sur un serveur (machine), généralement virtuel comme une instance EC2, tout comme vous l'exécutez lors du développement local.

Pour exécuter votre code local, le serveur doit en avoir une copie. Je viens de cloner mon dépôt Github sur le serveur à partir de l'interface de ligne de commande du serveur.

Vous devez également configurer votre serveur. Ceci comprend:

  • configurer la machine pour pouvoir accéder à Internet et exécuter votre code
  • exposer les bons ports
  • écoute des requêtes HTTP (requêtes Internet)
  • pointant un nom de domaine personnalisé vers le serveur à partir duquel votre application s'exécute

Vous saurez que cela fonctionne lorsque vous pouvez accéder à votre application en utilisant votre nom de domaine personnalisé à partir de n'importe quelle machine sur Internet et que toutes les fonctionnalités de votre application fonctionnent comme prévu.

Donc, c'est un aperçu. Mais comment le faisons-nous réellement?

Commencer

Vous devez diviser votre application et résoudre le problème. Vous déployez deux choses différentes: des fichiers statiques côté client et du code côté serveur.

Ma première erreur a été de penser à mon application dans son ensemble, plutôt qu'à deux applications distinctes qui se parlent.

Cela a ajouté à la complexité et a rendu inutile la recherche de réponses sur Google. Cela m'a laissé dépassé.

J'ai décomposé le problème en ces étapes. Bien que chaque problème puisse toujours être décomposé davantage.

  • Configuration de votre VM et déploiement de votre backend
  • Déployer votre frontend
  • Faire communiquer les deux applications
  • Pointant votre nom de domaine

Dans la figure ci-dessous, j'ai tenté de mettre le processus complet dans un diagramme.

Configuration de votre VM et déploiement de votre backend

Dans mon cas, il s'agissait d'un serveur Express.js déployé sur une machine virtuelle Amazon EC2. J'aurais expliqué comment le faire, mais le didacticiel «Création et gestion d'un serveur Node.js sur AWS - Partie 1» fait un bien meilleur travail.

C'est le meilleur tutoriel que j'ai rencontré dans cet espace et couvre:

  • Démarrage d'une machine virtuelle AWS
  • Obtenir des groupes de sécurité corrects pour les ports
  • Extraire du code de GitHub sur la machine virtuelle
  • Exécuter votre serveur
  • Utilisation de Nginx, un serveur HTTP, pour transférer les requêtes du port 80
  • Utilisation de PM2 pour conserver le processus exécutant votre serveur

C'était une bouée de sauvetage, et sans cela, je serais probablement toujours coincé. Alors merci, Robert Tod.

Vous pouvez facilement tester que votre serveur fonctionne à l'aide de Postman pour envoyer une requête à l'un de vos points de terminaison Backend.

Déployer votre frontend

Alors maintenant que vous avez un serveur avec votre backend en cours d'exécution (j'espère), vous devez faire fonctionner votre frontend. C'est vraiment facile lorsque vous comprenez le processus.

Malheureusement, je ne l'ai pas fait pendant longtemps. Par exemple, au début, j'ai essayé d'exécuter mon frontend en utilisant npm start.

Npm start crée un serveur de développement local, servant les fichiers de manière à ce qu'ils ne soient accessibles qu'en utilisant localhostce que nous ne voulons pas.

Pour déployer le code Frontend, vous devez stocker tous les fichiers sur votre machine virtuelle dans un emplacement que votre serveur Web connaît. Le serveur Web permet à un client de télécharger le code et de l'exécuter dans son navigateur.

Apache et Nginx sont des exemples de serveurs Web.

Un serveur Web écoute certains ports, le port 80 ou plus communément le port 443 (sécurisé), et sert des fichiers statiques (votre code Frontend) ou transmet la demande à un autre port. Par exemple, nous avons vu une demande au backend dans le didacticiel Node.js ci-dessus.

Le code Frontend n'étant qu'un ensemble de fichiers stockés sur un serveur Web, nous souhaitons rendre ces fichiers aussi petits et optimisés que possible. Cela garantit que le client peut les télécharger et les exécuter aussi rapidement que possible.

Une page plus rapide se charge autant d'utilisateurs heureux.

Tous vos fichiers JavaScript frontaux peuvent être regroupés dans un seul fichier JavaScript. Cela se fait généralement en exécutant npm run build, en supposant que ce script soit défini dans votre package.json.

Vous pouvez en savoir plus sur le code de regroupement ici.

Basically, bundling your application removes anything that isn’t essential. This includes shortening names and placing all JavaScript code in one file. It will also compile your code into the correct JavaScript version. This is so all web browsers can understand and run it (for example, converting TypeScript to JavaScript).

When your code is bundled, you just have to copy the files into your web server. Then configure your web server to serve files stored at that location.

Here is a good article on deploying static files to an Nginx web server.

Hopefully, if all is going well (which it never does), your Frontend code is now working.

Visit the public DNS for the virtual machine to verify that the static information from the site loads.

Getting the Two Applications Communicating

So I had both my applications running individually, but something wasn’t right. I couldn’t get rid of a network request error.

This was the most frustrating point for me. I was so close, but I ran into some setbacks that ended up taking weeks to solve.

Cross-Origin Resource Sharing (CORS) is a mechanism that allows communication between different IP addresses or ports. You want your Backend to be allowed to send data back to your Frontend.

To enable this, your Frontend must include the correct headers when requesting resources. This can be done in two ways:

  • The headers can be added in Nginx although it takes some figuring out. You can start here.
  • You can use the cors npm module to include the headers.

A great way to test this if it is working is by looking within the network tab of your browser’s developer tools. This shows all the requests your application is making. If you select a request you can see where the request went to and what headers it included.

Once you have the right request headers being sent with your request, you have to make sure the requests are going to the correct place. This should be the address and port of your EC2 Backend server and not the address and port of your local Backend server like mine was.

Your Frontend communicates with your Backend using HTTP requests. Somewhere in your Frontend, code you will tell it where your Backend is located.

const networkInterface = createNetworkInterface({ uri: ‘//0.0.0.0:5000/graphql', });

Mine looked like this, which clearly was not going to be correct for my production server.

Annoyingly this made my application seem like it worked when I first navigated to it on my local machine, as my local server was running and able to return the required information.

To fix this, you can simply change the URI defined, but that means having to change it back every time you do further development, which is not the best approach (I know because I did it).

A more sophisticated solution is to include both URIs and use environment variables to select the appropriate one.

const networkInterface = createNetworkInterface({ uri: process.env.NODE_ENV === 'production' ? '//thecommunitymind.com/graphql' : '//0.0.0.0:5000/graphql', });

Simple but effective. Just make sure you set your NODE_ENV to production when using it for your production server.

We’re almost there. In fact, your deployment might work now.

But I had one last problem to overcome.

Even though my CORS setup was correct, the required headers were not being included consistently and were only getting added sometimes. For some POST requests, the CORS headers were not always present. Very odd!

This error lead me on a frustrating goose chase trying to fix my CORS setup in Nginx, when actually it had nothing to do with CORS.

Actually, I didn’t even need to do anything with CORS in Nginx, because I was using the CORS npm module.

The error was due to two other issues:

  • My database was included as an sqlite file in the Backend and
  • My process manager, PM2, was watching for file changes

So writing to the database file on a POST request caused PM2 to restart the server. This was leading to the correct headers not getting picked up which resulted in misleading errors.

A great tip and one I wish I had known earlier is to check your server logs on your EC2 instance. Whether you’re using PM2 or something else there will always be a way to check your logs. Just Google it!

These logs provided the key to solve my issue.

I simply had to turn off the watch ability of PM2. Bingo. And finally, it worked.

Pointing your Domain Name

This is the icing on the cake. You want a nice clean URL for your newly deployed application.

I bought my domain name through Amazon and used Route 53 to point it to the correct EC2 instance. This was a surprisingly painless experience.

Amazon’s tutorial was quite sufficient.

Summary

I hope this post has helped you understand the web application deployment process and ultimately get your amazing project online — whatever that may be.

At least you should have a better idea of what to Google for!

Good Luck.