Milo, un nuevo analizador HTTP para Node.js

Rate this content
Bookmark

La interpretación HTTP de Node.js actualmente se basa en llhttp, un analizador que ofrece un rendimiento muy bueno pero que actualmente presenta algunos desafíos para la salud del tiempo de ejecución.

¿Es posible crear una alternativa moderna, mantenible, bien documentada, segura y eficiente? ¡Sí lo es!

Permítanme presentarles a Milo, un nuevo analizador HTTP basado en Rust que planeo integrar en Node.js y permítanme mostrarles cómo pueden ayudar a ser parte de su primer componente en Rust.

Paolo Insogna
Paolo Insogna
23 min
04 Apr, 2024

Video Summary and Transcription

Hola y bienvenidos al Congreso de Node 2024. NearForm se enfoca en ofrecer soluciones modernas y elegantes. Milo es un nuevo analizador HTTP escrito en Rust, diseñado para abordar la complejidad y las vulnerabilidades del analizador HTTP actual de Node. Milo permite a los desarrolladores optar por copiar los datos que se están analizando para mejorar la experiencia del desarrollador. Sigue estrictamente las últimas RFC para HTTP y proporciona una interfaz común en diferentes lenguajes. Se está explorando la integración de Milo con C++ y WebAssembly, y los próximos pasos incluyen mejoras de rendimiento y pruebas de regresión.

Available in English

1. Introducción a Node Congress 2024

Short description:

Hola y bienvenidos a Node Congress 2024. NearForm se enfoca en ofrecer soluciones modernas y elegantes. Paolo se presenta y habla sobre las versiones de HTTP. Node tiene implementaciones estables para HTTP 1 y 2, y están trabajando en HTTP 3.

Hola y bienvenidos a Node Congress 2024. Este es Milo, un nuevo analizador HTTP para Node.js.

En primer lugar, permítanme presentar NearForm. Somos una empresa de servicios profesionales que se enfoca en ofrecer las soluciones más modernas, eficientes y elegantes a nuestros socios digitales. Estamos activos en varios países del mundo y siempre estamos buscando nuevos talentos, así que por favor apliquen.

A veces, ser imprudente tiene sus recompensas. ¿Por qué es eso? Permítanme demostrárselo. En primer lugar, quiero presentarme. Hola de nuevo, soy Paolo. Soy miembro del Comité Técnico de Dirección de Node y Ingeniero de Desarrollo en NearForm. Pueden encontrarme en línea al final de la diapositiva que pueden ver. Y también a la derecha pueden ver de dónde vengo. Vengo de Campobasso en Italia, en la región más pequeña que es Molise, que el resto de Italia finge que no existe. Pero es su pérdida, no la mía. Continúen.

Todos amamos HTTP. ¿Por qué es eso? Porque es el protocolo más extendido y utilizado en todo el mundo. ¿Cuál versión eres tú? Bueno, resulta que a pesar de tener 30 años, solo existen tres versiones de HTTP en realidad. Dos solo fueron borradores, 09 y 10, así que no las considero como versiones existentes. Las que llegaron a ser la versión final son 11, 2 y 3. 11 es, con mucho, la más utilizada, es la histórica, es la que probablemente también conocen y aún está vigente y no irá a ninguna parte en el corto plazo. 20 fue creada para abordar algunos de los problemas del socket TCP utilizando el protocolo speedy. Sin embargo, los resultados no fueron realmente exitosos. Ahora también tenemos la 3, que en cambio utiliza QUIC, que utiliza UDP, lo que complica las cosas, especialmente para los administradores del sistema. Lo siento por ustedes, de verdad.

¿Y qué hay de Node? Node tiene una implementación estable para HTTP 1 y HTTP 2. En ese caso, están listos para comenzar. En cuanto a HTTP 3, aún no hemos llegado del todo. Todavía estamos trabajando en la implementación de QUIC, pero llegaremos allí. Es una promesa.

2. Análisis de HTTP e Introducción a Milo

Short description:

