En nodejs cuando queremos usar un módulo, paquete o script creado por nosotros debemos importarlo y para eso seguimos la convención commonJs CJS o si tenemos la ultima version podemos usar emacscript module ESM.

Modules - require

Repositorio

En nodejs cuando queremos usar un módulo, paquete o script creado por nosotros debemos importarlo y para eso seguimos la convención commonJs CJS o si tenemos la ultima version podemos usar emacscript module ESM que aun esta en modo experimental.

// CJS
const requiredjs = require("module");

// ESM
import { requirejs } from 'module'; // or import 'module'

Import

El path es la ruta en donde se va a buscar nuestro modulo, existen básicamente dos formas de llamar nuestros módulos: la primera es llamar un módulo del core o un paquete externo que usualmente instalamos con npm y se guarda en la carpeta node_modules, la segunda es llamar un script creado por nosotros mediante su path.

  • Si es un módulo core se busca en la carpeta lib y si es un paquete externo lo va a buscar en una de las jerarquías de la carpeta node_modules, esto lo podemos observar en los paths de nuestro module, los scripts se van a buscar en ese orden.
const http = require('http') // sin path
# Podemos tener un node_module para nuestro archivo, 
# para nuestro proyecto, para nuestro usuario en el sistema o uno global.

# ejecutemos este comando en la ubicación de nuestro archivo y 
# lo comparamos llamandolo fuera de nuestro proyecto.
> node -p "module"
  • Si es un script debemos llamarlo mediante su path el cual puede ser absoluto o relativo.
// absolute path
const myscript = require('/home/user/project/script.js')

// relative path - script se encuentra en la misma carpeta en el mismo nivel
const myscript = require('./script.js') 

Export

Antes de importar un script para usarlo en nuestro archivo este se debe haber exportado, para poder llamarlo y usarlo desde otro archivo.

// square.js
class Square {
    constructor(width) {
      this.width = width;
    }
  
    area() {
      return this.width ** 2;
    }
  };

// se modifica todo el export para que sea la clase
// solo se puede hacer mediante module
module.exports = Square;
// circle.js
const { PI } = Math;

// agrego funciones al export, como un objeto
exports.area = (r) => PI * r ** 2;
exports.circumference = (r) => 2 * PI * r;

Wrapper

Cuando se llama un archivo, internamente nodejs lo manipula para agregarle algunas funciones y metadata, es por esto que podemos obtener información importante, como el require, module, __filename, etc.

// wrapper.js

// import a file
require('./circle')
// export a function
exports.myFunc= (r) => PI * r ** 2;

console.log("Wrapper: ", require('module').wrapper)
console.log("Exports: ", exports)
console.log("Require: ", require)
console.log("Module: ", module)
console.log("Filename: ", __filename)
console.log("Dirname: ", __dirname)

Require

Como lo vimos anteriormente tenemos a module que es la referencia al módulo que estamos corriendo y con require podemos identificar quien ha llamado el módulo y algunas otras propiedades que nos pueden ser útiles para que nuestro script se comporte de una manera si es requerido y de otra si es usado independiente.

// square.js
class Square {
    constructor(width) {
      this.width = width;
    }
  
    area() {
      return this.width ** 2;
    }
  };
 
  if (require.main === module) {
      // Estoy corriendo el script - fue llamado 'node square.js param' desde consola
     if (isNaN(process.argv[2])) throw new Error("missed or wrong parameter")

    const square = new Square(process.argv[2]);
    console.log(`The area of mySquare is ${square.area()}`);
  } else {
      //Fue requerido por otro archivo
      module.exports = Square;
  }

Cache

Cuando cargamos por primera vez un módulo o un archivo este queda guardado gracias al mecanismo de cache de Nodejs, esto significa que la siguiente vez que sea llamado este archivo lo va tomar de la cache, a menos que usemos new en el caso de una clase o que el archivo se pueda resolver con otro path, un ejemplo puede ser llamar un módulo en primera instancia con mayúsculas y después en minúsculas, esto node lo interpreta como algo diferente.

// squareCache.js
class Square {
    
    constructor(width) {
      this.width = width;
      console.log("Square called");
    }
  
    area() {
      return this.width ** 2;
    }
  };

module.exports = new Square('4');
// index.js
const square = require('./squareCache') // 1 call and cached
const square2 = require('./SquareCache') // 2 call because of S in name and cached
const square3 = require('./SquareCache') // none call already cached

console.log(square.area());
console.log(square2.area());
console.log(square3.area());