En un proyecto en el que estoy colaborando, tenemos dos opciones sobre qué sistema de módulos podemos usar:
- Importando módulos usando
require
, y exportando usandomodule.exports
yexports.foo
. - Importar módulos con ES6
import
y exportar con ES6export
¿Hay algún beneficio de rendimiento al usar uno sobre el otro? ¿Hay algo más que deberíamos saber si tuviéramos que usar módulos ES6 sobre nodos?
javascript
node.js
ecmascript-6
babeljs
kpimov
fuente
fuente
node --experimental-modules index.mjs
te permite usarimport
sin Babel y funciona en el Nodo 8.5.0+. También puede (y debe) publicar sus paquetes npm como ESModule nativo , con compatibilidad con versiones anterioresrequire
.Respuestas:
Tenga en cuenta que todavía no hay un motor de JavaScript que admita de forma nativa los módulos ES6. Tú mismo dijiste que estás usando Babel. Babel convierte
import
yexport
declara a CommonJS (require
/module.exports
) de forma predeterminada de todos modos. Entonces, incluso si usa la sintaxis del módulo ES6, usará CommonJS debajo del capó si ejecuta el código en Node.Existen diferencias técnicas entre los módulos CommonJS y ES6, por ejemplo, CommonJS le permite cargar módulos dinámicamente. ES6 no permite esto, pero hay una API en desarrollo para eso .
Como los módulos ES6 son parte del estándar, los usaría.
fuente
ES6 import
conrequire
pero trabajaron de manera diferente. CommonJS exporta la clase en sí mientras solo hay una clase. ES6 exporta como si hubiera varias clases, por lo que debe usar.ClassName
para obtener la clase exportada. ¿Hay alguna otra diferencia que realmentemodule.exports = ...;
es equivalente aexport default ...
.exports.foo = ...
es equivalente aexport var foo = ...
;import
a CommonJS en Node, utilizado junto con Webpack 2 / Rollup (y cualquier otro paquete que permita sacudir el árbol ES6), es posible terminar con un archivo que es significativamente más pequeño que el código equivalente Node crunches mediante el usorequire
exacto debido al hecho de que ES6 permite el análisis estático de importación / exportación. Si bien esto no hará una diferencia para Node (todavía), ciertamente puede hacerlo si el código finalmente va a terminar como un paquete de navegador único.Hay varios usos / capacidades que puede considerar:
Exigir:
require
electrónicos, se cargan y procesan uno por uno.Importaciones ES6:
Además, el sistema del módulo Requerir no está basado en estándares. Es muy poco probable que se convierta en estándar ahora que existen módulos ES6. En el futuro habrá soporte nativo para módulos ES6 en varias implementaciones, lo que será ventajoso en términos de rendimiento.
fuente
require
todos modos, por lo que está utilizando el sistema de módulos de Node y el cargador de todos modos.Las principales ventajas son sintácticas:
Es poco probable que vea beneficios de rendimiento con los módulos ES6. Aún necesitará una biblioteca adicional para agrupar los módulos, incluso cuando haya compatibilidad total con las funciones de ES6 en el navegador.
fuente
node --experimemntal-modules index.mjs
te permite usarloimport
sin Babel. Se puede (y debe) también publicar sus paquetes MNP ESModule nativa, la compatibilidad hacia atrás de la viejarequire
manera. Muchos navegadores también admiten importaciones dinámicas de forma nativa.La respuesta actual es no, porque ninguno de los motores de navegador actuales se implementa
import/export
desde el estándar ES6.Algunos cuadros de comparación http://kangax.github.io/compat-table/es6/ no tienen esto en cuenta, así que cuando vea casi todos los verdes para Chrome, tenga cuidado.
import
La palabra clave de ES6 no se ha tenido en cuenta.En otras palabras, los motores de navegador actuales, incluido V8, no pueden importar archivos JavaScript nuevos desde el archivo JavaScript principal a través de ninguna directiva JavaScript.
(Es posible que aún nos falten algunos errores o que falten años para que V8 lo implemente de acuerdo con la especificación ES6).
Este documento es lo que necesitamos, y este documento es lo que debemos obedecer.
Y el estándar ES6 decía que las dependencias del módulo deberían estar allí antes de leer el módulo como en el lenguaje de programación C, donde teníamos (encabezados)
.h
archivos .Esta es una estructura buena y bien probada, y estoy seguro de que los expertos que crearon el estándar ES6 lo tenían en cuenta.
Esto es lo que permite a Webpack u otros paquetes de paquetes optimizar el paquete en algunos casos especiales y reducir algunas dependencias del paquete que no son necesarias. Pero en casos tenemos dependencias perfectas, esto nunca sucederá.
Necesitará algo de tiempo hasta que se
import/export
active el soporte nativo, y larequire
palabra clave no irá a ningún lado durante mucho tiempo.¿Qué es
require
?Esta es la
node.js
forma de cargar módulos. ( https://github.com/nodejs/node )El nodo utiliza métodos de nivel de sistema para leer archivos. Básicamente confías en eso cuando lo usas
require
.require
finalizará en alguna llamada al sistema comouv_fs_open
(depende del sistema final, Linux, Mac, Windows) para cargar el archivo / módulo de JavaScript.Para comprobar que esto es cierto, intente usar Babel.js y verá que la
import
palabra clave se convertirá enrequire
.fuente
import
en un proceso de compilación de Webpack 2 / Rollup puede reducir potencialmente el tamaño del archivo resultante al 'agitar el árbol' de los módulos / código no utilizados, que de lo contrario podrían terminar en el paquete final. Tamaño de archivo más pequeño = más rápido para descargar = más rápido para iniciar / ejecutar en el cliente.import
palabra clave de forma nativa. O esto significa que no puede importar otro archivo JavaScript desde un archivo JavaScript. Es por eso que no puede comparar los beneficios de rendimiento de estos dos. Pero, por supuesto, herramientas como Webpack1 / 2 o Browserify pueden manejar la compresión. Están cuello a cuello: gist.github.com/substack/68f8d502be42d5cd4942import
yexport
son declaraciones estáticas que importan una ruta de código específico, mientras querequire
puede ser dinámica y, por tanto agrupar en código que no se utiliza. La ventaja de rendimiento es indirect-- webpack 2 y / o el paquete acumulativo puede potencialmente resultar en tamaños de paquete más pequeñas que son más rápidas para descargar, y por lo tanto aparecerá más ágil para el usuario final (de un navegador). Esto solo funciona si todo el código está escrito en módulos ES6 y, por lo tanto, las importaciones pueden analizarse estáticamente.import/export
se convierte arequire
, concedido. Pero lo que sucede antes de este paso podría considerarse una mejora del "rendimiento". Ejemplo: silodash
está escrito en ES6 y ustedimport { omit } from lodash
, el paquete final SOLO contendrá 'omitir' y no las otras utilidades, mientras que un simplerequire('lodash')
importará todo. Esto aumentará el tamaño del paquete, llevará más tiempo descargarlo y, por lo tanto, disminuirá el rendimiento. Esto solo es válido en un contexto de navegador, por supuesto.El uso de módulos ES6 puede ser útil para 'sacudir árboles'; es decir, habilitar Webpack 2, Rollup (u otros paquetes) para identificar rutas de código que no se usan / importan y, por lo tanto, no se incluyen en el paquete resultante. Esto puede reducir significativamente el tamaño de su archivo al eliminar el código que nunca necesitará, pero con CommonJS se incluye de forma predeterminada porque Webpack et al no tienen forma de saber si es necesario.
Esto se realiza mediante análisis estático de la ruta del código.
Por ejemplo, usando:
... le da al paquete una pista que
package.anotherPart
no es necesaria (si no se importa, no se puede usar, ¿verdad?), por lo que no se molestará en agruparlo.Para habilitar esto para Webpack 2, debe asegurarse de que su transpiler no esté escupiendo módulos CommonJS. Si está utilizando el
es2015
complemento con babel, puede deshabilitarlo de la.babelrc
misma manera:El paquete acumulativo y otros pueden funcionar de manera diferente: vea los documentos si está interesado.
fuente
Cuando se trata de una carga asíncrona o tal vez lenta,
import ()
es mucho más potente. Vea cuándo requerimos el componente de manera asíncrona, luego lo usamosimport
de alguna manera asíncrona como en elconst
uso de variablesawait
.O si quieres usar
require()
entonces,La cosa es en
import()
realidad asíncrona en la naturaleza. Como lo menciona neehar venugopal en ReactConf , puede usarlo para cargar dinámicamente componentes de reacción para la arquitectura del lado del cliente.También es mucho mejor cuando se trata de enrutamiento. Esa es la única cosa especial que hace que el registro de red descargue una parte necesaria cuando el usuario se conecta a un sitio web específico a su componente específico. por ejemplo, la página de inicio de sesión antes del tablero no descargará todos los componentes del tablero. Porque lo que se necesita actual es decir, el componente de inicio de sesión, que solo se descargará.
Lo mismo ocurre con
export
: ES6export
son exactamente iguales que para CommonJSmodule.exports
.NOTA - Si está desarrollando un proyecto node.js, entonces debe usarlo estrictamente
require()
como nodo arrojará un error de excepción comoinvalid token 'import'
si fuera a usarimport
. Por lo tanto, el nodo no admite declaraciones de importación.ACTUALIZACIÓN: según lo sugerido por Dan Dascalescu : desde v8.5.0 (lanzado en septiembre de 2017), le
node --experimental-modules index.mjs
permite usarimport
sin Babel. Se puede (y debe) también publicar sus paquetes MNP ESModule nativa, con compatibilidad hacia atrás para la edadrequire
manera.Consulte esto para obtener más autorización sobre dónde usar las importaciones asíncronas: https://www.youtube.com/watch?v=bb6RCrDaxhw
fuente
Lo más importante que debe saber es que los módulos ES6 son, de hecho, un estándar oficial, mientras que los módulos CommonJS (Node.js) no lo son.
En 2019, los módulos ES6 son compatibles con el 84% de los navegadores. Si bien Node.js los coloca detrás de un indicador --experimental-modules , también hay un conveniente paquete de nodos llamado esm , que hace que la integración sea fluida.
Otro problema que es probable que encuentre entre estos sistemas de módulos es la ubicación del código. Node.js supone que la fuente se mantiene en un
node_modules
directorio, mientras que la mayoría de los módulos ES6 se implementan en una estructura de directorio plana. No es fácil conciliarlos, pero se puede hacer pirateando supackage.json
archivo con scripts de instalación previos y posteriores. Aquí hay un ejemplo de módulo isomorfo y un artículo que explica cómo funciona.fuente
Personalmente uso la importación porque, podemos importar los métodos requeridos, miembros, usando la importación.
FileName: dep.js
El crédito va a Paul Shan. Más información .
fuente
require
manera?const {a,b} = require('module.js');
funciona igual ... si exportasa
yb
module.exports = { a: ()={}, b: 22 }
- La segunda parte de @BananaAcid respondeA partir de ahora la importación de ES6, la exportación siempre se compila a CommonJS , por lo que no hay ningún beneficio al usar uno u otro. Aunque se recomienda el uso de ES6, ya que debería ser ventajoso cuando se lanza el soporte nativo de los navegadores. La razón es que puede importar parciales de un archivo, mientras que con CommonJS debe requerir todo el archivo.
ES6 →
import, export default, export
CommonJS →
require, module.exports, exports.foo
A continuación se muestra el uso común de esos.
Exportación ES6 predeterminada
ES6 exporta múltiples e importa múltiples
CommonJS module.exports
Módulo CommonJS exporta múltiples
fuente
No estoy seguro de por qué (probablemente optimización - ¿carga lenta?) Funciona así, pero he notado que es
import
posible que no analice el código si no se utilizan módulos importados.Lo cual puede no ser un comportamiento esperado en algunos casos.
Tome la odiada clase Foo como nuestra dependencia de muestra.
foo.ts
Por ejemplo:
index.ts
index.ts
index.ts
Por otra parte:
index.ts
fuente