web-dev-qa-db-fra.com

Comment partagez-vous les constantes dans les modules NodeJS?

Actuellement je fais ça:

foo.js

const FOO = 5;

module.exports = {
    FOO: FOO
};

Et l'utiliser dans bar.js:

var foo = require('foo');
foo.FOO; // 5

Y a-t-il une meilleure manière de faire cela? Il est difficile de déclarer la constante dans l'objet exports.

203
Tower

Vous pouvez explicitement l'exporter dans la portée globale avec global.FOO = 5. Ensuite, vous devez simplement exiger le fichier et ne même pas enregistrer votre valeur de retour.

Mais vraiment, vous ne devriez pas faire ça. Garder les choses correctement encapsulées est une bonne chose. Vous avez déjà la bonne idée, alors continuez à faire ce que vous faites.

80
Alex Wayne

À mon avis, utiliser Object.freeze permet un style plus sec et plus déclaratif. Mon modèle préféré est:

./lib/constants.js

module.exports = Object.freeze({
    MY_CONSTANT: 'some value',
    ANOTHER_CONSTANT: 'another value'
});

./lib/some-module.js

var constants = require('./constants');

console.log(constants.MY_CONSTANT); // 'some value'

constants.MY_CONSTANT = 'some other value';

console.log(constants.MY_CONSTANT); // 'some value'

Avertissement de performance obsolète

Le problème suivant a été résolu dans la v8 en janvier 2014 et ne concerne plus la plupart des développeurs:

Sachez que la définition de false en écriture et l’utilisation d’Object.freeze entraînent une pénalité de performances considérable dans la v8 - https://bugs.chromium.org/p/v8/issues/detail?id=1858 et http://jsperf.com/performance-frozen-object

254
Spain Train

Techniquement, const ne fait pas partie de la spécification ECMAScript. En outre, en utilisant le modèle "CommonJS Module" que vous avez noté, vous pouvez modifier la valeur de cette "constante" puisqu'il ne s'agit désormais que d'une propriété d'objet. (je ne sais pas si cela va entraîner en cascade des modifications sur d'autres scripts nécessitant le même module, mais c'est possible)

Pour obtenir une vraie constante que vous pouvez également partager, consultez Object.create , Object.defineProperty et Object.defineProperties . Si vous définissez _writable: false_, la valeur de votre "constante" ne peut pas être modifiée. :)

C'est un peu verbeux (mais même cela peut être changé avec un peu de JS), mais vous ne devriez avoir besoin que de le faire une fois pour votre module de constantes. En utilisant ces méthodes, tout attribut que vous omettez est pris par défaut à false. (par opposition à la définition de propriétés via une affectation, qui attribue par défaut tous les attributs à true)

Donc, hypothétiquement, vous pourriez simplement définir value et enumerable, en laissant de côté writable et configurable car ils utiliseront par défaut false, je viens d'inclure eux pour plus de clarté.

Mise à jour - J'ai créé un nouveau module ( constantes de nœud ) avec des fonctions d'assistance pour ce même cas d'utilisation.

constants.js - Bien

_Object.defineProperty(exports, "PI", {
    value:        3.14,
    enumerable:   true,
    writable:     false,
    configurable: false
});
_

constants.js - Mieux

_function define(name, value) {
    Object.defineProperty(exports, name, {
        value:      value,
        enumerable: true
    });
}

define("PI", 3.14);
_

script.js

_var constants = require("./constants");

console.log(constants.PI); // 3.14
constants.PI = 5;
console.log(constants.PI); // still 3.14
_
157
Dominic Barnes

ES6 façon.

export dans foo.js

const FOO = 'bar';
module.exports = {
  FOO
}

import dans bar.js

const {FOO} = require('foo');
76
Diego Mello

J'ai trouvé la solution suggérée par Dominic comme étant la meilleure, mais il lui manque encore une caractéristique de la déclaration "const". Lorsque vous déclarez une constante dans JS avec le mot-clé "const", l'existence de la constante est vérifiée au moment de l'analyse, pas au moment de l'exécution. Donc, si vous avez mal orthographié le nom de la constante quelque part plus tard dans votre code, vous obtiendrez une erreur lorsque vous essayez de démarrer votre programme node.js. Ce qui est une vérification beaucoup plus efficace.

Si vous définissez la constante avec la fonction define () comme suggéré par Dominic, vous n'obtiendrez pas d'erreur en cas d'orthographe erronée de la constante et la valeur de la constante mal orthographiée sera indéfinie (ce qui peut entraîner des problèmes de débogage).

Mais je suppose que c'est le meilleur que nous puissions avoir.

De plus, voici une sorte d'amélioration de la fonction de Dominic, dans constans.js:

global.define = function ( name, value, exportsObject )
{
    if ( !exportsObject )
    {
        if ( exports.exportsObject )
            exportsObject = exports.exportsObject;
        else 
            exportsObject = exports;        
    }

    Object.defineProperty( exportsObject, name, {
        'value': value,
        'enumerable': true,
        'writable': false,
    });
}

exports.exportObject = null;

De cette façon, vous pouvez utiliser la fonction define () dans d'autres modules, ce qui vous permet de définir des constantes à la fois dans le module constants.js et des constantes dans votre module à partir duquel vous avez appelé la fonction. La déclaration des constantes de module peut ensuite être effectuée de deux manières (dans script.js).

Première:

require( './constants.js' );

