Grégory Bourguin
SysReIC - LISIC - ULCO
Introduction à Node.js

Introduction à Node.js

Dans cette partie, nous allons étudier comment créer une application Full Stack en Javascript (backend + frontend) en utilisant le langage Javascript.

Pour créer notre serveur web en Javascript, nous allons mettre en oeuvre un ensemble d'outils dont la base est constitué du runtime Node.js.

Installation de Node.js

L'installation de Node.js est assez simple du fait qu'il existe un runtime déstiné à de nombreux systèmes d'exploitations.

Il suffit de vous rendre sur le site officiel Node.js, et de suivre les instructions d'installation (téléchargement, etc.) correspondantes à votre système.

Pour vérifier l'installation, vous pouvez ensuite aller dans un terminal et entrer l'instruction suivante : node --version.

Si tout est bien installé, vous devez alors voir s'afficher l'information correspondante.

Initialisation de projet Node.js

Dans une approche Full Stack Javascript, les parties backend (code serveur) et frontend (code client) sont en général séparées.

Cependant, de manière à apprendre à maitriser les outils liés à Node.js, nous allons dans un premier temps nous concentrer sur la construction d'un backend plus "classique" qui contiendra les fonctionnalités offertes par le serveur, mais aussi une partie cliente.

Création d'un projet

Commencez par créer un projet (un dossier dont vous choisirez le nom) dans lequel vous créerez un sous-dossier nommé backend destiné à recevoir notre code serveur.

