AWS Lambda - ESM Node.js

Algunas generalidades previas

En la mayoría de los paradigmas de programación, podemos encontrar sistemas que nos permiten auto organizar el código en pequeñas piezas o para incorporar librerías/bibliotecas de terceros a nuestro código. Al combinar todo lo anterior resulta una pieza de código más grande y compleja.

Desde un inicio Javascript utilizó el sistema de carga de módulos llamado CommonsJS (CJS) y es parte integral de Node.js hasta la version v8.5.0 donde se incorpora un nuevo sistema de carga de módulos, ESM. A partir de la version v13.2.0 de Node.js fue estabilizado e incorporado como un nuevo estándar.

¿ Por qué deberíamos usar ESM en AWS Lambdas ?

James Beswick (Principal Developer Advocate for the AWS Serverless Team) escribió un artículo titulado Using Node.js ES modules and top-level await in AWS Lambda ,donde detalla el por qué y en qué casos deberías usar ESM como cargador de módulos de Javascript en el contexto de un AWS Lambda. Uno de los motivos más importantes de usar ESM, es que la carga en frío de un lambda tarda casi un tercio en comparación con CommonsJS.

Dejo aquí la comparativa entre CJS y ESM donde en el p99 (carga en frío) la partida se reduce a un tercio mejorando el rendimiento en un 43,5%. Para esta prueba, todas las métricas de ESM salieron por debajo (mejores en tiempo) de las de CJS es simplemente marginal (alrededor de 2-5ms).

¿ Cómo usamos ESM en AWS Lambdas ?

Configuración del artefacto - package.json

Primero que todo se deben ajustar un par de atributos en el archivo package.json para indicar que el módulo es del tipo ESM.

package.json
1
2
3
4
5
6
7
8
9
{
"name": "serverless-lambda-esm",
"version": "1.0.0-beta",
"description": "Serverless Lambda ESM",
"main": "src/Handler.js", // <-- Sera cargado como módulo
"license": "UNLICENSED",
"private": true,
"type": "module", // <-- Este atributo debe tener el valor: module
}

Con este ajuste le indicamos al cargador que trate los archivos como ES módulos según su extensión, es decir, con el atributo type y valor en module todos los archivos con extensión .js serán tratados como ESM. Si por alguna razón quieres mezclar ambos mundos debes hacerlo de forma explícita usando como extensión .cjs. Por el contrario, si no utilizas el atributo type o lo dejas con valor commonjs, todos los archivos con extension .js serán tratados como CJS y si quieres utilizar ESM estos deben tener extension .mjs.

Preparamos el Handler

Handler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { DateTime } from "luxon";

/**
*
* @param {*} event
* @returns
*/
export const handler = async (event, context) => {
const date = DateTime.now().toFormat("yyyy-MM-dd");
console.log("Date: ", date);
console.log(JSON.stringify(event));

return {
statusCode: 200,
body: JSON.stringify({ message: "ok" })
};
};

El handler debe estar expuesto de esa forma para que sea cargado como ESM. Se puede apreciar que ya no usamos la sentencia require para cargar una dependencia externa (en esta caso luxon) y en su reemplazo utilizamos import.

Algunos detallitos que he ido aprendiendo en el camino y que no está muy explícito en la documentación, es que los imports de nuestros archivos, es decir, el código que está dentro del proyecto, deben ser cargados y nombrados con su extensión, dejo un ejemplo:

Handler.js
1
2
import { DateTime } from "luxon"; // <-- Sin la extension (lib)
import Service from './service/Service.js'; // <-- Con la extension

Export de los módulos

Service.js
1
2
3
4
5
6
7
8
9
10
11

const Service = {
/**
* Funcion
*/
doSomething: async(event)=>{
console.log("Event: ", JSON.stringify(event));
}
};

export default Service; // <-- Así se exponen los módulos al código

Palabras al cierre

Espero les sea útil para sus desarrollos de lambdas con Node.js. Más adelante ire dejando nuevos artículos con ejemplos e ideas para implementar con AWS Lambdas. Pase y deje su comentario.

Enlaces de interés

Escuchando Subterranean Homesick Alien del disco OK Computer

Radiohead
Author

Francisco Collao

Posted on

2023-06-04

Updated on

2025-11-01

Licensed under

Comentarios