# Uso de módulos en JavaScript con ECMAScript 6

JavaScript no tiene (por ahora) un sistema de módulos propio, aunque eso si, la
comunidad fue creando varios para suplir esa necesidad. Actualmente hay dos
importantes propuestas (incompatibles entre sí):

**CommonJS**: Esta es la implementación usada en Node.js y Browserify, se
caracteriza por una sintaxis sencilla, carga los módulos de forma síncrona y se
usa principalmente en el servidor.

**Definición de Módulos Asíncronos (AMD)**: La implementación más popular de
este estándar es RequireJS, se caracteriza por una sintaxis un poco más
complicada, estar diseñado para cargar módulos de forma asíncrona y se usa
principalmente en navegadores.

Más documentación sobre estos sistemas:
https://addyosmani.com/writing-modular-js/

> Nota: El soporte para módulos de ECMAScript 6 en los navegadores actualmente
> es nulo, esto está todavía en desarrollo y no está listo para ser usado, hay
> sin embargo formas de escribir código usando ES6 y luego convertir el código a
> ES5 quedando un resultado bastante bueno, pero no es un soporte nativo, sigue
> siendo ES5.

La meta final de los módulos de ECMAScript 6 fue crear un formato que dejara
contento a los usuarios de CommonJS y AMD.

- **Similitudes con CommonJS**: sintaxis sencilla, preferencia por un solo
  export y soportar dependencias cíclicas.
- **Similitudes con AMD**: soporte para carga asíncrona y configurable de
  módulos.

Al estar el sistema incorporado directamente en el lenguaje, permite que sea
mejor que CommonJS y AMD.

- La sintaxis es incluso más simple que CommonJS.
- La estructura puede ser analizada estaticamente (para comprobaciones,
  optimizaciones, etc.).
- Tiene un mejor soporte para dependencias cíclicas que CommonJS.

El estándar de módulo de ES6 se divido en dos partes:

- La sintaxis para exportar e importar.
- La API de carga programable, para configurar como se cargan los módulos y
  cargarlos en diferentes condiciones.

## Visión general de la sintaxis

Hay dos formas de exportar: exportación con nombre (varias por módulo) o por
defecto (una por módulo).

### Exportación con nombre (varias por módulo)

Un módulo puede exportar múltiples cosas agregandole la palabra **export** antes
de la declaración. Estas exportaciones se distinguen por su nombre.

```js
//------ calculos.js ------
export function sumar(x, y) {
  return x + y;
}
export function restar(x, y) {
  return x - y;
}
```

```js
//------ main.js ------
import { sumar, restar } from "calculos";
console.log(sumar(2, 3)); // 5
console.log(restar(4, 3)); // 1
```

Como se ve es bastante simple, solo escribes el código como si no hubiera nada
que lo englobe (sin scope global) y a todo lo que desees exportar solo le
agregas la palabra **export**.

Si lo deseas también puedes importar un módulo entero y acceder a las
exportaciones con nombre usando la sintaxis de propiedades:

```js
//------ main.js ------
import * as calc from "calculos";
console.log(calc.sumar(2, 3)); // 7
console.log(calc.restar(4, 3)); // 1
```

### Exportación por defecto (una por módulo)

Los módulos que solo exporten un único valor son muy populares en la comunidad
de Node.js y en el desarrollo frontend. Un módulo de ES6 puede tomar un valor
por defecto en la exportación.

```js
//------ miFunc.js ------
export default function () { ... };
```

```js
//------ main1.js ------
import miFunc from "miFunc";
miFunc();
```

> Nota: El valor a exportar por defecto es una expresión y no tiene nombre, este
> es obtenido al importar el módulo, normalmente se usaría el nombre del módulo.

## Beneficio de los módulos de ECMAScript 6

A primera vista, tener módulos de forma nativa en ES6 puede parecer una
funcionalidad inútil, después de todo ya existe varios sistemas de módulos muy
buenos. Pero los módulos de ES6 tienen características que no se pueden agregar
con una librería, como una sintaxis reducida y una estructura estática de
modulos (lo que ayuda a optimizar entre otras cosas). Además se espera que
termine con la fragmentación entre los sistemas CommonsJS y AMD.

Tener un único estandar para módulos nativo significa:

- No más UMD ([Definición Universal de Módulos](https://github.com/umdjs/umd)):
  UMD es un patrón que permite que un mismo archivo sea usado por distintos
  sistemas (como CommonJS y AMD). Cuando ES6 este listo para su uso UMD se
  volverá obsoleto.
- Las nuevas API de los navegadores se volveran módulos en lugar de variables
  globales o propiedades como navigator.
- No más objetos como namespaces. Objetos como Math y JSON sirven como
  namespaces para funciones en ECMAScript 5. En el futuro, esta funcionalidad la
  darán los módulos.

## Referencias (en inglés)

Para finalizar les dejo algunos links (en inglés) con más información sobre los
módulos de ES6 para los que quieran aprender un poco más sobre como funcionan
(como la carga asíncrona de módulos que no está explicado arriba).

- [A JavaScript glossary: ECMAScript, TC39, etc.](https://www.2ality.com/2011/06/ecmascript.html)
- ["Static module resolution" by David Herman](https://calculist.org/blog/2012/06/29/static-module-resolution/)
- ["Modules: Cycles" in the Node.js API documentation](https://nodejs.org/api/modules.html#modules_cycles)
- ["Exports" (ECMAScript 6 specification)](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-exports)
- ["Imports" (ECMAScript 6 specification)](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-imports)