define( 'SOME_LOCAL_CONSTANT', "const value 1", this ); // constant in script.js
define( 'SOME_OTHER_LOCAL_CONSTANT', "const value 2", this ); // constant in script.js

define( 'CONSTANT_IN_CONSTANTS_MODULE', "const value x" ); // this is a constant in constants.js module

Seconde:

constants = require( './constants.js' );

// More convenient for setting a lot of constants inside the module
constants.exportsObject = this;
define( 'SOME_CONSTANT', "const value 1" ); // constant in script.js
define( 'SOME_OTHER_CONSTANT', "const value 2" ); // constant in script.js

De même, si vous souhaitez que la fonction define () soit appelée uniquement à partir du module constantes (sans pour autant altérer l'objet global), vous la définissez comme ceci dans constants.js:

exports.define = function ( name, value, exportsObject )

et utilisez-le comme ceci dans script.js:

constants.define( 'SOME_CONSTANT', "const value 1" );
15
xmak

D'après l'expérience du projet précédent, c'est un bon moyen:

Dans les constants.js:

// constants.js

'use strict';

let constants = {
    key1: "value1",
    key2: "value2",
    key3: {
        subkey1: "subvalue1",
        subkey2: "subvalue2"
    }
};

module.exports =
        Object.freeze(constants); // freeze prevents changes by users

Dans main.js (ou app.js, etc.), utilisez-le comme suit:

// main.js

let constants = require('./constants');

console.log(constants.key1);

console.dir(constants.key3);
9

Je pense que const résout le problème pour la plupart des gens à la recherche de cette réponse. Si vous avez vraiment besoin d'une constante immuable, examinez les autres réponses. Pour que tout reste organisé, j'enregistre toutes les constantes d'un dossier, puis le dossier au complet.

fichier src/main.js

const constants = require("./consts_folder");

src/répertoire_configuration/index.js

const deal = require("./deal.js")
const note = require("./note.js")


module.exports = {
  deal,
  note
}

Ps. ici les deal et note seront au premier niveau sur le fichier main.js

src/dossier_configuration/note.js

exports.obj = {
  type: "object",
  description: "I'm a note object"
}

Ps. obj sera le deuxième niveau sur le fichier main.js

src/consts_folder/deal.js

exports.str = "I'm a deal string"

Ps. str sera le deuxième niveau sur le fichier main.js

Résultat final sur le fichier main.js:

console.log(constants.deal); Ouput:

{deal: {str: 'je suis une chaîne de deal'},

console.log(constants.note); Ouput:

note: {obj: {type: 'objet', description: 'j’ai un objet note'}}

5
Luis Martins

import et export (probablement besoin de quelque chose comme Babel à partir de 2018 pour utiliser l'importation)

types.js

export const BLUE = 'BLUE'
export const RED = 'RED'

myApp.js

import * as types from './types.js'

const MyApp = () => {
  let colour = types.RED
}

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

4
orangesherbert

Alternativement, vous pouvez regrouper vos valeurs "constantes" dans un objet local et exporter une fonction qui renvoie un clone superficiel de cet objet.

var constants = { FOO: "foo" }

module.exports = function() {
  return Object.assign({}, constants)
}

Dans ce cas, il importe peu que quelqu'un réattribue FOO car cela n'affectera que sa copie locale.

3
herman

Etant donné que Node.js utilise les modèles CommonJS, vous ne pouvez partager des variables entre modules avec module.exports ou en définissant une variable globale comme vous le feriez dans le navigateur, mais au lieu d'utiliser window, utilisez global.your_var = value;.

2
alessioalex

J'ai fini par exporter un objet gelé avec des fonctions de lecture anonymes, plutôt que les constantes elles-mêmes. Cela réduit le risque de mauvaises erreurs introduites en raison d'une simple faute de frappe du nom de const, car une erreur d'exécution sera renvoyée en cas de faute de frappe. Voici un exemple complet qui utilise également les symboles ES6 pour les constantes, garantissant l'unicité, et les fonctions de flèche ES6. J'apprécierais les commentaires si quelque chose dans cette approche semble problématique.

'use strict';
const DIRECTORY = Symbol('the directory of all sheets');
const SHEET = Symbol('an individual sheet');
const COMPOSER = Symbol('the sheet composer');

module.exports = Object.freeze({
  getDirectory: () => DIRECTORY,
  getSheet: () => SHEET,
  getComposer: () => COMPOSER
});
1
Eloquence

Je ne pense pas que ce soit une bonne pratique d'envahir l'espace GLOBAL à partir de modules, mais dans des scénarios où il pourrait être strictement nécessaire de le mettre en œuvre:

Object.defineProperty(global,'MYCONSTANT',{value:'foo',writable:false,configurable:false});

Il faut prendre en compte l'impact de cette ressource. Sans une désignation correcte de ces constantes, le risque de SUPERVISION des variables globales déjà définies est quelque chose de réel.

0
colxi

Je recommande de le faire avec webpack (en supposant que vous utilisez webpack).

La définition de constantes est aussi simple que de définir le fichier de configuration webpack:

var webpack = require('webpack');
module.exports = {
    plugins: [
        new webpack.DefinePlugin({
            'APP_ENV': '"dev"',
            'process.env': {
                'NODE_ENV': '"development"'
            }
        })
    ],    
};

De cette façon, vous les définissez en dehors de votre source et ils seront disponibles dans tous vos fichiers.

0
galki