Sergio Xalambrí

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.

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

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

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.

//------ calculos.js ------
export function sumar(x, y) {
  return x + y;
}
export function restar(x, y) {
  return x - y;
}
//------ 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:

//------ 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.

//------ miFunc.js ------
export default function () { ... };
//------ 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:

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).