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.
1 | { |
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
1 | import { DateTime } from "luxon"; |
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:
1 | import { DateTime } from "luxon"; // <-- Sin la extension (lib) |
Export de los módulos
1 |
|
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
- Using Node.js ES modules and top-level await in AWS Lambda
- AWS Lambda ahora admite módulos ES y Top-Level Await para Node.js 14
- How to use ES6 modules and top-level await in AWS Lambda
- ESModule in AWS Lambda
Escuchando Subterranean Homesick Alien del disco OK Computer