Ahora centrémonos en el tema de esta charla, que es el análisis de HTTP. El analizador actual de HTTP en Node se llama LLHTTP y fue escrito por Fedor Indutny en 2019. Es el predeterminado desde Node 12 y funciona de manera brillante. LLHTTP es compatible con versiones anteriores de HTTP 09 y 10, lo que trae consigo una complejidad y vulnerabilidades innecesarias. Para abordar estos problemas, se desarrolló Milo como solución. Milo está escrito en Rust, un lenguaje flexible y de alto rendimiento. La elección de Rust fue deliberada para explorar su potencial para contribuir a Node con código en Rust.

Ahora centrémonos en el tema de esta charla, que es el análisis de HTTP. ¿Cuál es el analizador actual de HTTP en Node en la actualidad? Se llama LLHTTP. Fue escrito por Fedor Indutny en 2019 y es el predeterminado desde Node 12. Funciona de manera brillante. En el lado derecho pueden ver la máquina de estados que realmente utiliza, compuesta por 80 estados, por lo que es muy, muy compleja. La magia está en su generador de máquina de análisis, que es LLParse. LLParse recibe una definición de máquina de estados de entrada en TypeScript, que tiene un subconjunto muy específico del lenguaje oval, y genera una máquina de estados en C. En otras palabras, LLParse transpila de TypeScript a C. Malas señales hoy. Pueden ver fácilmente cómo un transpilador así puede ser difícil de debug y de lanzar. Además, LLHTTP siempre ha sido compatible con versiones anteriores de HTTP 09 y 10, y esto trae consigo una complejidad innecesaria para abordar casos excepcionales. También ha sido tolerante con implementaciones rotas de HTTP, como, no sé, dispositivos integrados generalmente. Esto es muy peligroso porque abre la puerta a vulnerabilidades y otras puertas traseras y demás. Estos son generalmente los problemas de LLHTTP, que me llevaron a la decisión de escribir Milo, como verán en un momento. Milo es la solución, por supuesto, de lo contrario no estarían aquí, así que por supuesto tenemos una solución. Empezamos desde cero. Perdón por el horrible juego de palabras, realmente lo siento. Este es Milo. No es el Milo que esperaban, pero este también era Milo. Lo que están viendo es una, para aquellos que no lo saben, es una ardilla Tamiya, básicamente es una ardilla japonesa, y esta en particular se llamaba Milo. Era una de las mascotas de mi esposa, que en ese momento era mi novia, y también fue la primera que elegí para nombrar mi nuevo software. Básicamente, ahora tengo la costumbre de nombrar mi software en honor a mis mascotas actuales o anteriores, y tengo muchas. Ya saben, gatos, perros, caballos, peces, lo que sea. De todos modos, este es Milo, o un Milo. Les mostraré el otro Milo en un momento. Hablando del último Milo, por el que realmente están aquí, soltemos la bomba. Milo está escrito en Rust, punto. ¿Por qué? El lenguaje ha demostrado ser flexible, poderoso y eficiente para lograr esta tarea específica. Es de bajo nivel en cuanto a rendimiento, pero no es de bajo nivel en cuanto a definición. Por ejemplo, no conocía Rust en absoluto antes de escribir Milo, y hice esta elección a propósito, hice un experimento conmigo mismo para ver qué tan difícil sería para un nuevo colaborador adoptar Rust para contribuir a Node si Node contiene código en Rust.

3. Arquitectura y Generación de Código de Milo

Short description:

No estoy aquí para iniciar una nueva discusión sobre lenguajes o criticar a LLHTTP o Feather. La arquitectura de Milo está inspirada en LLHTTP pero con una máquina de estados más simple. Aprovechando las macros de Rust, Milo genera código Rust a partir de archivos YAML, lo que permite flexibilidad y una potente generación de código. El sistema de macros de Rust es increíblemente poderoso, permitiendo la generación de código sin limitaciones. Milo tiene una huella de memoria pequeña y proporciona código compilado que se asemeja a la máquina de estados original.

No es tan difícil. Se puede hacer. Además, no estoy aquí para iniciar una nueva discusión sobre lenguajes. No soy un troll, o al menos no tanto. Así que por favor, sean amables. No inicien una discusión sobre lenguajes.

