Node.js 13.2.0 viene con soporte ECMAScript para módulos conocidos por su sintaxis de importación y exportación. Anteriormente, esta funcionalidad estaba detrás de la bandera --experimental-modules
, que ya no es necesaria. Sin embargo, la implementación aún es experimental y está sujeta a cambios.
De un traductor: esta característica tan esperada finalmente nos permitirá usar la sintaxis modular estándar ya disponible en los navegadores modernos, y ahora también en Node.js sin banderas y transpiladores
La activación
Node.js procesará el código como módulos ES en los siguientes casos:
- Archivos con la extensión
.mjs
- Archivos con la extensión
.js
o sin la extensión, siempre que el package.json
principal.json más cercano a ellos contenga el valor "type": "module"
- Código pasado a través del argumento
—-eval
o STDIN, junto con el indicador de —-input-type=module
En todos los demás casos, el código se considerará CommonJS. Esto se aplica a los archivos .js
sin "type": "module"
en el package.json
más cercano y al código pasado a través de la línea de comando sin especificar --input-type
. Esto se hace para mantener la compatibilidad con versiones anteriores. Sin embargo, dado que ahora tenemos dos tipos de módulos, CommonJS y ES, será mejor especificar el tipo de módulos explícitamente.
Puede marcar explícitamente su código como CommonJS con las siguientes características:
- Archivos con la extensión
.cjs
- Archivos con la extensión
.js
o sin extensión, siempre que el package.json
padre más package.json
contenga el valor "type": "“commonjs”"
- Código pasado a través del argumento
--eval
o STDIN con la --input-type=commonjs
explícita --input-type=commonjs
Para obtener más información sobre estas características, consulte las secciones de documentación "Alcance del paquete y Extensiones de archivo" y --input-type
Importación y exportación de sintaxis
En el contexto del módulo ES, puede usar import
, apuntando a otros archivos Javascript. Se pueden especificar en uno de los siguientes formatos:
- URL relativa:
"./file.mjs"
- URL absoluta c
file://
, por ejemplo, "file:///opt/app/file.mjs"
- Nombre del paquete:
"es-module-package"
- La ruta al archivo dentro del paquete:
"es-module-package/lib/file.mjs"
En las importaciones, puede usar valores predeterminados ( import _ from "es-module-package"
) y valores con nombre ( import { shuffle } from "es-module-package"
), así como importar todo como un espacio de nombres ( import * as fs from "fs"
). Todos los paquetes integrados de Node.js, como fs
o path
, admiten los tres tipos de importaciones.
Las importaciones que apuntan al código CommonJS (es decir, todos los JavaScript actuales escritos para Node.js require
y module.exports
) solo pueden usar la opción predeterminada ( import _ from "commonjs-package"
).
La importación de otros formatos de archivo como JSON y WASM sigue siendo experimental, y requiere los indicadores --experimental-json-modules
y --experimental-wasm-modules
respectivamente. Sin embargo, puede descargar estos archivos utilizando la API module.createRequire
, que está disponible sin module.createRequire
adicionales.
En sus módulos ES, puede usar la palabra clave export para exportar valores predeterminados y con nombre.
Las expresiones dinámicas con import()
se pueden usar para cargar módulos ES desde CommonJS o código ES. Tenga en cuenta que import()
no devuelve un módulo sino su promesa (Promise).
import.meta.url
está disponible en los módulos, que contiene la URL absoluta del módulo ES actual.
Archivos y el nuevo campo "tipo" en package.json
Agregue "type": "module"
al package.json de su proyecto, y Node.js comenzará a percibir todos los archivos .js
de su proyecto como módulos ES.
Si algunos archivos de su proyecto todavía usan CommonJS y no puede migrar todo el proyecto a la vez, puede usar la extensión .cjs
para este código o colocarlo en un directorio separado y agregar package.json
contenga { "type": "commonjs" }
, que le dice a Node.js que debe tratarse como CommonJS.
Para cada archivo descargado, Node.js buscará package.json
en el directorio que lo contiene, luego un nivel más y así sucesivamente hasta que llegue al directorio raíz. Este mecanismo es similar a cómo Babel .babelrc
archivos Babel .babelrc
. Este enfoque permite que Node.js use package.json
como fuente de varios metadatos sobre el paquete y la configuración, de forma similar a cómo ya funciona en Babel y otras herramientas.
Recomendamos que todos los desarrolladores de paquetes especifiquen un campo de type
, incluso si commonjs
está escrito commonjs
.
Los puntos de entrada del paquete y el campo "exportaciones" en package.json
Ahora tenemos dos campos para especificar el punto de entrada en el paquete: main
y exports
. El campo main
es compatible con todas las versiones de Node.js, pero sus capacidades son limitadas: con él puede definir solo un punto de entrada principal en el paquete. El nuevo campo de exports
también le permite definir el punto de entrada principal, así como rutas adicionales. Esto proporciona encapsulación adicional para paquetes donde solo las rutas de exports
explícitas están disponibles para importar desde fuera del paquete. exports
aplican a ambos tipos de módulos, CommonJS y ES, sin importar si se usan mediante require
o import
.
Esta funcionalidad permitirá que las importaciones de tipo pkg/feature
apunten a una ruta real como ./node_modules/pkg/esm/feature.js
. Además, Node.js arrojará un error si la importación se refiere a pkg/esm/feature.js
que no se especifica en las exports
.
Una característica adicional, aún experimental, las exportaciones condicionales proporcionan la capacidad de exportar diferentes archivos para diferentes entornos. Esto permitirá que el paquete proporcione el código CommonJS para llamar a require("pkg")
y el código del módulo ES para importar a través de la import "pkg"
, aunque escribir dicho paquete no está exento de otros problemas . Puede habilitar las exportaciones condicionales con el indicador " —-experimental-conditional-exports
.
El rastrillo principal de los nuevos módulos.
Extensiones de archivo requeridas
Cuando use importaciones, debe especificar la extensión del archivo. Al importar un archivo de índice desde un directorio, también debe especificar completamente la ruta al archivo, es decir, "./startup/index.js".
Este comportamiento coincide con el funcionamiento de las importaciones en los navegadores cuando se accede a un servidor normal sin configuración adicional.
module.exports
, exports
, module.exports
, __filename
, __dirname
Estos valores de CommonJS no están disponibles en el contexto de los módulos ES. Sin embargo, require
se puede importar al módulo ES a través de module.createRequire()
. Los equivalentes __filename
y __dirname
se pueden obtener de import.meta.url
.
Creando paquetes
Por el momento, recomendamos que los autores de paquetes utilicen módulos totalmente CommonJS o totalmente ES para sus proyectos Node.js. El grupo de trabajo de módulos para Node.js continúa buscando formas de mejorar el soporte para paquetes duales, con CommonJS para usuarios heredados y módulos ES para nuevos. Las exportaciones condicionales ahora son experimentales y esperamos implementar esta funcionalidad o su alternativa para fines de enero de 2020, o incluso antes.
Para obtener más información sobre esto, consulte nuestros ejemplos y recomendaciones para crear paquetes duales de módulos CommonJS / ES.
¿Qué pasará después?
Cargadores El trabajo continúa en la API para escribir cargadores personalizados, para implementar la transpilación de módulos en tiempo de ejecución, anular rutas de importación (paquetes o archivos individuales) y también instrumentación de código. La API experimental, disponible bajo el indicador " —-experimental-loader
, estará sujeta a modificaciones importantes antes de que la eliminemos del indicador.
Paquetes de módulos duales CommonJS / ES. Queremos proporcionar una forma estándar de publicar un paquete que pueda usarse tanto mediante require
en CommonJS como mediante import
en módulos ES. Tenemos más información sobre esto en la documentación . Planeamos completar el trabajo y retirarnos de la bandera para fines de enero de 2020, si no antes.
Eso es todo! Esperamos que el soporte de ECMAScript para módulos acerque Node.js a los estándares de JavaScript y brinde nuevas características de compatibilidad en todo el ecosistema de JavaScript. El flujo de trabajo para mejorar el soporte del módulo se está haciendo públicamente aquí: https://github.com/nodejs/modules .