Skip to content

Módulos: Módulos CommonJS

[Estable: 2 - Estable]

Estable: 2 Estabilidad: 2 - Estable

Los módulos CommonJS son la forma original de empaquetar código JavaScript para Node.js. Node.js también es compatible con el estándar módulos ECMAScript utilizado por los navegadores y otros entornos de ejecución de JavaScript.

En Node.js, cada archivo se trata como un módulo separado. Por ejemplo, considera un archivo llamado foo.js:

js
const circle = require('./circle.js')
console.log(`El área de un círculo de radio 4 es ${circle.area(4)}`)

En la primera línea, foo.js carga el módulo circle.js que está en el mismo directorio que foo.js.

Aquí está el contenido de circle.js:

js
const { PI } = Math

exports.area = r => PI * r ** 2

exports.circumference = r => 2 * PI * r

El módulo circle.js ha exportado las funciones area() y circumference(). Las funciones y los objetos se añaden a la raíz de un módulo especificando propiedades adicionales en el objeto especial exports.

Las variables locales al módulo serán privadas, porque el módulo está envuelto en una función por Node.js (consulta envoltorio del módulo). En este ejemplo, la variable PI es privada para circle.js.

A la propiedad module.exports se le puede asignar un nuevo valor (como una función u objeto).

En el siguiente código, bar.js utiliza el módulo square, que exporta una clase Square:

js
const Square = require('./square.js')
const mySquare = new Square(2)
console.log(`El área de mySquare es ${mySquare.area()}`)

El módulo square se define en square.js:

js
// Asignar a exports no modificará el módulo, debe usar module.exports
module.exports = class Square {
  constructor(width) {
    this.width = width
  }

  area() {
    return this.width ** 2
  }
}

El sistema de módulos CommonJS está implementado en el módulo central module.

Habilitación

Node.js tiene dos sistemas de módulos: módulos CommonJS y módulos ECMAScript.

De forma predeterminada, Node.js tratará lo siguiente como módulos CommonJS:

  • Archivos con extensión .cjs;
  • Archivos con extensión .js cuando el archivo package.json principal más cercano contenga un campo de nivel superior "type" con el valor "commonjs".
  • Archivos con extensión .js o sin extensión, cuando el archivo package.json principal más cercano no contiene un campo de nivel superior "type" o no hay package.json en ninguna carpeta principal; a menos que el archivo contenga sintaxis que genere errores a menos que se evalúe como un módulo ES. Los autores de paquetes deben incluir el campo "type", incluso en paquetes donde todas las fuentes son CommonJS. Ser explícito sobre el type del paquete facilitará que las herramientas de compilación y los cargadores determinen cómo se deben interpretar los archivos del paquete.
  • Archivos con una extensión que no sea .mjs, .cjs, .json, .node o .js (cuando el archivo package.json principal más cercano contenga un campo de nivel superior "type" con un valor de "module", esos archivos serán reconocidos como módulos CommonJS solo si se incluyen a través de require(), no cuando se usan como el punto de entrada de la línea de comandos del programa).

Consulte Determinación del sistema de módulos para obtener más detalles.

Llamar a require() siempre usa el cargador de módulos CommonJS. Llamar a import() siempre usa el cargador de módulos ECMAScript.

Accediendo al módulo principal

Cuando un archivo se ejecuta directamente desde Node.js, require.main se establece en su module. Eso significa que es posible determinar si un archivo se ha ejecutado directamente probando require.main === module.

Para un archivo foo.js, esto será true si se ejecuta a través de node foo.js, pero false si se ejecuta mediante require('./foo').

Cuando el punto de entrada no es un módulo CommonJS, require.main es undefined y el módulo principal está fuera de alcance.

Consejos para el administrador de paquetes

La semántica de la función require() de Node.js fue diseñada para ser lo suficientemente general como para admitir estructuras de directorio razonables. Los programas de administración de paquetes como dpkg, rpm y npm deberían poder construir paquetes nativos a partir de módulos de Node.js sin modificación.

A continuación, ofrecemos una estructura de directorio sugerida que podría funcionar:

Digamos que queremos que la carpeta en /usr/lib/node/\<some-package\>/\<some-version\> contenga el contenido de una versión específica de un paquete.

Los paquetes pueden depender unos de otros. Para instalar el paquete foo, puede ser necesario instalar una versión específica del paquete bar. El paquete bar puede tener dependencias propias y, en algunos casos, estas pueden incluso colisionar o formar dependencias cíclicas.