Tampoco estoy criticando a LLHTTP o Feather en absoluto, porque Feather es una persona muy buena, y LLHTTP fue un analizador increíble y eficiente que me encantó. Su arquitectura es la inspiración y la base de Milo, obviamente. Aún tengo una máquina de estados, pero mucho más simple, tengo muchos menos estados. Pasamos de 80 a 32, y elegí usar una forma declarativa de escribir estados, sin restricciones de código en Rust.

Ahora, no es magia negra. Nada es magia negra en TI, ¿verdad? Simplemente aprovecho las macros. El sistema de macros de Rust es uno de los más poderosos, si no el más poderoso, que he visto. Básicamente, la idea es que antes de completar tu código, si usas una macro (no estoy hablando de macros procedurales), básicamente puedes ejecutar otra parte de código Rust que se genera y se compila eventualmente. Entonces, básicamente, la macro en Rust producirá código Rust, pero no tienes ninguna limitación de código, puedes hacer lo que quieras. Por ejemplo, cargo la lista de métodos, estados, etc., desde archivos YAML que no están presentes o incrustados en tiempo de ejecución, porque se pasan en tiempo de compilación, genero código Rust y creo un ejecutable Rust.

También hay una herramienta que está hecha específicamente para depurar la macro procedural en Rust, porque en Rust, generalmente se usan las bibliotecas scene y quote, y con cargo span, puedes ver qué hacen estas bibliotecas con tu código, por lo que puedes tener un paso adicional antes de la compilación. Los ejemplos suelen ser más elocuentes que mil palabras. Echemos un vistazo. Incluso si no eres programador de Rust, puedes ver fácilmente la similitud entre el lado izquierdo y el lado derecho. En el lado izquierdo, tienes un estado real en Milo, que es el estado después de recibir un fragmento y volver a la longitud del siguiente fragmento, eventualmente, si recibes un slash r slash n. De lo contrario, si recibes otros dos caracteres que no esperas, fallas en el análisis. O si no tienes al menos dos caracteres para hacer la comparación, generalmente solo tienes uno, suspendes la ejecución, detienes el análisis por ahora y regresas al llamador. En el lado derecho, después de transpilar las macros, que para que conste son las que terminan en signo de exclamación, tienes el código compilado. Básicamente, el estado se convierte en una función con una firma específica que no tienes que recordar porque está implícita en la macro. CR LF se convierte en slash r slash n, pero con una sintaxis expandida que Rust espera. Lo mismo ocurre con MOV2 que se convierte en analizador MOV2, un estado y un tamaño. Finalmente, también puedes devolver una constante. Pero no tienes que recordar todos estos detalles porque las macros lo harán por ti. Ahora, ¿qué hay de la memoria? Sabemos que Milo es de alto rendimiento, ¿verdad? Pero, ¿qué hay de la huella de memoria? Milo tiene una huella de memoria muy pequeña.

4. Copia de datos en Milo

Short description:

Milo permite a los desarrolladores optar por copiar los datos que se están analizando, lo que facilita y mejora la experiencia del desarrollador. Por defecto, Milo prioriza el rendimiento y no copia ningún dato. La función de optar por copiar automáticamente copia la parte no consumida del búfer para la próxima iteración.

En primer lugar, por supuesto, debo recordar algunas banderas, algunos contadores, generalmente de 32 bits, y algunos contadores de 64 bits, por lo que probablemente menos de unos cientos de bytes. Eso es todo.

Luego, si el desarrollador opta por este comportamiento, que está desactivado de forma predeterminada, eventualmente se puede copiar parte de los datos que se están analizando en Milo. Por defecto, Milo no copia ningún dato. Los datos se analizan sobre la marcha y se devuelven al llamador sin copiar incluso el puntero de memoria.

Si optas por ello, en lugar de devolver el número de bytes no consumidos al llamador, Milo eventualmente optará por copiar la parte no consumida del búfer y la añadirá al comienzo de la próxima iteración de la ejecución. En lugar de recordarte que lo hagas, Milo lo hará automáticamente por ti. Esto es simplemente experiencia del desarrollador. Es totalmente opcional y puede facilitar la vida en algunos casos. De lo contrario, de forma predeterminada, Milo se centra en el rendimiento.

