Cómo usar module.exports en Node.js

El uso de módulos es una parte esencial de la creación de aplicaciones y sistemas de software completos con Node.js. En ausencia de módulos, su código estaría fragmentado...

El uso de módulos es una parte esencial de la creación de aplicaciones y sistemas de software completos con Node.js. En ausencia de módulos, su código estaría fragmentado y sería difícil de ejecutar, y mucho menos de mantener con el tiempo. Pero, ¿qué es un módulo? ¿Y cómo exactamente se supone que debes usar module.exports para construir tus programas Node.js?

Un módulo es un programa discreto, contenido en un solo archivo en Node.js. Por lo tanto, los módulos están vinculados a archivos, con un módulo por archivo. Los módulos están disponibles en otros lenguajes de programación. Node.JS usa el sistema de módulos CommonJS, pero hay otros tipos de módulos que se usan en el ecosistema de JavaScript. Los más destacados de estos otros sistemas de módulos son la definición de módulo asíncrono (AMD) y los sistemas de módulo ES6 (ECMAScript 6).

Como veremos, module.exports es un objeto que el módulo actual devuelve cuando es "requerido" en otro programa o módulo.

Puede incluir funcionalidad de otros módulos en cualquier otro módulo. Hacerlo se denomina "requerir" el módulo, que simplemente solicita un determinado objeto especial que representa la funcionalidad del módulo.

Compartir código con module.exports

Para el uso diario, los módulos nos permiten componer programas más grandes a partir de piezas más pequeñas. Módulos se convierten en los componentes básicos de la pieza de software más grande que, en conjunto, definen.

Debajo de las cubiertas, el módulo realiza un seguimiento de sí mismo a través de un objeto llamado “módulo”. Dentro de cada módulo, por lo tanto, 'módulo' se refiere al objeto que representa el módulo actual. Este objeto contiene metadatos sobre el módulo, como el nombre de archivo del módulo, así como la identificación del módulo.

Aquí hay un pequeño fragmento de código que puede ejecutar para ver los valores de estas propiedades de ejemplo en un módulo:

1
2
3
4
5
// module1.js

console.log(module.filename);
console.log(module.id);
console.log(module.exports);

Puede ejecutar esto usando el comando node module1.js. Verá, por ejemplo, que la propiedad module.filename se establece en una ruta de archivo que termina con el nombre correcto del archivo en el que existe este módulo, que es module1.js. Aquí hay una salida de ejemplo para el código anterior:

1
2
3
4
$ node module1.js
/Users/scott/projects/sandbox/javascript/module-test/module1.js
.
{}

En Node.js, la práctica de hacer que el código de un módulo esté disponible para que lo usen otros módulos se llama "exportar" valores.

Pero si se va a construir una pieza de software complejo a partir de módulos individuales, es posible que ya esté pensando en las siguientes preguntas:

Pregunta importante #1: ¿Cómo identifica Node.js el módulo "principal" para comenzar a ejecutar el programa?

Node.js identifica el módulo principal que se ejecutará mediante los argumentos que se pasan al ejecutable node. Por ejemplo, si tenemos un módulo contenido en el archivo server.js, junto con otras partes de nuestro programa contenidas en los archivos login.js y music_stream.js, invocando el comando node server.js identifica el módulo servidor como el principal. Ese módulo principal, a su vez, solicitará la funcionalidad de los otros módulos al "requerirlos".

Pregunta importante #2: ¿Cómo comparte un módulo su código con otros módulos?

El objeto módulo tiene una propiedad especial, llamada exportaciones, que es responsable de definir lo que un módulo pone a disposición para que lo usen otros módulos. En la terminología de Node.js, module.exports define los valores que exporta el módulo. Recuerde que "exportar" es simplemente hacer que los objetos o valores estén disponibles para que otros módulos los importen y usen.

Por lo tanto, podemos exportar cualquier valor o función u otro objeto que nos gustaría exportar al adjuntarlo como una propiedad del objeto module.exports. Por ejemplo, si quisiéramos exportar una variable llamada temperatura, podríamos hacerla disponible para su uso fuera del módulo simplemente agregándola como una nueva propiedad de módulo.exportaciones de la siguiente manera:

1
module.exports.temperature = temperature; 

Exportación y solicitud de funciones y variables con module.exports {#exportación y solicitud de funciones y variables con module.exports}

Ahora que hemos visto el significado conceptual de un módulo, así como por qué usamos módulos, pongamos en práctica estas ideas creando un módulo, definiendo funciones y luego exportando esas funciones para que puedan ser utilizadas por otros módulos.

Como ejemplo, aquí hay un nuevo módulo que da recomendaciones de libros. En el siguiente código, he definido una variable y algunas funciones. Posteriormente, accederemos a la funcionalidad de estas recomendaciones de libros desde otro módulo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// book_recommendations.js

// stores the favorite author in a constant variable
const favoriteAuthor = { name: "Ken Bruen", genre: "Noir", nationality: "Irish" };

// returns the favorite book
function favoriteBook() {
    return { title: "The Guards", author: "Ken Bruen" };
}
 
// returns a list of good books
function getBookRecommendations() {
    return [
        {id: 1, title: "The Guards", author: "Ken Bruen"},
        {id: 2, title: "The Stand", author: "Steven King"},
        {id: 3, title: "The Postman Always Rings Twice", author: "James M. Cain"}
    ];
}
 
// exports the variables and functions above so that other modules can use them
module.exports.favoriteAuthor = favoriteAuthor;
module.exports.favoriteBook = favoriteBook;
module.exports.getBookRecommendations = getBookRecommendations;

Hemos agregado todas las variables y funciones que nos gustaría exportar a module.exports como propiedades del objeto. Acabamos de lograr nuestro objetivo de exportar estas funciones y variables desde el módulo book_recommendations.

Ahora veamos cómo podríamos importar este módulo y acceder a su funcionalidad desde otro módulo.

Para importar el módulo, necesitamos usar una palabra clave especial que se usa para importar cosas, y se llama [requerir](https://medium.freecodecamp.org/requiring-modules-in-node-js-everything-you -necesito-saber-e7fbd119be8). Donde module.exports nos permite configurar cosas para la exportación, require nos permite especificar los módulos que se importarán al módulo actual.

La funcionalidad para importar módulos se proporciona en un módulo llamado requerir, disponible en el ámbito global. La exportación principal de este módulo es una función a la que le pasamos la ruta del módulo que nos gustaría importar. Por ejemplo, para importar un módulo definido en music.js, haríamos require('./music'), donde hemos especificado la ruta relativa.

Ahora podemos ver lo fácil que es importar cualquier cosa usando require. Volviendo a nuestro módulo book_recommendations, podemos importarlo y acceder a las funciones que exporta. Esto se muestra en la siguiente lista de códigos. Este módulo imprime un mensaje que describe los regalos de cumpleaños recomendados. Obtiene libros recomendados del módulo de recomendaciones de libros importados y los combina con recomendaciones musicales.

Cree un nuevo módulo como se muestra a continuación, luego ejecútelo como se muestra anteriormente para verlo usando las funciones definidas en el módulo book_recommendations importado.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// birthday_gifts.js

// import the book recommendations module
let books = require('./book_recommendations');

// gets some music recommendations as well
let musicAlbums = [
    { artist: "The Killers", title: "Live From The Royal Albert Hall" },
    { artist: "Eminem", title: "The Marshall Mathers LP" }
];

// the two best items from each category
let topIdeas = function() {
    return [musicAlbums[0], books.favoriteBook()];
}
 
// outputs a message specifying the customer's recommended gifting items
let gifts = function() {
    console.log("Your recommended gifts are:\n");
    console.log("######MUSIC######");

    for (let i = 0, len = musicAlbums.length; i < len; i++) {
        console.log(musicAlbums[i].title + " by " + musicAlbums[i].artist);
    }

    console.log("######BOOKS######");

    let recommendedBooks = books.getBookRecommendations();

    for (let i = 0, len = recommendedBooks.length; i < len; i++) {
        console.log(recommendedBooks[i].title + " by " + recommendedBooks[i].author);
    }

    console.log("\n\nYours");
    console.log("Shop Staff\n*************");
    console.log("P.S. If you have a limited budget, you should just get the music album " + topIdeas()[0].title + " and the book " + topIdeas()[1].title + ".");
}

console.log("Welcome to our gift shop.\n");

// Get the gifts
gifts();

Como puede ver, usamos require para importar el módulo book_recommendations. Dentro del nuevo módulo, podíamos acceder a variables y funciones que habían sido exportadas añadiéndolas a module.exports.

Con ambos módulos completos, al invocar node birthday_gifts.js se imprime un mensaje ordenado con las recomendaciones completas de regalos del cliente. Puedes ver la salida en la siguiente imagen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Welcome to our gift shop.

Your recommended gifts are:

######MUSIC######
Live From The Royal Albert Hall by The Killers
The Marshall Mathers LP by Eminem
######BOOKS######
The Guards by Ken Bruen
The Stand by Steven King
The Postman Always Rings Twice by James M. Cain


Yours
Shop Staff
*************
P.S. If you have a limited budget, you should just get the music album Live From The Royal Albert Hall and the book The Guards.

Este patrón de componer programas Node.js a partir de módulos más pequeños es algo que verás a menudo, como Middleware exprés, por ejemplo.

Exportación y solicitud de clases con module.exports {#exportación y solicitud de clases con module.exports}

Además de funciones y variables, también podemos usar module.exports para exportar otros objetos complejos, como clases. Si no está familiarizado con el uso de clases u otros fundamentos de Node.js, puede consultar nuestra Node.js para guía de principiantes.

En el siguiente ejemplo, creamos una clase Cat que contiene un nombre y una edad para los objetos Cat. Luego exportamos la clase Cat anexándola como una propiedad del objeto module.exports. Como puede ver, esto no es tan diferente de cómo exportamos funciones y variables antes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// cat.js

// constructor function for the Cat class
function Cat(name) {
    this.age = 0;
    this.name = name;
}
 
// now we export the class, so other modules can create Cat objects
module.exports = {
    Cat: Cat
}

Ahora podemos acceder a esta clase Cat importando el módulo cat. Una vez hecho esto, podemos crear nuevos objetos Cat y usarlos en el módulo de importación como se muestra en el siguiente ejemplo. Una vez más, debe intentar ejecutar este código con node cat_school.js para ver los nombres y las edades de los nuevos gatos en el símbolo del sistema.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// cat_school.js

// import the cat module
let cats = require('./cat');
let Cat = cats.Cat;

// creates some cats
let cat1 = new Cat("Manny");
let cat2 = new Cat("Lizzie");

// Let's find out the names and ages of cats in the class
console.log("There are two cats in the class, " + cat1.name + " and " + cat2.name + ".");
console.log("Manny is " + cat1.age + " years old " +  " and Lizzie is " + cat2.age + " years old.");

Como acabamos de ver, se puede exportar una clase adjuntando la clase como una propiedad del objeto module.exports. Primero, creamos una clase usando una función constructora. Luego exportamos la clase usando module.exports. Para usar la clase, la requerimos en otro módulo y luego creamos instancias de la clase.

Para ver un ejemplo de exportación de una clase que se creó con la sintaxis de ES6, consulte la clase “Libro” a continuación.

Una alternativa: Usar las exportaciones abreviadas VS module.exports

Si bien podemos continuar asignando cosas para exportar como propiedades de module.exports, existe una forma abreviada de exportar cosas desde el módulo. Esta forma abreviada implica usar solo exportaciones en lugar de module.exports. Hay algunas diferencias entre los dos. Sin embargo, lo más importante a notar aquí es que debe asignar sus nuevos valores como propiedades del objeto de acceso directo export, y no asignar objetos directamente para sobrescribir el valor de export en sí.

Aquí hay un ejemplo en el que uso esta forma abreviada de exportar un par de objetos de un módulo llamado film_school.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// film_school.js

// a beginner film course
let film101 = {
    professor: 'Mr Caruthers',
    numberOfStudents: 20,
    level: 'easy'
}
 
// an expert film course
let film102 = {
    professor: 'Mrs Duguid',
    numberOfStudents: 8,
    level: 'challenging' 
}
 
// export the courses so other modules can use them
exports.film101 = film101;
exports.film102 = film102;

Observe cómo estamos asignando los objetos como, por ejemplo, exportaciones.película101 = ... en lugar de exportaciones = película101. Esa asignación posterior no exportaría la variable, pero estropearía por completo sus exportaciones de acceso directo.

La exportación realizada de la forma abreviada anterior, podría haberse logrado en la forma larga que hemos usado con module.exports usando las siguientes líneas para la exportación.

1
2
3
// export the courses so other modules can use them
module.exports.film101 = film101;
module.exports.film102 = film102;

También podríamos exportar los dos objetos asignando un objeto directamente a module.exports pero esto no funcionaría con exportaciones.

1
2
3
4
5
// export the courses so other modules can use them
module.exports = {
    film101: film101,
    film102: film102
}

Los dos son muy similares, y con razón. Estas son dos formas de lograr lo mismo, pero las exportaciones pueden causarle problemas si asigna un objeto a las exportaciones de la misma forma que lo haría con module.exports.

Diferencias entre los módulos de Node.js y los módulos de ES6 {#differences betweennodejsmodulesandes6modules}

Los módulos utilizados en Node.js siguen una especificación de módulo conocida como especificación ComúnJS. Las actualizaciones recientes del lenguaje de programación JavaScript, en forma de ES6, especifican cambios en el lenguaje, agregando cosas como una nueva sintaxis de clase y un [sistema de módulos](https://developer.mozilla.org/en-US/docs /Web/JavaScript/Reference/Statements/import). Este sistema de módulos es diferente de los módulos de Node.js. Un módulo en ES6 tiene el siguiente aspecto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// book.js
const favoriteBook = {
    title: "The Guards",
    author: "Ken Bruen"
}

// a Book class using ES6 class syntax
class Book {
    constructor(title, author) {
        this.title = title;
        this.author = author;
    }

    describeBook() {
        let description = this.title + " by " + this.author + ".";
        return description;
    }
}

// exporting looks different from Node.js but is almost as simple
export {favoriteBook, Book};

Para importar este módulo, usaríamos la funcionalidad de importación de ES6, de la siguiente manera.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// library.js

// import the book module
import {favoriteBook, Book} from 'book';

// create some books and get their descriptions
let booksILike = [
    new Book("Under The Dome", "Steven King"),
    new Book("Julius Ceasar", "William Shakespeare")
];

console.log("My favorite book is " + favoriteBook + ".");
console.log("I also like " + booksILike[0].describeBook() + " and " + booksILike[1].describeBook());

Los módulos ES6 parecen casi tan simples como los módulos que hemos usado en Node.js, pero son incompatibles con los módulos de Node.js. Esto tiene que ver con la forma en que los módulos se cargan de manera diferente entre los dos formatos. Si usa un compilador como Babel, puede mezclar y combinar formatos de módulos. Sin embargo, si tiene la intención de codificar en el servidor solo con Node.js, puede apegarse al formato de módulo para Node.js que cubrimos anteriormente.

Más información {#más información}

¿Quiere aprender más sobre los fundamentos de Node.js? Personalmente, recomendaría un curso en línea, como Aprender Node.js de Wes Bos ya que los videos son mucho más fáciles de seguir y usted De hecho, llegaré a construir una aplicación del mundo real.

Conclusión

El uso de module.exports nos permite exportar valores, objetos y estilos desde los módulos de Node.js. Junto con el uso de require para importar otros módulos, tenemos un ecosistema completo para componer programas grandes a partir de partes más pequeñas. Cuando combinamos una serie de módulos que se ocupan de partes únicas de la funcionalidad, podemos crear aplicaciones y sistemas de software más grandes, más útiles, pero fáciles de mantener. .