Debido a que Node.js busca la ruta realpath de cualquier módulo que carga (es decir, resuelve los enlaces simbólicos) y luego busca sus dependencias en las carpetas node_modules, esta situación se puede resolver con la siguiente arquitectura:

  • /usr/lib/node/foo/1.2.3/: Contenido del paquete foo, versión 1.2.3.
  • /usr/lib/node/bar/4.3.2/: Contenido del paquete bar del que depende foo.
  • /usr/lib/node/foo/1.2.3/node_modules/bar: Enlace simbólico a /usr/lib/node/bar/4.3.2/.
  • /usr/lib/node/bar/4.3.2/node_modules/*: Enlaces simbólicos a los paquetes de los que depende bar.

Por lo tanto, incluso si se encuentra un ciclo o si hay conflictos de dependencias, cada módulo podrá obtener una versión de su dependencia que pueda usar.

Cuando el código en el paquete foo hace require('bar'), obtendrá la versión que está enlazada simbólicamente en /usr/lib/node/foo/1.2.3/node_modules/bar. Luego, cuando el código en el paquete bar llama a require('quux'), obtendrá la versión que está enlazada simbólicamente en /usr/lib/node/bar/4.3.2/node_modules/quux.

Además, para hacer que el proceso de búsqueda de módulos sea aún más óptimo, en lugar de colocar los paquetes directamente en /usr/lib/node, podríamos colocarlos en /usr/lib/node_modules/\<name\>/\<version\>. Entonces, Node.js no se molestará en buscar dependencias faltantes en /usr/node_modules o /node_modules.

Para que los módulos estén disponibles para el REPL de Node.js, también podría ser útil agregar la carpeta /usr/lib/node_modules a la variable de entorno $NODE_PATH. Dado que las búsquedas de módulos utilizando las carpetas node_modules son todas relativas y se basan en la ruta real de los archivos que realizan las llamadas a require(), los paquetes en sí pueden estar en cualquier lugar.

Carga de módulos ECMAScript usando require()

[Historial]

VersiónCambios
v23.5.0Esta característica ya no emite una advertencia experimental por defecto, aunque la advertencia todavía puede emitirse por --trace-require-module.
v23.0.0Esta característica ya no está detrás de la bandera CLI --experimental-require-module.
v23.0.0Soporte para la exportación de interop 'module.exports' en require(esm).
v22.0.0, v20.17.0Añadido en: v22.0.0, v20.17.0

[Estable: 1 - Experimental]

Estable: 1 Estabilidad: 1.2 - Candidato para lanzamiento

La extensión .mjs está reservada para Módulos ECMAScript. Consulta la sección Determinación del sistema de módulos para obtener más información sobre qué archivos se analizan como módulos ECMAScript.

require() solo admite la carga de módulos ECMAScript que cumplen los siguientes requisitos:

  • El módulo es totalmente síncrono (no contiene await de nivel superior); y
  • Se cumple una de estas condiciones:

Si el módulo ES que se está cargando cumple los requisitos, require() puede cargarlo y devolver el objeto de espacio de nombres del módulo. En este caso, es similar a import() dinámico, pero se ejecuta de forma síncrona y devuelve el objeto de espacio de nombres directamente.

Con los siguientes módulos ES:

js
// distance.mjs
export function distance(a, b) {
  return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
js
// point.mjs
export default class Point {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
}

Un módulo CommonJS puede cargarlos con require():

js
const distance = require('./distance.mjs')
console.log(distance)
// [Module: null prototype] {
//   distance: [Function: distance]
// }

const point = require('./point.mjs')
console.log(point)
// [Module: null prototype] {
//   default: [class Point],
//   __esModule: true,
// }

Para la interoperabilidad con las herramientas existentes que convierten los módulos ES en CommonJS, que luego podrían cargar módulos ES reales a través de require(), el espacio de nombres devuelto contendría una propiedad __esModule: true si tiene una exportación default para que el código de consumo generado por las herramientas pueda reconocer las exportaciones predeterminadas en los módulos ES reales. Si el espacio de nombres ya define __esModule, esto no se agregaría. Esta propiedad es experimental y puede cambiar en el futuro. Solo debe ser utilizada por herramientas que convierten módulos ES en módulos CommonJS, siguiendo las convenciones de ecosistema existentes. El código creado directamente en CommonJS debería evitar depender de él.

Cuando un módulo ES contiene tanto exportaciones con nombre como una exportación predeterminada, el resultado devuelto por require() es el objeto de espacio de nombres del módulo, que coloca la exportación predeterminada en la propiedad .default, similar a los resultados devueltos por import(). Para personalizar lo que debería devolver require(esm) directamente, el módulo ES puede exportar el valor deseado utilizando el nombre de cadena "module.exports".

js
// point.mjs
export default class Point {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
}

// `distance` se pierde para los consumidores CommonJS de este módulo, a menos que se
// añada a `Point` como una propiedad estática.
export function distance(a, b) {
  return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
export { Point as 'module.exports' }
js
const Point = require('./point.mjs')
console.log(Point) // [class Point]

// Las exportaciones con nombre se pierden cuando se usa 'module.exports'
const { distance } = require('./point.mjs')
console.log(distance) // undefined

Observa en el ejemplo anterior que cuando se utiliza el nombre de exportación module.exports, las exportaciones con nombre se perderán para los consumidores CommonJS. Para permitir que los consumidores CommonJS sigan accediendo a las exportaciones con nombre, el módulo puede asegurarse de que la exportación predeterminada sea un objeto con las exportaciones con nombre adjuntas como propiedades. Por ejemplo, en el ejemplo anterior, distance se puede adjuntar a la exportación predeterminada, la clase Point, como un método estático.

js
export function distance(a, b) {
  return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}

export default class Point {
  constructor(x, y) {
    this.x = x
    this.y = y
  }
  static distance = distance
}

export { Point as 'module.exports' }
js
const Point = require('./point.mjs')
console.log(Point) // [class Point]

const { distance } = require('./point.mjs')
console.log(distance) // [Function: distance]

Si el módulo que se está require() contiene await de nivel superior, o el grafo de módulos que import contiene await de nivel superior, se lanzará ERR_REQUIRE_ASYNC_MODULE. En este caso, los usuarios deberían cargar el módulo asíncrono utilizando import().

Si --experimental-print-required-tla está habilitado, en lugar de lanzar ERR_REQUIRE_ASYNC_MODULE antes de la evaluación, Node.js evaluará el módulo, intentará localizar los awaits de nivel superior e imprimirá su ubicación para ayudar a los usuarios a solucionarlos.

El soporte para la carga de módulos ES utilizando require() es actualmente experimental y se puede deshabilitar utilizando --no-experimental-require-module. Para imprimir dónde se utiliza esta característica, utiliza --trace-require-module.

Esta característica se puede detectar comprobando si process.features.require_module es true.

Todo junto

Para obtener el nombre de archivo exacto que se cargará cuando se llame a require(), utilice la función require.resolve().

Reuniendo todo lo anterior, aquí está el algoritmo de alto nivel en pseudocódigo de lo que hace require():

text
require(X) desde el módulo en la ruta Y
1. Si X es un módulo central,
   a. devuelve el módulo central
   b. DETENER
2. Si X comienza con '/'
   a. establece Y como la raíz del sistema de archivos
3. Si X comienza con './' o '/' o '../'
   a. LOAD_AS_FILE(Y + X)
   b. LOAD_AS_DIRECTORY(Y + X)
   c. LANZAR "no encontrado"
4. Si X comienza con '#'
   a. LOAD_PACKAGE_IMPORTS(X, dirname(Y))
5. LOAD_PACKAGE_SELF(X, dirname(Y))
6. LOAD_NODE_MODULES(X, dirname(Y))
7. LANZAR "no encontrado"

MAYBE_DETECT_AND_LOAD(X)
1. Si X se analiza como un módulo CommonJS, carga X como un módulo CommonJS. DETENER.
2. En caso contrario, si el código fuente de X se puede analizar como módulo ECMAScript utilizando
  <a href="esm#resolver-algorithm-specification">DETECT_MODULE_SYNTAX definido en
  el resolvedor ESM</a>,
  a. Carga X como un módulo ECMAScript. DETENER.
3. LANZAR el SyntaxError al intentar analizar X como CommonJS en 1. DETENER.

LOAD_AS_FILE(X)
1. Si X es un archivo, carga X como su formato de extensión de archivo. DETENER
2. Si X.js es un archivo,
    a. Encuentra el ámbito de paquete SCOPE más cercano a X.
    b. Si no se encontró ningún ámbito
      1. MAYBE_DETECT_AND_LOAD(X.js)
    c. Si el SCOPE/package.json contiene el campo "type",
      1. Si el campo "type" es "module", carga X.js como un módulo ECMAScript. DETENER.
      2. Si el campo "type" es "commonjs", carga X.js como un módulo CommonJS. DETENER.
    d. MAYBE_DETECT_AND_LOAD(X.js)
3. Si X.json es un archivo, carga X.json a un objeto JavaScript. DETENER
4. Si X.node es un archivo, carga X.node como complemento binario. DETENER

LOAD_INDEX(X)
1. Si X/index.js es un archivo
    a. Encuentra el ámbito de paquete SCOPE más cercano a X.
    b. Si no se encontró ningún ámbito, carga X/index.js como un módulo CommonJS. DETENER.
    c. Si el SCOPE/package.json contiene el campo "type",
      1. Si el campo "type" es "module", carga X/index.js como un módulo ECMAScript. DETENER.
      2. En caso contrario, carga X/index.js como un módulo CommonJS. DETENER.
2. Si X/index.json es un archivo, analiza X/index.json a un objeto JavaScript. DETENER
3. Si X/index.node es un archivo, carga X/index.node como complemento binario. DETENER

LOAD_AS_DIRECTORY(X)
1. Si X/package.json es un archivo,
   a. Analiza X/package.json y busca el campo "main".
   b. Si "main" es un valor falso, GOTO 2.
   c. sea M = X + (campo principal json)
   d. LOAD_AS_FILE(M)
   e. LOAD_INDEX(M)
   f. LOAD_INDEX(X) DEPRECATED
   g. LANZAR "no encontrado"
2. LOAD_INDEX(X)

LOAD_NODE_MODULES(X, START)
1. sea DIRS = NODE_MODULES_PATHS(START)
2. para cada DIR en DIRS:
   a. LOAD_PACKAGE_EXPORTS(X, DIR)
   b. LOAD_AS_FILE(DIR/X)
   c. LOAD_AS_DIRECTORY(DIR/X)

NODE_MODULES_PATHS(START)
1. sea PARTS = path split(START)
2. sea I = recuento de PARTS - 1
3. sea DIRS = []
4. mientras I >= 0,
   a. si PARTS[I] = "node_modules", GOTO d.
   b. DIR = path join(PARTS[0 .. I] + "node_modules")
   c. DIRS = DIR + DIRS
   d. sea I = I - 1
5. devuelve DIRS + GLOBAL_FOLDERS

LOAD_PACKAGE_IMPORTS(X, DIR)
1. Encuentra el ámbito de paquete SCOPE más cercano a DIR.
2. Si no se encontró ningún ámbito, regresa.
3. Si el "imports" de SCOPE/package.json es nulo o indefinido, regresa.
4. Si `--experimental-require-module` está habilitado
  a. sea CONDITIONS = ["node", "require", "module-sync"]
  b. En caso contrario, sea CONDITIONS = ["node", "require"]
5. sea MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE),
  CONDITIONS) <a href="esm#resolver-algorithm-specification">definido en el resolvedor ESM</a>.
6. RESOLVE_ESM_MATCH(MATCH).

LOAD_PACKAGE_EXPORTS(X, DIR)
1. Intenta interpretar X como una combinación de NAME y SUBPATH donde el nombre
   puede tener un prefijo @scope/ y la subruta comienza con una barra (`/`).
2. Si X no coincide con este patrón o DIR/NAME/package.json no es un archivo,
   regresa.
3. Analiza DIR/NAME/package.json y busca el campo "exports".
4. Si "exports" es nulo o indefinido, regresa.
5. Si `--experimental-require-module` está habilitado
  a. sea CONDITIONS = ["node", "require", "module-sync"]
  b. En caso contrario, sea CONDITIONS = ["node", "require"]
6. sea MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH,
   `package.json` "exports", CONDITIONS) <a href="esm#resolver-algorithm-specification">definido en el resolvedor ESM</a>.
7. RESOLVE_ESM_MATCH(MATCH)

LOAD_PACKAGE_SELF(X, DIR)
1. Encuentra el ámbito de paquete SCOPE más cercano a DIR.
2. Si no se encontró ningún ámbito, regresa.
3. Si el "exports" de SCOPE/package.json es nulo o indefinido, regresa.
4. Si el "name" de SCOPE/package.json no es el primer segmento de X, regresa.
5. sea MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE),
   "." + X.slice("name".length), `package.json` "exports", ["node", "require"])
   <a href="esm#resolver-algorithm-specification">definido en el resolvedor ESM</a>.
6. RESOLVE_ESM_MATCH(MATCH)

RESOLVE_ESM_MATCH(MATCH)
1. sea RESOLVED_PATH = fileURLToPath(MATCH)
2. Si el archivo en RESOLVED_PATH existe, carga RESOLVED_PATH como su extensión
   formato. DETENER
3. LANZAR "no encontrado"

Almacenamiento en caché

Los módulos se almacenan en caché después de la primera vez que se cargan. Esto significa (entre otras cosas) que cada llamada a require('foo') obtendrá exactamente el mismo objeto devuelto, si se resuelve al mismo archivo.

Siempre que require.cache no se modifique, múltiples llamadas a require('foo') no harán que el código del módulo se ejecute varias veces. Esta es una característica importante. Con ella, se pueden devolver objetos "parcialmente terminados", lo que permite que las dependencias transitivas se carguen incluso cuando causen ciclos.

Para que un módulo ejecute el código varias veces, exporte una función y llame a esa función.

Advertencias sobre el almacenamiento en caché de módulos

Los módulos se almacenan en caché según su nombre de archivo resuelto. Dado que los módulos pueden resolverse a un nombre de archivo diferente según la ubicación del módulo que llama (carga desde carpetas node_modules), no es una garantía que require('foo') siempre devuelva exactamente el mismo objeto, si se resuelve a diferentes archivos.

Además, en sistemas de archivos o sistemas operativos que no distinguen entre mayúsculas y minúsculas, diferentes nombres de archivo resueltos pueden apuntar al mismo archivo, pero la caché aún los tratará como módulos diferentes y volverá a cargar el archivo varias veces. Por ejemplo, require('./foo') y require('./FOO') devuelven dos objetos diferentes, independientemente de si ./foo y ./FOO son el mismo archivo.

Módulos integrados

[Historial]

VersiónCambios
v16.0.0, v14.18.0Se añadió el soporte de importación node: a require(...).

Node.js tiene varios módulos compilados en el binario. Estos módulos se describen con mayor detalle en otras partes de esta documentación.

Los módulos integrados se definen dentro del código fuente de Node.js y se encuentran en la carpeta lib/.

Los módulos integrados se pueden identificar usando el prefijo node:, en cuyo caso se omite la caché de require. Por ejemplo, require('node:http') siempre devolverá el módulo HTTP integrado, incluso si hay una entrada en require.cache con ese nombre.

Algunos módulos integrados siempre se cargan preferentemente si su identificador se pasa a require(). Por ejemplo, require('http') siempre devolverá el módulo HTTP integrado, incluso si hay un archivo con ese nombre. La lista de módulos integrados que se pueden cargar sin usar el prefijo node: se expone en module.builtinModules, listados sin el prefijo.

Módulos incorporados con el prefijo node: obligatorio

Cuando se cargan mediante require(), algunos módulos incorporados deben solicitarse con el prefijo node:. Este requisito existe para evitar que los módulos incorporados recientemente introducidos entren en conflicto con los paquetes de usuario que ya han tomado el nombre. Actualmente, los módulos incorporados que requieren el prefijo node: son:

La lista de estos módulos se expone en module.builtinModules, incluyendo el prefijo.

Ciclos

Cuando hay llamadas require() circulares, es posible que un módulo no haya terminado de ejecutarse cuando se devuelve.

Consideremos esta situación:

a.js:

js
console.log('a starting')
exports.done = false
const b = require('./b.js')
console.log('in a, b.done = %j', b.done)
exports.done = true
console.log('a done')

b.js:

js
console.log('b starting')
exports.done = false
const a = require('./a.js')
console.log('in b, a.done = %j', a.done)
exports.done = true
console.log('b done')

main.js:

js
console.log('main starting')
const a = require('./a.js')
const b = require('./b.js')
console.log('in main, a.done = %j, b.done = %j', a.done, b.done)

Cuando main.js carga a.js, entonces a.js a su vez carga b.js. En ese punto, b.js intenta cargar a.js. Para evitar un bucle infinito, se devuelve una copia inacabada del objeto exports de a.js al módulo b.js. A continuación, b.js termina de cargarse y su objeto exports se proporciona al módulo a.js.

Para cuando main.js ha cargado ambos módulos, ambos han terminado. La salida de este programa sería por lo tanto:

bash
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true

Se requiere una planificación cuidadosa para que las dependencias modulares cíclicas funcionen correctamente dentro de una aplicación.

Módulos de archivo

Si no se encuentra el nombre de archivo exacto, Node.js intentará cargar el nombre de archivo requerido con las extensiones añadidas: .js, .json y, finalmente, .node. Al cargar un archivo que tiene una extensión diferente (por ejemplo, .cjs), su nombre completo debe pasarse a require(), incluida su extensión de archivo (por ejemplo, require('./file.cjs')).

Los archivos .json se analizan como archivos de texto JSON, los archivos .node se interpretan como módulos de complementos compilados cargados con process.dlopen(). Los archivos que utilizan cualquier otra extensión (o ninguna extensión en absoluto) se analizan como archivos de texto de JavaScript. Consulte la sección Determinación del sistema de módulos para comprender qué objetivo de análisis se utilizará.

Un módulo requerido con el prefijo '/' es una ruta absoluta al archivo. Por ejemplo, require('/home/marco/foo.js') cargará el archivo en /home/marco/foo.js.

Un módulo requerido con el prefijo './' es relativo al archivo que llama a require(). Es decir, circle.js debe estar en el mismo directorio que foo.js para que require('./circle') lo encuentre.

Sin un prefijo '/', './' o '../' para indicar un archivo, el módulo debe ser un módulo central o se carga desde una carpeta node_modules.

Si la ruta dada no existe, require() lanzará un error MODULE_NOT_FOUND.

Carpetas como módulos

[Estable: 3 - Heredado]

Estable: 3 Estabilidad: 3 - Heredado: Utilice exportaciones de subrutas o importaciones de subrutas en su lugar.

Hay tres formas en las que una carpeta puede pasarse a require() como argumento.

La primera es crear un archivo package.json en la raíz de la carpeta, que especifique un módulo main. Un ejemplo de archivo package.json podría ser así:

json
{ "name": "some-library", "main": "./lib/some-library.js" }

Si esto estuviera en una carpeta en ./some-library, entonces require('./some-library') intentaría cargar ./some-library/lib/some-library.js.

Si no hay un archivo package.json presente en el directorio, o si la entrada "main" falta o no se puede resolver, entonces Node.js intentará cargar un archivo index.js o index.node de ese directorio. Por ejemplo, si no hubiera un archivo package.json en el ejemplo anterior, entonces require('./some-library') intentaría cargar:

  • ./some-library/index.js
  • ./some-library/index.node

Si estos intentos fallan, entonces Node.js reportará todo el módulo como faltante con el error predeterminado:

bash
Error: Cannot find module 'some-library'

En los tres casos anteriores, una llamada import('./some-library') resultaría en un error ERR_UNSUPPORTED_DIR_IMPORT. El uso de exportaciones de subrutas o importaciones de subrutas puede proporcionar los mismos beneficios de organización de contención que las carpetas como módulos, y funciona tanto para require como para import.

Cargando desde carpetas node_modules

Si el identificador del módulo pasado a require() no es un módulo incorporado, y no comienza con '/', '../' o './', entonces Node.js comienza en el directorio del módulo actual, y agrega /node_modules, e intenta cargar el módulo desde esa ubicación. Node.js no agregará node_modules a una ruta que ya termine en node_modules.

Si no se encuentra allí, entonces se mueve al directorio principal, y así sucesivamente, hasta que se alcanza la raíz del sistema de archivos.

Por ejemplo, si el archivo en '/home/ry/projects/foo.js' llamara a require('bar.js'), entonces Node.js buscaría en las siguientes ubicaciones, en este orden:

  • /home/ry/projects/node_modules/bar.js
  • /home/ry/node_modules/bar.js
  • /home/node_modules/bar.js
  • /node_modules/bar.js

Esto permite a los programas localizar sus dependencias, para que no choquen.

Es posible requerir archivos específicos o submódulos distribuidos con un módulo incluyendo un sufijo de ruta después del nombre del módulo. Por ejemplo, require('example-module/path/to/file') resolvería path/to/file en relación a dónde se encuentra example-module. La ruta con sufijo sigue la misma semántica de resolución de módulos.

Cargando desde las carpetas globales

Si la variable de entorno NODE_PATH está establecida en una lista de rutas absolutas delimitadas por dos puntos, entonces Node.js buscará módulos en esas rutas si no se encuentran en otro lugar.

En Windows, NODE_PATH está delimitada por punto y coma (;) en lugar de dos puntos.

NODE_PATH fue creada originalmente para admitir la carga de módulos desde diferentes rutas antes de que se definiera el algoritmo actual de resolución de módulos.

NODE_PATH todavía es compatible, pero es menos necesaria ahora que el ecosistema de Node.js se ha establecido en una convención para ubicar los módulos dependientes. A veces, las implementaciones que dependen de NODE_PATH muestran un comportamiento sorprendente cuando las personas no saben que NODE_PATH debe establecerse. A veces, las dependencias de un módulo cambian, lo que hace que se cargue una versión diferente (o incluso un módulo diferente) a medida que se busca en la NODE_PATH.

Además, Node.js buscará en la siguiente lista de GLOBAL_FOLDERS:

  • 1: $HOME/.node_modules
  • 2: $HOME/.node_libraries
  • 3: $PREFIX/lib/node

Donde $HOME es el directorio de inicio del usuario y $PREFIX es el node_prefix configurado de Node.js.

Estas son principalmente por razones históricas.

Se recomienda encarecidamente colocar las dependencias en la carpeta local node_modules. Estos se cargarán más rápido y de manera más confiable.

El envoltorio del módulo

Antes de que se ejecute el código de un módulo, Node.js lo envolverá con un envoltorio de función que se parece al siguiente:

js
;(function (exports, require, module, __filename, __dirname) {
  // El código del módulo vive aquí
})

Al hacer esto, Node.js logra varias cosas:

  • Mantiene las variables de nivel superior (definidas con var, const o let) en el ámbito del módulo en lugar del objeto global.
  • Ayuda a proporcionar algunas variables de aspecto global que en realidad son específicas del módulo, como:
    • Los objetos module y exports que el implementador puede usar para exportar valores del módulo.
    • Las variables de conveniencia __filename y __dirname, que contienen el nombre de archivo absoluto y la ruta del directorio del módulo.

El ámbito del módulo

__dirname

Añadido en: v0.1.27

El nombre del directorio del módulo actual. Esto es lo mismo que el path.dirname() de __filename.

Ejemplo: ejecutar node example.js desde /Users/mjr

js
console.log(__dirname)
// Imprime: /Users/mjr
console.log(path.dirname(__filename))
// Imprime: /Users/mjr

__filename

Agregado en: v0.0.1

El nombre de archivo del módulo actual. Esta es la ruta absoluta del archivo del módulo actual con los enlaces simbólicos resueltos.

Para un programa principal, esto no es necesariamente lo mismo que el nombre de archivo utilizado en la línea de comandos.

Consulta __dirname para el nombre del directorio del módulo actual.

Ejemplos:

Ejecutando node example.js desde /Users/mjr

js
console.log(__filename)
// Imprime: /Users/mjr/example.js
console.log(__dirname)
// Imprime: /Users/mjr

Dados dos módulos: a y b, donde b es una dependencia de a y hay una estructura de directorios de:

  • /Users/mjr/app/a.js
  • /Users/mjr/app/node_modules/b/b.js

Las referencias a __filename dentro de b.js devolverán /Users/mjr/app/node_modules/b/b.js, mientras que las referencias a __filename dentro de a.js devolverán /Users/mjr/app/a.js.

exports

Agregado en: v0.1.12

Una referencia a module.exports que es más corta de escribir. Consulta la sección sobre el atajo exports para obtener detalles sobre cuándo usar exports y cuándo usar module.exports.

module

Agregado en: v0.1.16

Una referencia al módulo actual, consulta la sección sobre el objeto module. En particular, module.exports se utiliza para definir lo que un módulo exporta y hace disponible a través de require().

require(id)

Agregado en: v0.1.13

  • id <string> nombre o ruta del módulo
  • Devuelve: <any> contenido del módulo exportado

Se utiliza para importar módulos, JSON y archivos locales. Los módulos se pueden importar desde node_modules. Los módulos locales y los archivos JSON se pueden importar utilizando una ruta relativa (p. ej., ./, ./foo, ./bar/baz, ../foo) que se resolverá con respecto al directorio nombrado por __dirname (si se define) o el directorio de trabajo actual. Las rutas relativas de estilo POSIX se resuelven de forma independiente del sistema operativo, lo que significa que los ejemplos anteriores funcionarán en Windows de la misma manera que lo harían en los sistemas Unix.

js
// Importando un módulo local con una ruta relativa al `__dirname` o al
// directorio de trabajo actual. (En Windows, esto se resolvería como .\path\myLocalModule).
const myLocalModule = require('./path/myLocalModule')

// Importando un archivo JSON:
const jsonData = require('./path/filename.json')

// Importando un módulo desde node_modules o un módulo integrado de Node.js:
const crypto = require('node:crypto')

require.cache

Agregado en: v0.3.0

Los módulos se almacenan en caché en este objeto cuando se requieren. Al eliminar un valor clave de este objeto, el siguiente require recargará el módulo. Esto no se aplica a los complementos nativos, para los cuales la recarga resultará en un error.

También es posible agregar o reemplazar entradas. Esta caché se verifica antes que los módulos integrados y si se agrega un nombre que coincida con un módulo integrado a la caché, solo las llamadas a require con el prefijo node: recibirán el módulo integrado. ¡Úselo con cuidado!

js
const assert = require('node:assert')
const realFs = require('node:fs')

const fakeFs = {}
require.cache.fs = { exports: fakeFs }

assert.strictEqual(require('fs'), fakeFs)
assert.strictEqual(require('node:fs'), realFs)

require.extensions

Agregado en: v0.3.0

Obsoleto desde: v0.10.6

[Estable: 0 - Obsoleto]

Estable: 0 Estabilidad: 0 - Obsoleto

Instruye a require sobre cómo manejar ciertas extensiones de archivo.

Procese los archivos con la extensión .sjs como .js:

js
require.extensions['.sjs'] = require.extensions['.js']

Obsoleto. En el pasado, esta lista se ha utilizado para cargar módulos que no son de JavaScript en Node.js compilándolos bajo demanda. Sin embargo, en la práctica, hay formas mucho mejores de hacer esto, como cargar módulos a través de algún otro programa de Node.js o compilarlos a JavaScript con anticipación.

Evite usar require.extensions. Su uso podría causar errores sutiles y la resolución de las extensiones se vuelve más lenta con cada extensión registrada.

require.main

Agregado en: v0.1.17

El objeto Module que representa el script de entrada cargado cuando se inicia el proceso de Node.js, o undefined si el punto de entrada del programa no es un módulo CommonJS. Consulta "Acceder al módulo principal".

En el script entry.js:

js
console.log(require.main)
bash
node entry.js
js
Module {
  id: '.',
  path: '/ruta/absoluta/a',
  exports: {},
  filename: '/ruta/absoluta/a/entry.js',
  loaded: false,
  children: [],
  paths:
   [ '/ruta/absoluta/a/node_modules',
     '/ruta/absoluta/node_modules',
     '/ruta/absoluta/node_modules',
     '/node_modules' ] }

require.resolve(request[, options])

[Historial]

VersiónCambios
v8.9.0Ahora se admite la opción paths.
v0.3.0Agregado en: v0.3.0
  • request <string> La ruta del módulo a resolver.

  • options <Object>

    • paths <string[]> Rutas desde las que resolver la ubicación del módulo. Si están presentes, estas rutas se utilizan en lugar de las rutas de resolución predeterminadas, con la excepción de las CARPETAS_GLOBALES como $HOME/.node_modules, que siempre se incluyen. Cada una de estas rutas se utiliza como punto de partida para el algoritmo de resolución de módulos, lo que significa que la jerarquía node_modules se comprueba desde esta ubicación.
  • Devuelve: <string>

Utiliza el mecanismo interno require() para buscar la ubicación de un módulo, pero en lugar de cargar el módulo, simplemente devuelve el nombre de archivo resuelto.

Si no se puede encontrar el módulo, se lanza un error MODULE_NOT_FOUND.

require.resolve.paths(request)

Agregado en: v8.9.0

Devuelve un array que contiene las rutas buscadas durante la resolución de request o null si la cadena request hace referencia a un módulo principal, por ejemplo, http o fs.

El objeto module

Agregado en: v0.1.16

En cada módulo, la variable libre module es una referencia al objeto que representa el módulo actual. Para mayor comodidad, también se puede acceder a module.exports a través del módulo global exports. module no es realmente un global sino local para cada módulo.

module.children

Agregado en: v0.1.16

Los objetos de módulo requeridos por primera vez por este.

module.exports

Agregado en: v0.1.16

El objeto module.exports es creado por el sistema Module. A veces esto no es aceptable; muchos quieren que su módulo sea una instancia de alguna clase. Para hacer esto, asigna el objeto de exportación deseado a module.exports. Asignar el objeto deseado a exports simplemente volverá a vincular la variable local exports, lo que probablemente no sea lo deseado.

Por ejemplo, supongamos que estuviéramos haciendo un módulo llamado a.js:

js
const EventEmitter = require('node:events')

module.exports = new EventEmitter()

// Hacer algo de trabajo, y después de un tiempo emitir
// el evento 'ready' desde el propio módulo.
setTimeout(() => {
  module.exports.emit('ready')
}, 1000)

Luego, en otro archivo podríamos hacer:

js
const a = require('./a')
a.on('ready', () => {
  console.log('el módulo "a" está listo')
})

La asignación a module.exports debe hacerse inmediatamente. No se puede hacer en ninguna devolución de llamada. Esto no funciona:

x.js:

js
setTimeout(() => {
  module.exports = { a: 'hola' }
}, 0)

y.js:

js
const x = require('./x')
console.log(x.a)

Atajo exports

Añadido en: v0.1.16

La variable exports está disponible dentro del alcance a nivel de archivo de un módulo, y se le asigna el valor de module.exports antes de que se evalúe el módulo.

Permite un atajo, de modo que module.exports.f = ... se pueda escribir de forma más concisa como exports.f = .... Sin embargo, tenga en cuenta que, como cualquier variable, si se asigna un nuevo valor a exports, ya no está vinculado a module.exports:

js
module.exports.hello = true // Exportado desde require del módulo
exports = { hello: false } // No exportado, solo disponible en el módulo

Cuando la propiedad module.exports se está reemplazando completamente por un nuevo objeto, es común reasignar también exports:

js
module.exports = exports = function Constructor() {
  // ... etc.
}

Para ilustrar el comportamiento, imagine esta implementación hipotética de require(), que es bastante similar a lo que realmente hace require():

js
function require(/* ... */) {
  const module = { exports: {} }
  ;((module, exports) => {
    // Código del módulo aquí. En este ejemplo, definir una función.
    function someFunc() {}
    exports = someFunc
    // En este punto, exports ya no es un atajo para module.exports, y
    // este módulo todavía exportará un objeto vacío predeterminado.
    module.exports = someFunc
    // En este punto, el módulo ahora exportará someFunc, en lugar del
    // objeto predeterminado.
  })(module, module.exports)
  return module.exports
}