5. Milo en Acción

Short description:

Milo sigue estrictamente las últimas RFC para HTTP, sin excepciones. La función principal en Rust crea un analizador utilizando el método milocreate y establece devoluciones de llamada para el manejo de datos. La carga útil consiste en un desplazamiento de datos y un tamaño, y se llama al método parse para procesar los datos. Se utiliza un enfoque de interfaz común en diferentes lenguajes para garantizar la consistencia. Al ejecutar el ejemplo con Cargo, se imprime la información de depuración.

Además, Milo elimina la compatibilidad hacia atrás y la latencia. Somos estrictos. Punto. Seguimos estrictamente las últimas RFC para HTTP, que son la 91.10 y la 91.12. Al pie de la letra, no tenemos ninguna excepción. Punto. No deberíamos, deberíamos, deberíamos, cruzar los dedos, tener ninguna vulnerabilidad siguiendo la especificación al pie de la letra.

Ahora, creo que estás bastante cansado de escucharme hablar, así que vamos a la acción. Permíteme mostrarte a Milo en acción. Esto es Rust. Ahora, incluso si no conoces Rust, deberías ser capaz de seguir mi explicación. Solo echemos un vistazo a la función principal. Creas un analizador utilizando el método milocreate. Declaras un mensaje y luego estableces un cierto número de devoluciones de llamada. Todas estas devoluciones de llamada tienen la misma firma. Devuelven un puntero y eventualmente una carga útil. La carga útil está compuesta por un desplazamiento de data al búfer de entrada y el tamaño. Básicamente, es un puntero y una longitud. Si no hay carga útil, tanto data como el tamaño serán cero, por lo que son fáciles de detectar en el código.

Una vez que tienes eso, eventualmente puedes manipular los data e imprimir en tiempo de ejecución. Listo. Por último, llamas al método parse. Ahora, debería haber importado parse en el useMilo, pero confía en mí en esto. Lo olvidé. De todos modos, si eres un programador de Rust, te preguntarás por qué no he implementado parse como una implementación de la estructura parse. Hay una razón, que proviene de WebAssembly y también de C++, y te lo mostraré en un momento. Pero hay una razón para eso. Intento tener una interfaz común en los tres posibles lenguajes en lugar de tres implementaciones diferentes. Sé que no es muy sólido para Rust, pero ya sabes. Si ejecutas el ejemplo anterior con Cargo, verás la impresión de la información de depuración.

6. Flujo de trabajo de C++ en Milo

Short description:

El flujo de trabajo de C++ en Milo es sencillo. Cargo admite la generación de bibliotecas estáticas, que se pueden enlazar estáticamente en cualquier ejecutable de C o C++. Cbindgen, creado por Mozilla, genera archivos de encabezado completamente funcionales de C o C++ a partir de un pequeño archivo TOML.

Entonces, la posición, por ejemplo, del estado code, el nombre del encabezado, el valor del encabezado y el cuerpo, y la carga útil. Si eres un desarrollador o colaborador de Node, sabes que Node utiliza ya sea JavaScript o C++. Así que en este caso, nos preocupamos por C++, y te tengo cubierto, no te preocupes. El flujo de trabajo de C++ es bastante sencillo.

En primer lugar, Cargo admite de forma nativa la generación de bibliotecas estáticas. Estas bibliotecas estáticas, por ejemplo, en Mac OS y Linux son archivos.ai, se pueden enlazar estáticamente en cualquier ejecutable de C o C++. Básicamente, se importan estáticamente. Y tenemos una herramienta que genera los archivos de encabezado, se llama Cbindgen, creado por Mozilla, y genera un archivo de encabezado de C o C++ completamente funcional a partir de un archivo TOML muy pequeño, de aproximadamente 3-4 líneas de code. Listo. Muy fácil.

7. C++ Version and WebAssembly in Milo

Short description:

Y esta es la versión de C++. Haces un analizador, declaras un mensaje, estableces un callback. Lo único es que en este caso, las conversiones de reinterpretación hacen que el código sea un poco más difícil de leer. Al final del día, haces el análisis de Milo con el analizador, el mensaje y especificas la longitud. C++ con Milo, con main y ejemplo. Eso es todo. Ahora, veamos la historia divertida. Node admite varias arquitecturas, pero SmartOS o Solaris, el soporte de Rust está en un nivel experimental. Así que elegimos WebAssembly como una solución diferente. WebAssembly siempre ha sido un ciudadano de primera clase en Rust. Ahora tenemos Wasm-BinGen, que facilita la generación de un paquete JS completamente funcional con un archivo de WebAssembly y código de enlace de JavaScript. Esto es Milo en Node.js con WebAssembly. Importamos Milo, preparamos un mensaje y jugamos con la memoria. WebAssembly exporta un espacio de memoria compartido entre WebAssembly y la capa de JavaScript.

Y esta es la versión de C++. Ahora, incluso si no eres programador de C++, puedes reconocer fácilmente la similitud con Rust. 1. Haces un analizador, declaras un mensaje y luego estableces un callback. Puedes reconocer cómo la firma es la misma. Lo único es que en este caso, las conversiones de reinterpretación hacen que el código sea un poco más difícil de leer, pero entiendes la idea.

Al final del día, hacemos lo mismo que hicimos en Rust y con la misma firma, haces el análisis de Milo con el analizador, el mensaje y en este caso, también tienes que especificar la longitud. Esto es algo bastante común en C++. Y este es el resultado. C++ con Milo, con main y ejemplo. Eso es todo, y aún obtienes el cuerpo cuando ejecutas el código.

Ahora, esta es una historia divertida. Cuando presenté originalmente Milo en la Cumbre NodeCollab en Bilbao en septiembre del año pasado, pensé que la gente estaría contenta de que les diera una forma de incrustar Milo a partir de una biblioteca estática y un archivo de encabezado sin tener que instalar la cadena de herramientas de Rust. Ese no fue el caso. Fue todo lo contrario. Querían instalar la cadena de herramientas de Rust en lugar de descargar un archivo compilado. Pero ese no fue realmente el problema. El verdadero problema que todos encontramos al hablar juntos es que Node admite varias arquitecturas.

Y desafortunadamente, una de estas arquitecturas es SmartOS, que es un dialecto de Solaris. Desafortunadamente, para SmartOS o Solaris, el soporte de Rust está en un nivel experimental. Así que hay soporte, pero no muy extenso. Y por lo tanto, elegimos no incluir este tipo de cosa en Node en un entorno de producción, crítico para la misión, y así sucesivamente. Necesitamos encontrar una solución diferente, que es WebAssembly. WebAssembly siempre ha sido un ciudadano de primera clase en Rust. Rust siempre ha podido compilar a la arquitectura Wasm. Ahora también tenemos una cadena de herramientas, que es Wasm-BinGen, que está probada en batalla, lo que facilita mucho la generación de un paquete JS completamente funcional, un paquete NPM, compuesto por un archivo de WebAssembly y código de enlace de JavaScript. Básicamente, este código de enlace carga internamente el archivo Wasm de forma transparente para el desarrollador, como verás en un momento.

Vamos a verlo en acción. Esto es Milo en Node.js con WebAssembly. Importamos Milo, preparamos un mensaje y ahora tenemos que jugar un poco con la memoria. El concepto es que WebAssembly exporta un espacio de memoria que se comparte entre WebAssembly y la capa de JavaScript.

8. Asignación de memoria y análisis en Milo

Short description:

Si colocas datos dentro de ese espacio de memoria, es accesible por ambas capas. Asignamos un búfer de memoria, creamos un búfer usando esa memoria y creamos un analizador y un callback. En JavaScript, no necesitamos llevar el analizador con nosotros. Copiamos el mensaje en el búfer compartido, luego llamamos a milo.parse con el analizador, el puntero a la memoria compartida y la longitud. La razón de usar milo.parse es el rendimiento, ya que evita la deserialización. El analizador se pasa como un entero a WebAssembly, donde se reconstruye como un analizador dentro del espacio de WebAssembly de alto rendimiento. Si encuentras una mejor manera, avísame.