NB1 : il n'est pas obligatoire de créer un sous-dossier backend dans le projet, mais cela permet de bien séparer la partie serveur (dans backend/) d'une éventuelle partie cliente (qu'on mettra plus tard dans un sous-dossier par exemple nommé frontend/).

NB2 : dans les exemples ci-après, j'ai nommé mon projet/dossier fsjs_demo

Initialisation

L'installation de Node.js a (en plus de la commande node) permis d'installer le gestionnaire npm qui va nous être très utile pour ajouter de nombreuses fonctionnalités sous la forme de packages.

Dans un terminal, rendez-vous dans le dossier backend et exécutez la commande npm init.

L'invite de commande pose alors plusieurs questions utilisées pour configurer le projet :

Vous pouvez laisser la plupart des valeurs par défaut (appuyez simplement sur la touche entrée), mais par convention, vous changerez la valeur de entry point en indiquant server.js.

NB : le fichier server.js n'existe pas encore -> nous allons le créer et c'est lui qui fera office de point de démarrage de l'exécution de notre serveur web.

Une fois la commande exécutée, vous devez trouver dans le dossier backend un nouveau fichier nommé package.json qui reprend les informations que vous avez entrées.

Ce fichier est très important car c'est lui qui contiendra (entre autres) les informations de dépendances des packages utilisés dans le projet.

Nous reviendrons plus tard sur les informations principales contenues dans ce fichier.

L'exemple ci-dessous illustre un projet nommé fsjs_demo après initialisation :

Serveur Basique

Pour démarrer notre serveur web, il nous faut maintenant créer le point d'entrée principal correspondant au fichier server.js (dans le dossier backend).

Le contenu de ce fichier va très vite de complexifier, mais il est intéressant de créer un serveur très basique pour comprendre les bases du fonctionnement de Node.js.

server.js

// Définition du n° de port sur lequel le serveur va écouter
// (ce sera la valeur système process.env.PORT si elle existe, 3000 sinon)
const port = process.env.PORT || 3000

// Inclusion du module prédéfini de Node.js permettant d'exécuter un serveur http
const http = require('http')

// Ce serveur très simple reverra toujours la même réponse :
// - un code http 200
// - un header spécifiant l'encodage de la réponse
// - le message "Le serveur Node.js dit <b>bonjour</b>"
const server = http.createServer((req, res) =>{
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html;charset=utf-8');
    res.end("Le serveur Node.js dit <b>bonjour</b>")
})

// Démarrage de l'écoute des requêtes sur le port indiqué
server.listen(port,()=>{
    console.log(`Le server écoute sur http://127.0.0.1:${port}/`);
})

Il ne reste plus qu'à exécuter ce script au sein de Node.js pour lancer le serveur :
Dans un terminal, dans le dossier backend, entrez la commande : node server.js

Ouvrez un navigateur à l'adresse qui a été affichée dans la console à l'exécution du listen : vous devriez voir la réponse du serveur "Le serveur Node.js dit bonjour".
En affichant les informations réseau, vous verrez aussi le status code 200 (OK) envoyé par le serveur pour indiquer au navigateur qu'il a bien pu traiter cette requête.

Vous pourrez remarquer que (pour l'instant) la réponse du serveur (représentée par l'objet res dans le callback de l'appel à la méthode createServer) est identique quelle que soit la route demandée par votre navigateur : par exemple, si votre serveur tourne à l'adresse http://127.0.0.1:3000, la réponse reçue est la même qu'avec un chemin plus complexe comme http://127.0.0.1:3000/truc/machin/chose.

Ceci est dû au fait que dans l'appel à la méthode createServer, notre code indique au serveur d'envoyer la même réponse (res) quelle que soit la requête req reçue : le paramètre req qui contient les informations relatives à cette requête n'est d'ailleurs même pas utilisé.

NB : ce serveur est très basique -> nous verrons bientôt comment faire mieux ;).

Pour arrêter le serveur : CTRL+C dans le terminal.

Scripts

L'environnement Node.js permet de spécifier des scripts correspondant à des tâches spécifiques liées au projet : ces scripts peuvent être définis sous la clé scripts du fichier package.json.

D'ailleurs, dans le fichier que nous avons généré avec npm init, on peut voir un script nommé test qui a été automatiquement généré et affiche un message dans la console s'il est lancé.

Pour exécuter un script, on utilise la commande npm run nom_du_script

Vous pouvez essayer d'exécuter le script test en lançant npm run test : vous verrez alors le message indiquant qu'aucun test a été défini.

Pour créer un script de démarrage de notre projet, il suffit d'ajouter une ligne sous la clé scripts de package.json.

Dans l'exemple ci-dessous, nous avons ajouté un script start contenant le code de lancement du serveur :

Pour l'utiliser, il suffit de lancer la commande : npm run start.

NB : un script nommé start est un cas un peu particulier du fait que pour le lancer, on peut aussi simplement écrire npm start.

Nous verrons par la suite que ce mécanisme de scripts est bien utile lorsqu'on veut par exemple mettre simplement en oeuvre plusieurs manières de démarrer le serveur (mode développement, mode production, etc.).

Package/module : nodemon

Petite expérience : modifiez la réponse de votre serveur en changeant le message renvoyé
par exemple : "Le serveur Node.js dit bonjour" -> "Le serveur dit YO !!!"

Si vous rechargez directement la page dans votre navigateur, vous verrez que le message n'a pas changé.

Pour que le serveur change de comportement, il faut le redémarrer !

Cela signifie qu'à chaque modification de votre code, vous devez aller dans la console, faire un CTRL+C, et relacer la commande node server.js : c'est fastidieux !

Heureusement, le package/module nommé nodemon facilite grandement le développement en redémarrant automatiquement le serveur node à chaque modification de son source.

Installation

Pour installer nodemon (uniquement dans le projet) : npm install nodemon.

NB: depuis la version 5 de Node.js, il n'est plus nécessaire d'ajouter l'option --save.

npm install ... crée/complète dans backend un nouveau fichier package-lock.json : il ne nous intéresse pas et vous ne devez pas y toucher !

npm install ... crée/complète dans backend le dossier node_modules : ce dossier contient l'ensemble des package que vous installe(re)z avec npm : vous ne devez pas y toucher !
Par contre, vous pouvez aller voir ce qui s'y trouve : vous remarquerez en particulier le dossier .bin qui contient la commande nodemon -> c'est cette commande qui va nous permettre de démarrer le serveur sans avoir à le relancer manuellement à chaque modification.

npm install ... complète le fichier package.json en y indiquant les dépendances du projet. Cette fonctionnalité particulièrement dans le cas où vous souhaitez (ré)installer les packages : vous pouvez supprimer le fichier package-lock.json et le dossier node_modules -> la commande npm-install utilisera le fichier package.json pour tout réinstaller automatiquement.

Exécution

Pour utiliser nodemon, vous pouvez entrer : node_modules/.bin/nodemon server.js

Ceci a pour effet de lancer le serveur (comme avec node server.js), mais maintenant, chaque modification du code source relance automatiquement le serveur !
(NB : il faut quand même rafraichir la page du navigateur).

Pour arrêter le serveur : CTRL+C dans le terminal.

NB : il est aurait été possible d'installer nodemon de manière globale (rendant la commande directement accessible en ligne de commande pour tous vos projets) grâce à npm install -g nodemon. Cependant, pour que cela fonctionne, vous devez avoir les droits d'écriture dans les dossiers d'installation de Node.js, ce qui n'est pas le cas dans les salles de TP.

Nous venons de voir qu'il est possible de lancer l'exécution du serveur de plusieurs manières : avec node pour une "simple" exécution, et avec nodemon pour une exécution avec redémarrage automatique en phase de développement.

Pour simplifier ces tâches, nous allons créer différents scripts dans package.json :

NB1 : dans le script, on n'indique pas le chemin complet vers node_modules/.bin/nodemon : npm ira automatiquement le chercher dans le répertoire d'installation.

NB2 : on aurait tout à fait pu choisir un autre nom que "start-dev" pour le script.

Pour lancer le serveur en développement avec nodemon, il suffit maintenant d'exécuter : npm run start-dev.

Dotenv

Dans les scripts précédents, vous avez du remarquer que nous utilisons le code suivant pour définir le port sur lequel tourne notre application :

const port = process.env.PORT || 3000

Comme indiqué précédemment, ce code 'tente' d'utiliser la valeur système process.env.PORT pour déterminer sur quel port démarrer le serveur.

Le module dotenv sert à charger les variables d'environnement définies dans un fichier .env pour les rendre accessibles dans process.env.

Installation

Pour ajouter le module dotenv au projet : npm install dotenv.

Mise en oeuvre

Les variables d'environnement sont définies dans un fichier qu'on appelle par convention .env.

L'exemple ci-dessous défini la variable PORT que nous voulons utiliser :

.env

PORT=4000

Le chargement des variables est alors effectué dès le démarrage de l'application (par exemple au tout début de server.js) grâce à l'instruction :

require('dotenv').config({ path: './.env'} ) ;

On peut ensuite accéder à cette variable dans toute l'application au travers de process.env

Ci-dessous le nouveau fichier server.js obtenu

server.js

// Charge les variables d'environnement définies dans .env
require('dotenv').config({ path: './.env'} ) ;

// Définition du n° de port sur lequel le serveur va écouter
const port = process.env.PORT || 3000

const http = require('http')
const server = http.createServer((req, res) =>{
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/html;charset=utf-8');
    res.end("Le serveur Node.js dit <b>bonjour</b>")
})

// Démarrage de l'écoute des requêtes sur le port indiqué
server.listen(port,()=>{
    console.log(`Le server écoute sur http://127.0.01:${port}/`);
})

Vous constaterez maintenant que votre serveur tourne sur le port 4000 au lieu du port 3000 comme c'était le cas auparavant.

NB : nous verrons dans la suite de ce cours que le fichier .env peut contenir d'autres données cruciales comme les informations de connexion à une base de données, une clé de chiffrage, etc.

... et c'est pour cette raison qu'il est conseillé d'ajouter la ligne **/.env à votre fichier .gitignore.