module.filename

Agregado en: v0.1.16

El nombre de archivo completamente resuelto del módulo.

module.id

Agregado en: v0.1.16

El identificador del módulo. Normalmente, este es el nombre de archivo completamente resuelto.

module.isPreloading

Agregado en: v15.4.0, v14.17.0

  • Tipo: <boolean> true si el módulo se está ejecutando durante la fase de precarga de Node.js.

module.loaded

Agregado en: v0.1.16

Indica si el módulo ha terminado de cargarse o está en proceso de carga.

module.parent

Obsoleto desde: v14.6.0, v12.19.0

[Estable: 0 - Obsoleto]

Estable: 0 Estabilidad: 0 - Obsoleto: Por favor, use require.main y module.children en su lugar.

El módulo que primero requirió este, o null si el módulo actual es el punto de entrada del proceso actual, o undefined si el módulo fue cargado por algo que no es un módulo CommonJS (E.J.: REPL o import).

module.path

Agregado en: v11.14.0

El nombre del directorio del módulo. Esto suele ser lo mismo que el path.dirname() de module.id.

module.paths

Agregado en: v0.4.0

Las rutas de búsqueda del módulo.

module.require(id)

Agregado en: v0.5.1

El método module.require() proporciona una forma de cargar un módulo como si se llamara a require() desde el módulo original.

Para hacer esto, es necesario obtener una referencia al objeto module. Dado que require() devuelve module.exports y el module normalmente solo está disponible dentro del código de un módulo específico, debe exportarse explícitamente para poder utilizarse.

El objeto Module

Esta sección se movió a Módulos: Módulo central module.

Soporte para source map v3

Esta sección se movió a Módulos: Módulo central module.