Skip to content

undefinedschool/notes-es6-modules

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 

Repository files navigation

✨ ES6: Modules

¿Para qué sirven?

  • Los módulos nos permiten exportar e importar diferentes partes de código, entre diferentes archivos, lo cual nos permite modularizar el código
  • Un módulo no es más que un archivo (en este caso JS) que importamos/exportamos desde o hacia otro archivo para utilizarlo
  • Definición cheta: un módulo es una unidad independiente (autocontenida) de código reutilizable, que podemos exportar para luego importarla y utilizarla en otro archivo (ó módulo)
  • Otra: los módulos nos permiten encapsular funcionalidad y exponerla a otros archivos JS, como si se tratase de librerías (biliotecas)

Motivación (o sea... ¿por qué usarlos?)

  • Para organizar mejor nuestro código.
  • Igual, si, código más organizado => código más legible, simple, conciso, más fácil de razonar => más mantenible

Otros problemas que resuelven los módulos

  • Duplicación de código
  • Namespacing (evitar la colisión de nombres de variables, funciones, clases, etc)
  • Dependency Tree (cargar las dependencias necesarias, en el orden correcto)
  • etc

Antes de ES6 Modules

  • Cargábamos los diferentes script tags a mano en el HTML
    • Si los cargábamos en orden incorrecto (según las dependencias), no funcionaba
    • Genera problemas de performance/usabilidad: hasta que no se termina de cargar un script, no se carga el siguiente y así, porque es render-blocking
    • tl;dr Hacer esto a mano es bastante molesto, perdemos mucho tiempo y casi siempre sale mal (la palabra técnica para eso es error-prone 😁)
  • Antes de ES6 Modules, No teníamos una forma nativa (y standard) de cómo usar módulos en JS
  • Más tarde fueron apareciendo diferentes soluciones de terceros (CommonJS, AMD, UMD, Browserify, etc) y era medio un complejo por temas de compatibilidad, etc
  • Aparecen los package bundlers/module loaders que nos simplifican un poco la vida y hacen el trabajo sucio por nosotros, pero agregamos más herramientas y capas de complejidad a nuestro código

Dependencias e interfaz

  • Llamamos dependencias a la funcionalidad/valores que importamos en un archivo. Cuando un módulo importa funcionalidad de otro módulo, decimos que depende o tiene como dependencia a ese otro módulo
  • Llamamos interfaz a la funcionalidad/valores que un módulo provee (exporta) al resto. Un módulo sólo puede importar funcionalidad que forme parte de la interfaz de otor módulo. Todo lo que no se exporta es privado dentro de un módulo y no puede ser usado fuera del mismo

¿Qué podemos exportar? (e importar)

  • variables/constantes
  • objetos
  • funciones
  • clases

Soporte

Recíen a mediados del 2018 esta feature comenzó a tener más soporte, por lo que en algunos browsers posiblemente tengamos que usar herramientas (aka package bundlers) como Webpack o Parcel, para compilar nuestros módulos de ES6 a una sintaxis que el browser entienda.

Uso

  • Named export: Lo usamos cuando queremos indicar explícitamente qué exportamos y con qué nombre. Permite exportar múltiples valores por archivo. Necesitamos usar {} en el import y llamarlo con el mismo nombre con el que fue exportado (ó usar un alias). Si el nombre no matchea con ningún export, va a importar el default
export const package = {};

import { package } from './module-name.js';
// Podemos exportar múltiples valores
const a = 1;
const b = 2;
const c = 3;

export { a, b, c };

// Y después importar sólo los que vamos a usar (con destructuring!)
import { a, b } from './module-name.js'

// En el caso de ser necesario, podemos renombrar los imports, suando 'as'
import { a as one } from './module-name.js'
  • Default export: Lo usamos generalmente cuando exportamos un único valor. Sólo puede haber un default export por módulo. No necesitamos usar {} en el import y podemos ponerle el nombre que querramos
export default const package = {};

import package from './module-name.js';
  • Nota: podemos usar named y default exports en el mismo módulo

  • Wildcard export: Lo usamos si queremos importar todo lo que otro módulo exporta

const a = 1;
const b = 2;
const c = 3;

export { a, b, c };

// Importamos a, b y c
import * from './module-name.js'
// Exportar todos los _named export_ a un objeto
import * as MainComponents from "./MyComponent";
// Usamos MainComponents.MyComponent y MainComponents.MyComponent2 por ejemplo
  • Absolute path: También podemos usar paths absolutos para referenciar módulos que se encuentran en otro dominio
import toUpperCase from 'https://git.io/fjjGt'

Usando ES6 modules en el browser

  • Tenemos que agregar el atributo type="module" a nuestros tags script para que el browser los cargue como ES6 Modules
  • Ojo con el tema de CORS, necesitamos levantar los archivos en un server. Algunas opciones: Live Server, http-server
  • Para browsers sin soporte, podemos definir un script con al atributo nomodule como fallback
<script type="module" src="module.js"></script>
<script nomodule src="fallback.js"></script>

Node

  • Node utiliza CommonJS como sistema de módulos desde hace mucho tiempo
const package = require('module-name');
  • Gracias a esta feature de ES6, podemos estandarizar y unificar la forma de usarlos. En la versión 12, el soporte para ES6 modules mejoró mucho

Tips

  • Poner los imports siempre al inicio del archivo JS
  • Si el archivo exporta una sola cosa, usar export default
  • Los Named imports llevan {}, los default no
  • Si el path no es absoluto, no olvidarnos de usar ./ o / antes del nombre del módulo
  • No olvidarnos de ponerle la extensión .js al módulo que importamos
// Esto no funciona ❌
import { something } from './moduleName';

// Esto si ✅
import { something } from './moduleName.js';

JavaScript Modules in 100 Seconds