Si colocas data dentro de ese espacio de memoria, es accesible por ambas capas, sin la disponibilidad de serialización y deserialización. Por lo tanto, lo que hacemos es asignar una memoria en ese búfer y recibimos un puntero al inicio de esa memoria. Después de eso, podemos crear un búfer usando ese búfer de memoria, disculpa por la ambigüedad, pasando el puntero y la longitud. Finalmente, llegamos a lo importante. Creamos un analizador, y como siempre hemos estado haciendo en C++ y también en Rust, creamos el callback, que tiene la misma firma. En este caso, omitimos el analizador. En primer lugar, porque en JavaScript, podemos enlazar el callback, por lo que no necesitamos realmente llevar el analizador con nosotros, o lo tenemos en el ámbito local y así sucesivamente. Podemos jugar con el mensaje, podemos obtener el desplazamiento y así sucesivamente para extraer la carga útil, y mostramos en tiempo de ejecución lo que obtuvimos. Ahora, para activar el análisis, tenemos que hacer dos operaciones. En primer lugar, tenemos que copiar el mensaje en el búfer compartido, por lo que hacemos buffer.set desde la cadena como un búfer, y luego llamamos a milo.parse, analizando el analizador, el puntero a la memoria compartida y la longitud. Eso es todo. La razón por la que estoy usando milo.parse en lugar de parser.parse, que también es lo que estaba diciendo en Rust, es porque en WebAssembly, si creo el analizador como una clase, cada vez que llamo a un método dentro de WebAssembly desde JavaScript, tengo que deserializar la referencia al objeto, por lo que sería muy costoso. En cambio, de esta manera, el analizador no es más que un entero, que puedo pasar a WebAssembly, por lo que es un tipo primitivo que se puede cambiar de ida y vuelta de manera transparente. Y cuando llego a Rust, básicamente, ese entero es un puntero de memoria que eventualmente se reconstruye como un analizador, pero dentro del espacio de WebAssembly, y por lo tanto es eficiente. Disculpa por la explicación muy precisa. Puedes retroceder y escuchar a una velocidad más lenta. Pero esa es la idea. Esa es la idea general de por qué tengo esta estructura compleja, y por eso elegí no usar imp en Rust. Esa es la explicación. Si encuentras una mejor manera, avísame, porque estoy interesado.

9. Pasos Finales y Conclusión

Short description:

Este es el resultado, que es el mismo que en C++, nada ha cambiado. ¿Qué falta? Rendimiento con milo en comparación con LLHTTP en Node utilizando la versión de C++. Falta la integración de Node.js para la parte de WebAssembly. Trabajando en WebAssembly con Undis para integrar milo. Solucionando el problema de rendimiento de milo en WebAssembly. Considerando implementar SIMD en WebAssembly. Migrando la suite de pruebas de bus de LLHTTP a milo para asegurar que no haya regresiones. Citando a Albert Einstein: una persona que nunca ha cometido un error nunca ha intentado algo nuevo.

Este es el resultado, que es el mismo que en C++, nada ha cambiado. Y eso es milo. Hemos terminado. Lo lograste.

Ahora, ¿qué falta? En primer lugar, los rendimientos, con milo en comparación con LLHTTP en Node utilizando la versión de C++. Esto es una ejecución preliminar.

¿Qué falta? En primer lugar, la integración de Node.js para la parte de WebAssembly. Ahora estoy trabajando en WebAssembly con Undis como memoria, un software más pequeño con el que puedo experimentar para integrar milo. También me gustaría solucionar el problema de rendimiento de milo en WebAssembly, porque en este momento LLHTTP es más rápido. También estoy pensando en implementar SIMD en WebAssembly, si puedo hacerlo.

Finalmente, el último paso, que es solo para verificar la corrección, es migrar la suite de pruebas de bus de LLHTTP, que también fue heredada por el analizador anterior, el analizador LLHTTP, a milo, para asegurar que milo no introduzca ninguna regresión. Después de eso, milo estará listo.

