Travailler avec des variables d'environnement en Node.js

February 10, 2022
Rédigé par
Révisé par

Travailler avec des variables d'environnement en Node.js

Travailler avec des variables d'environnement est un excellent moyen de configurer différents aspects de votre application Node.js. De nombreux hôtes cloud (Heroku, Azure, AWS, now.sh, etc.) et modules Node.js utilisent des variables d'environnement. Les hôtes, par exemple, définiront une variable PORT spécifiant le port sur lequel le serveur devrait écouter pour fonctionner correctement. Les modules pourront avoir des comportements différents (comme la journalisation) en fonction de la valeur de la variable NODE_ENV.

Voici quelques-uns de mes trucs et outils quand je travaille avec des variables d'environnement dans Node.js.

Les bases

L'accès aux variables d'environnement dans Node.js est pris en charge par défaut. Lorsque votre processus Node.js démarre, il fournit automatiquement un accès à toutes les variables d'environnement existantes en créant un objet env en tant que propriété de l'objet global process. Si vous voulez jeter un coup d'œil à l'objet, exécutez l'environnement Node.js REPL avec nodedans votre ligne de commande, et tapez :

console.log(process.env);

Ce code devrait produire l'ensemble des variables d'environnement dont ce processus Node.js a connaissance. Pour accéder à une variable spécifique, faites comme pour n'importe quelle propriété d'un objet :

console.log('The value of PORT is:', process.env.PORT);

Vous devriez voir que la valeur de PORT est undefined sur votre ordinateur. Cependant, les hôtes cloud comme Heroku ou Azure utilisent la variable PORT pour vous indiquer sur quel port votre serveur devrait écouter pour que le routage fonctionne correctement. Par conséquent, la prochaine fois que vous configurerez un serveur web, vous devrez déterminer le port à écouter en vérifiant d'abord PORT et en lui donnant dans le cas contraire une valeur par défaut :