Ahora, algo que suelo hacer en mis charlas es terminar con una cita de una persona mucho más inteligente de lo que yo podría ser. En este caso, tengo una de Albert Einstein, a quien conoces, que dice: una persona que nunca ha cometido un error nunca ha intentado algo nuevo.

La clave aquí es que siempre debes intentar algo nuevo para atreverte incluso con lo imposible, incluso si no llegas a una solución, eso es lo que hice cuando escribí milo. No conocía Rust, nunca había escrito realmente un analizador HTTP, y probé ambos. Aprendí mucho sobre milo, sobre WebAssembly, sobre análisis HTTP, sobre Rust y sobre arquitectura. Ha sido un viaje increíble.

Espero que milo se fusione en Node lo antes posible. Eso es todo lo que tengo para hoy. Una vez más, gracias por asistir a esta charla. No dudes en contactarme en Twitter, LinkedIn, GitHub o por correo electrónico en cualquier momento que desees. Una vez más, gracias por asistir a Node Congress 2024 y gracias por asistir a mi charla. ¡Salud!

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

It's a Jungle Out There: What's Really Going on Inside Your Node_Modules Folder
Node Congress 2022Node Congress 2022
26 min
It's a Jungle Out There: What's Really Going on Inside Your Node_Modules Folder
Top Content
Do you know what’s really going on in your node_modules folder? Software supply chain attacks have exploded over the past 12 months and they’re only accelerating in 2022 and beyond. We’ll dive into examples of recent supply chain attacks and what concrete steps you can take to protect your team from this emerging threat.
You can check the slides for Feross' talk here.
Towards a Standard Library for JavaScript Runtimes
Node Congress 2022Node Congress 2022
34 min
Towards a Standard Library for JavaScript Runtimes
Top Content
You can check the slides for James' talk here.
Out of the Box Node.js Diagnostics
Node Congress 2022Node Congress 2022
34 min
Out of the Box Node.js Diagnostics
In the early years of Node.js, diagnostics and debugging were considerable pain points. Modern versions of Node have improved considerably in these areas. Features like async stack traces, heap snapshots, and CPU profiling no longer require third party modules or modifications to application source code. This talk explores the various diagnostic features that have recently been built into Node.
You can check the slides for Colin's talk here. 
ESM Loaders: Enhancing Module Loading in Node.js
JSNation 2023JSNation 2023
22 min
ESM Loaders: Enhancing Module Loading in Node.js
Native ESM support for Node.js was a chance for the Node.js project to release official support for enhancing the module loading experience, to enable use cases such as on the fly transpilation, module stubbing, support for loading modules from HTTP, and monitoring.
While CommonJS has support for all this, it was never officially supported and was done by hacking into the Node.js runtime code. ESM has fixed all this. We will look at the architecture of ESM loading in Node.js, and discuss the loader API that supports enhancing it. We will also look into advanced features such as loader chaining and off thread execution.
Node.js Compatibility in Deno
Node Congress 2022Node Congress 2022
34 min
Node.js Compatibility in Deno
Can Deno run apps and libraries authored for Node.js? What are the tradeoffs? How does it work? What’s next?
Multithreaded Logging with Pino
JSNation Live 2021JSNation Live 2021
19 min
Multithreaded Logging with Pino
Top Content
Almost every developer thinks that adding one more log line would not decrease the performance of their server... until logging becomes the biggest bottleneck for their systems! We created one of the fastest JSON loggers for Node.js: pino. One of our key decisions was to remove all "transport" to another process (or infrastructure): it reduced both CPU and memory consumption, removing any bottleneck from logging. However, this created friction and lowered the developer experience of using Pino and in-process transports is the most asked feature our user.In the upcoming version 7, we will solve this problem and increase throughput at the same time: we are introducing pino.transport() to start a worker thread that you can use to transfer your logs safely to other destinations, without sacrificing neither performance nor the developer experience.

Workshops on related topic

Node.js Masterclass
Node Congress 2023Node Congress 2023
109 min
Node.js Masterclass
Top Content
Workshop
Matteo Collina
Matteo Collina
Have you ever struggled with designing and structuring your Node.js applications? Building applications that are well organised, testable and extendable is not always easy. It can often turn out to be a lot more complicated than you expect it to be. In this live event Matteo will show you how he builds Node.js applications from scratch. You’ll learn how he approaches application design, and the philosophies that he applies to create modular, maintainable and effective applications.

Level: intermediate
Build and Deploy a Backend With Fastify & Platformatic
JSNation 2023JSNation 2023
104 min
Build and Deploy a Backend With Fastify & Platformatic
WorkshopFree
Matteo Collina
Matteo Collina
Platformatic allows you to rapidly develop GraphQL and REST APIs with minimal effort. The best part is that it also allows you to unleash the full potential of Node.js and Fastify whenever you need to. You can fully customise a Platformatic application by writing your own additional features and plugins. In the workshop, we’ll cover both our Open Source modules and our Cloud offering:- Platformatic OSS (open-source software) — Tools and libraries for rapidly building robust applications with Node.js (https://oss.platformatic.dev/).- Platformatic Cloud (currently in beta) — Our hosting platform that includes features such as preview apps, built-in metrics and integration with your Git flow (https://platformatic.dev/). 
In this workshop you'll learn how to develop APIs with Fastify and deploy them to the Platformatic Cloud.
0 to Auth in an Hour Using NodeJS SDK
Node Congress 2023Node Congress 2023
63 min
0 to Auth in an Hour Using NodeJS SDK
WorkshopFree
Asaf Shen
Asaf Shen
Passwordless authentication may seem complex, but it is simple to add it to any app using the right tool.
We will enhance a full-stack JS application (Node.JS backend + React frontend) to authenticate users with OAuth (social login) and One Time Passwords (email), including:- User authentication - Managing user interactions, returning session / refresh JWTs- Session management and validation - Storing the session for subsequent client requests, validating / refreshing sessions
At the end of the workshop, we will also touch on another approach to code authentication using frontend Descope Flows (drag-and-drop workflows), while keeping only session validation in the backend. With this, we will also show how easy it is to enable biometrics and other passwordless authentication methods.
Table of contents- A quick intro to core authentication concepts- Coding- Why passwordless matters
Prerequisites- IDE for your choice- Node 18 or higher
Building a Hyper Fast Web Server with Deno
JSNation Live 2021JSNation Live 2021
156 min
Building a Hyper Fast Web Server with Deno
WorkshopFree
Matt Landers
Will Johnston
2 authors
Deno 1.9 introduced a new web server API that takes advantage of Hyper, a fast and correct HTTP implementation for Rust. Using this API instead of the std/http implementation increases performance and provides support for HTTP2. In this workshop, learn how to create a web server utilizing Hyper under the hood and boost the performance for your web apps.
GraphQL - From Zero to Hero in 3 hours
React Summit 2022React Summit 2022
164 min
GraphQL - From Zero to Hero in 3 hours
Workshop
Pawel Sawicki
Pawel Sawicki
How to build a fullstack GraphQL application (Postgres + NestJs + React) in the shortest time possible.
All beginnings are hard. Even harder than choosing the technology is often developing a suitable architecture. Especially when it comes to GraphQL.
In this workshop, you will get a variety of best practices that you would normally have to work through over a number of projects - all in just three hours.
If you've always wanted to participate in a hackathon to get something up and running in the shortest amount of time - then take an active part in this workshop, and participate in the thought processes of the trainer.
Mastering Node.js Test Runner
TestJS Summit 2023TestJS Summit 2023
78 min
Mastering Node.js Test Runner
Workshop
Marco Ippolito
Marco Ippolito
Node.js test runner is modern, fast, and doesn't require additional libraries, but understanding and using it well can be tricky. You will learn how to use Node.js test runner to its full potential. We'll show you how it compares to other tools, how to set it up, and how to run your tests effectively. During the workshop, we'll do exercises to help you get comfortable with filtering, using native assertions, running tests in parallel, using CLI, and more. We'll also talk about working with TypeScript, making custom reports, and code coverage.