const app = require('http').createServer((req, res) => res.send('Ahoy!'));
const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Server is listening on port ${PORT}`);
});

La ligne mise en surbrillance prendra la valeur du PORT si elle est disponible, ou la valeur par défaut de 3000 en tant que port sécurisé sur lequel écouter. Essayez d'exécuter le code en l'enregistrant dans un fichier tel que server.js puis exécutez :

node server.js

La sortie devrait être un message indiquant Server is listening on port 3000. Arrêtez le serveur à l'aide des touches Ctrl+C et redémarrez-le à l'aide de la commande suivante :

PORT=9999 node server.js

Le message devrait maintenant dire Server is listening on port 9999 car la variable PORT a été temporairement définie pour cette exécution par le PORT=9999 devant node.

Puisque process.env est simplement un objet normal, nous pouvons définir/remplacer les valeurs très facilement :

process.env.MY_VARIABLE = 'ahoy';

Le code ci-dessus définira ou remplacera la valeur MY_VARIABLE. Cependant, gardez à l'esprit que cette valeur n'est définie que pendant l'exécution de ce processus Node.js, et n'est disponible que dans les processus enfants générés par ce processus. En règle générale, évitez autant que possible de remplacer les variables d'environnement, et initialisez plutôt une variable de configuration comme indiqué dans l'exemple PORT.

Charger explicitement des variables depuis des fichiers .env

Si vous développez sur différents projets Node.js depuis un même ordinateur, il se peut que vous vous retrouviez avec des chevauchements des noms de variables d'environnement. Par exemple, différentes applications de messagerie pourront avoir besoin de différents SID de service de messagerie Twilio, mais les deux s'appelleront TWILIO_MESSAGE_SERVICE_SID. Un excellent moyen d'obtenir une configuration spécifique au projet est d'utiliser des fichiers .env. Ceux-ci permettent de spécifier toute une variété de variables d'environnement différentes et leurs valeurs.

En principe, vous ne voulez pas suivre ces fichiers dans le contrôle de source, donc lorsque vous en créez un, vous devez ajouter .env à votre .gitignore. Vous verrez dans de nombreuses applications de démonstration Twilio des fichiers .env.example que vous pourrez ensuite copier vers .env et qui vous permettront de définir les valeurs vous-même. Une pratique courante consiste à avoir un fichier .env.example ou similaire si vous voulez partager un fichier modèle avec d'autres personnes du projet.

Comment charger les valeurs à partir de ce fichier ? La façon la plus simple est d'utiliser un module npm appelé dotenv. Il vous suffit d'installer le module via npm :

npm install dotenv --save

Ajoutez ensuite la ligne suivante tout en haut de votre fichier d'entrée :

require('dotenv').config();

Ce code chargera automatiquement le fichier .env à la racine de votre projet et initialisera les valeurs. Toutes les variables déjà définies seront ignorées. Cela dit, vous ne devriez pas utiliser de fichiers .env dans votre environnement de production, mais définir plutôt les valeurs directement sur l'hôte correspondant. Par conséquent, il pourrait être judicieux d'encapsuler votre instruction « load » dans une instruction « if » :

if (process.env.NODE_ENV !== 'production') {
  require('dotenv').config();
}

Avec ce code, nous ne chargerons le fichier .env que si le serveur n'est pas démarré en mode production.

Voyons cela en action. Installez dotenv dans un répertoire comme indiqué ci-dessus. Créez un fichier dotenv-example.js dans le même répertoire et insérez-y les lignes suivantes :

console.log('No value for FOO yet:', process.env.FOO);

if (process.env.NODE_ENV !== 'production') {
  require('dotenv').config();
}

console.log('Now the value for FOO is:', process.env.FOO);

Ensuite, créez un fichier nommé .env dans le même répertoire, avec le contenu suivant :

FOO=bar

Exécutez le script :

node dotenv-example.js

La sortie devrait ressembler à :

No value for FOO yet: undefined
Now the value for FOO is: bar

Comme vous pouvez le voir, la valeur a été chargée et définie à l'aide de dotenv. Si vous réexécutez la même commande avec NODE_ENV définie sur production, vous verrez qu'elle restera undefined.

NODE_ENV=production node dotenv-example.js

La sortie devrait maintenant être :

No value for FOO yet: undefined
Now the value for FOO is: undefined

Si vous ne voulez pas modifier votre code en lui-même, vous pouvez également utiliser l'argument -r de Node pour charger dotenv lors de l'exécution du script. Modifiez votre fichier dotenv-example.js :

console.log('The value for FOO is:', process.env.FOO);

Ensuite, exécutez d'abord le fichier normalement :

node dotenv-example.js

Le script devrait indiquer que la valeur actuelle pour FOO est undefined. Exécutez-le maintenant avec l'indicateur approprié pour appeler dotenv:

node -r dotenv/config dotenv-example.js

Le résultat est que FOO est maintenant définie sur bar depuis que le fichier .env a été chargé.

Si vous souhaitez en savoir plus sur dotenv, consultez sa documentation.

Charger autrement des fichiers .env

dotenv est certes génial, mais il y a une chose en particulier qui m'a personnellement gêné au cours du processus de développement : il ne remplace pas les variables env existantes et vous ne pouvez pas l'y forcer.

J'étais si frustré que j'ai décidé d'écrire mon propre module basé sur dotenv afin de résoudre ce problème et de rendre le chargement de variables d'environnement plus pratique. Le résultat est node-env-run ou nodenv. Il s'agit d'un outil de ligne de commande qui charge un fichier .env, initialise les valeurs à l'aide de dotenv, puis exécute votre script.

Vous pouvez l'installer globalement, mais je vous recommande de l'utiliser uniquement à des fins de développement et au niveau local du projet. Installez-le en exécutant :

npm install node-env-run --save-dev

Ensuite, créez un fichier nodenv-example.js et insérez-y ce code :

console.log('The value for FOO is:', process.env.FOO);

Comme vous pouvez le voir, nous n'avons pas besoin d'appeler quoi que ce soit ici. Il s'agit simplement de la logique applicative. Essayez d'abord de l'exécuter à l'aide de node :

node nodenv-example.js

Ce code exécuté devrait générer The value for FOO is: undefined. Essayez maintenant d'utiliser node-env-run en exécutant :

node_modules/.bin/nodenv nodenv-example.js

Le résultat devrait être The value for FOO is: bar dans la mesure où il a chargé le fichier .env.

Node-env-run peut remplacer les valeurs existantes. Pour le voir en action, exécutez d'abord la commande suivante :

FOO=foo node_modules/.bin/nodenv nodenv-example.js

La sortie de ligne de commande devrait indiquer The value for Foo is: foo. Si nous activons maintenant le mode force, nous pouvons remplacer les valeurs existantes :

FOO=foo node_modules/.bin/nodenv --force nodenv.js

Par conséquent, nous devrions revenir au The value for FOO is: bar initial.

Si vous souhaitez utiliser cet outil régulièrement, je vous recommande de l'encapsuler dans un script npm. En l'ajoutant dans package.json comme suit :

{
  "name": "twilio-blog",
  "version": "1.0.0",
  "description": "",
  "main": "nodenv-example.js",
  "scripts": {
    "start": "node .",
    "start:dev": "nodenv -f ."
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "node-env-run": "^2.0.1"
  }
}

Vous pouvez ainsi exécuter en toute simplicité :

npm run start:dev

Si vous souhaitez en savoir plus sur node-env-run, consultez sa documentation.

Variables d'environnement && scripts npm

Dans certains scénarios, il est utile de vérifier la valeur d'une variable d'environnement avant d'entrer dans l'application Node.js en scripts npm. Par exemple, si vous souhaitez utiliser node-env-run lorsque vous êtes dans un environnement de développement, mais node lorsque vous êtes en mode productionUn outil permet de le faire très facilement : if-env. Installez-le en exécutant :

npm install if-env --save

Assurez-vous de ne pas l'installer en tant que « dépendance de développement » car nous en aurons aussi besoin en production.

Maintenant, il vous suffit de modifier vos scripts npm dans votre package.json:

  "scripts": {
    "start": "if-env NODE_ENV=production ?? npm run start:prod || npm run start:dev",
    "start:dev": "nodenv -f .",
    "start:prod": "node ."
  }

Ce script va dès lors exécuter npm run start:prod, puis node . si NODE_ENV a la valeur production, et dans le cas contraire exécuteranpm run start:dev, puis nodenv -f .. Vous pouvez également utiliser cette technique avec n'importe quelle autre variable d'environnement.

Essayez par exemple en exécutant :

# should output "The value of FOO is: bar"
npm start
# should output "The value of FOO is: undefined"
NODE_ENV=production npm start

Si vous souhaitez en savoir plus sur if-env, consultez sa documentation.

Débogage

On connaît tous ce moment où les choses ne fonctionnent pas comme on le souhaiterait et où un module ne fait pas ce qu'il est censé faire. Le moment est alors venu de déboguer. Une stratégie qui m'a beaucoup aidé a été d'utiliser la variable d'environnement DEBUG afin de recevoir des journaux plus détaillés pour un groupe de modules. Par exemple, si vous prenez un serveur express de base comme celui-ci :

const app = require('express')();
const bodyParser = require('body-parser');
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

app.post('/', (req, res, next) => {
console.log(req);
});

app.listen(3000);

Et que vous le lancez avec la variable DEBUG définie sur * :

DEBUG=* node server.js

Vous recevrez une série de logs détaillés qui ressemblent à ceci :

logs

La « magie » s'opère grâce à un module léger appelé debug extrêmement facile d'utilisation. Lorsque vous voulez l'utiliser, il vous suffit de l'initialiser avec un « espace de nom ». Vous pouvez ensuite vous connecter à cet espace de nom. Si quelqu'un veut voir la sortie, il lui suffit d'activer l'espace de nom dans la variable DEBUG. Dans notre cas, express utilise un groupe de sous-espaces de noms. Si vous voulez tout ce qui provient du routeur express, il vous suffit de paramétrer DEBUG sur le caractère générique approprié :

DEBUG=express:router* node server.js

Si vous souhaitez utiliser debug dans votre propre module, il vous suffit d'abord de l'installer :

npm install debug --save

Vous pouvez ensuite le consommer de la manière suivante :

const debug = require('debug')('myApp:someComponent');

debug('Here is a pretty object %o', { someObject: true });

Si vous souhaitez en savoir plus sur le débogage assurez-vous de consulter la documentation.

Utilisez maintenant toutes les variables d'environnement !

Bien loin d'être les seules choses que vous pouvez faire avec les variables d'environnement ni les seuls outils disponibles, il s'agit ici simplement de ceux que j'utilise le plus souvent. Si vous utilisez régulièrement d'autres outils remarquables, je serais ravi d'en savoir plus !

Maintenant que vous en savez un peu plus sur les variables d'environnement dans Node.js, essayez les kits de démarrage rapide Node.js  de Twilio !