Video Summary and Transcription
Esta charla discute los desafíos y la colaboración involucrados en la construcción de Nodebox, un entorno de ejecución compatible con Node.js para el navegador. Proporciona una visión general de cómo funciona Nodebooks, incluyendo el administrador principal, las vistas previas y los trabajadores web. La charla también cubre la simplicidad y velocidad de lectura desde el sistema de archivos en Nodebooks. Destaca la complejidad de implementar el soporte HTTP y la simulación de WebSocket en Nodebox. Por último, menciona la capacidad de construir un servidor web utilizando Nodebox y proporciona información sobre las plantillas disponibles.
1. Construyendo Nodebox: Desafíos y Colaboración
Hola, soy Jasper. Hablaré sobre cómo construimos Nodebox, un entorno de ejecución compatible con Node.js para el navegador. Necesitábamos construir un sistema de archivos, un servidor HTTP, soporte para websockets, módulos y la capacidad de buscar módulos NPM. Tuvimos ayuda de las bibliotecas existentes en el ecosistema de Browserify.
Hola, soy Jasper. Soy un ingeniero de personal en Codesoundbox, y voy a dar una charla sobre cómo construimos nuestro entorno de ejecución compatible con Node.js para el navegador llamado Nodebox. Entonces, ¿por qué realmente construimos un entorno de ejecución compatible con Node.js para el navegador? Queríamos construir un entorno de ejecución compatible con Node.js porque queríamos permitir que nuestra biblioteca de juegos, Sandpack, ejecute pequeños proyectos. Como por ejemplo un pequeño ejemplo de Next.js, un ejemplo de feed, o una aplicación Next.pressjs. Obviamente para los propósitos de documentación.
¿Y qué necesitábamos construir para hacer esto posible? Hay muchas cosas que entran en Node.js. Por ejemplo, tuvimos que construir un sistema de archivos, un servidor HTTP y soporte para websockets, tuvimos que construir módulos, tuvimos que ser capaces de buscar módulos NPM. También tuvimos que asegurarnos de que teníamos soporte para procesos hijos, ya que la mayoría de las bibliotecas y frameworks dependen mucho de eso. Y también hay muchas más bibliotecas más pequeñas y otras bibliotecas estándar en Node.js que tuvimos que soportar para hacer todo esto funcionar. Así que en realidad tuvimos mucha ayuda de las bibliotecas existentes, porque hay muchas cosas por ahí del ecosistema de Browserify. Por ejemplo, está assert, y está como zlib. También está un buffer y eventos, o decodificador de cadena de ruta, como utilidades de URL. Stream legible por el equipo de Node, que nos ayuda a construir soporte para streams. Y luego también está como crypto, y un montón
2. Resumen de Nodebooks y Sistema de Archivos
Así que un resumen general de cómo funciona realmente Nodebooks. Tenemos un administrador principal que controla todo en nuestro entorno virtual. Genera procesos, imitando los procesos reales de Node. También tenemos vistas previas, que actúan como un servidor HTTP. Nuestros procesos Node son trabajadores web con su propio proceso contenido. Utilizamos trabajadores web para inicializar cada trabajador y hacer el trabajo de inicialización de construcción del árbol del sistema de archivos, cargar archivos de ensamblaje web y esperar a que termine. Una vez que el trabajador está listo, lo enviamos de vuelta al principal y podemos ejecutar comandos como Next.js. Envolvemos el módulo en nuestro propio global para hacerle creer que se está ejecutando en un entorno de nodo. Nuestro sistema de archivos funciona con el proceso principal teniendo todo el estado y los trabajadores teniendo consistencia eventual. Al escribir en el sistema de archivos, la escritura se sincroniza y se envía al proceso principal para sincronizarla en todo el estado de la aplicación.
y otras que no están listadas en esta diapositiva. Así que un resumen general de cómo funciona realmente Nodebooks. Así que tenemos nuestro administrador principal, que controla todo en nuestro entorno virtual. Y genera procesos, que son procesos reales de Node, o intentan ser procesos de Node, los imitan. Y luego también tenemos vistas previas, que son algo así como tu servidor HTTP, que pasa por nuestro administrador de vistas previas, que construimos, que luego inicia iframes para imitar este comportamiento del servidor HTTP. Y nuestros procesos Node son en realidad web workers, que también tienen su propio proceso contenido similar a cómo funciona Node. Y entonces, ¿cómo funciona un proceso Node en nuestro entorno? Como dije antes, utilizamos web workers. Para hacer esto, inicializamos cada trabajador enviando un buffer del sistema de archivos y variables de entorno y un montón de otras pequeñas opciones de configuración que tenemos en Nodebox. Bueno, una vez que esto sucede, el trabajador se pone en marcha y comienza a hacer su trabajo de inicialización, que es construir el árbol del sistema de archivos, cargar algunos archivos de ensamblaje web que utilizamos por ejemplo, para transpilar nuestro código o algunas cosas como probablemente la compresión, que realmente no existe en el navegador en este momento. Y también tenemos cosas como esperar a que termine al final. Y luego entramos en la carga del resto de las cosas. Entonces, una vez que el trabajador está listo, lo enviamos de vuelta al principal. Y una vez que está en el principal, el principal sabe que nuestro trabajador está listo. Y ahora, podemos hacer como ejecutar un comando. Por ejemplo, ejecutar Next.js es tan simple como pasar el comando JSON next y luego se inicia todo un servidor Next.js. Hace esto yendo a nuestros nodos modules y resolviendo el binario next que en realidad es solo un archivo JavaScript al final. Entonces, resolvemos eso que termina siendo como .bin slash next y luego tiene un enlace simbólico a slash node module slash next slash CLI.MJS o algo así. Y luego ejecutamos ese script real como node, el archivo resuelto y luego lo pasamos como argumentos a nuestro módulo. Y luego lo usamos para evaluar el módulo. Cómo hacemos eso es envolviendo nuestro módulo en nuestro propio global que construimos que contiene la mayoría de los globales, los nodos modules esperan como el módulo, global require hay un par de otras cosas del módulo ES y luego global this que es todo diferente del navegador y tratamos de hacerle creer que se está ejecutando en un entorno de nodo en lugar del navegador real. Así que también establecemos ciertos globales del navegador en indefinido o nulo. Y luego lo ejecutamos en una función. Lo envolvemos en una función con nuestros argumentos globales. Así que el código cree que estos son nuevos globales en lugar de los globales reales que tiene el navegador. Y eso también lo hacemos aplicar donde anulamos los discos para que sean nuestros discos globales en lugar de los discos del navegador. Así que realmente cree que está dentro de un entorno de nodo mientras todavía se está ejecutando dentro de un navegador. Entonces, ¿cómo funciona nuestro sistema de archivos? Nuestro sistema de archivos funciona de tal manera que nuestro proceso principal tiene el estado completo del sistema de archivos y todos nuestros trabajadores tienen consistencia eventual. Por ejemplo, aquí tenemos un ejemplo de cómo se escribe en un sistema de archivos. Entonces en el módulo, tienes importfs y luego llamas a fs.write. Esa escritura luego se envía a nuestro estado del sistema de archivos que instantáneamente lo sincroniza en su propio estado y luego envía un mensaje a nuestro bus de trabajadores al proceso principal para decir que he escrito algún archivo. ¿Puedes sincronizarlo en todo nuestro estado de la aplicación? Y luego el estado principal del sistema de archivos también recibe eso, actualiza su estado interno y luego
3. Lectura del Sistema de Archivos
En Nodebooks, la lectura del sistema de archivos es simple y rápida. Cada módulo tiene acceso al estado completo del sistema de archivos y puede recuperar archivos instantáneamente utilizando la función fs.read().
lo emite a todos los demás trabajadores. Así que en este caso solo hay un trabajador que recibe este mensaje y luego también actualiza su propio estado del sistema de archivos. Así que si ahora hubiera un segundo módulo en Worker2 que intenta leer ese archivo, obtendría el estado más reciente. Entonces, ¿cómo funciona la lectura? La lectura es mucho más simple porque ya tienes el estado completo del sistema de archivos en tu proceso. Así que es solo tu módulo tiene la biblioteca estándar del sistema de archivos y luego haces fs.read() y luego simplemente lo busca instantáneamente en un mapa en el estado del sistema de archivos y lo resuelve sin pasar ningún mensaje ni nada.
4. Soporte HTTP y Simulación de WebSocket
Y luego también tenemos soporte HTTP. Es más complicado que el sistema de archivos. Iniciamos un servidor HTTP simple en el puerto 3000. Nuestro entorno de Nodebox envía un mensaje a nuestro trabajador para iniciar el servidor. El administrador de vista previa abre un iframe con un relevo de vista previa. El relevo inicializa un trabajador de servicio. El administrador de vista previa envía el mensaje listo a Sandpack, que genera otro iframe de vista previa. Las solicitudes pasan por el trabajador de servicio, el relevo, el administrador de vista previa y el trabajador. Las respuestas se envían de vuelta a través del mismo flujo. El soporte de WebSocket se proporciona a través de un WebSocket simulado.
Es instantáneo. Es increíblemente rápido. Y luego también tenemos soporte HTTP. Esto es bastante más complicado que el sistema de archivos. Así que empecemos con el inicio de un simple servidor HTTP. Por ejemplo en el puerto 3000. Así que tenemos nuestro módulo que como tienes el código estándar de servidor HTTP y luego llamas a httpserver.listen() con un puerto al final. Y una vez que haces eso, nuestro entorno de Nodebox sale del módulo y luego envía un mensaje a nuestro trabajador para decir que inicie el servidor HTTP en el puerto 3000. Lo recibe, lo pasa al administrador de vista previa que gestiona todas las vistas previas y servidores que podrían ser comparados con los sockets en un sistema operativo. Y luego tú y luego el administrador de vista previa dice abrir un iframe para registrar este puerto. Ese iframe contiene lo que llamamos un relevo de vista previa que tiene un nombre de dominio único con algún script de inicialización que construimos en Code Sandbox. Ese script de inicialización inicia un trabajador de servicio que luego escucha las solicitudes que entran y una vez que está listo, dice que está listo para recibir solicitudes. Y luego volvemos al administrador de vista previa con ese mensaje listo a través de nuestro relevo y luego el administrador de vista previa envía esto a Sandpack que en realidad genera otro iframe de vista previa que en realidad muestra tu aplicación. El relevo tiene este script de inicialización y no muestra nada. El marco de vista previa en realidad contiene tu aplicación. Y una vez que ha hecho eso, vuelve a los trabajadores para decir que está listo y luego obtienes en tu módulo como un evento de escucha en tu HttpServer. Y es igual que Node.js regular. ¿Cómo funcionan las solicitudes en esta configuración? Tienes tu marco de vista previa que contiene tu aplicación. Haces una HttpRequest, por ejemplo, cargando el index.html. Pasa a través del trabajador de servicio que intercepta esa solicitud y luego le dice al relevo, he recibido una solicitud. El relevo luego le dice al administrador de vista previa, hay una solicitud aquí para que la manejes. El administrador de vista previa sabe dónde se está ejecutando el servidor en nuestra red de trabajadores. Así que pasa por el principal, luego el principal lo envía al trabajador. Ese trabajador luego emite un evento de solicitud a tu módulo y luego lo manejas como un nodo regular y luego eventualmente obtendrás una respuesta. Esa respuesta luego pasa de nuevo a través de ese trabajador, de vuelta al principal, de vuelta al administrador de vista previa, luego el administrador de vista previa lo envía de nuevo al relevo, y hay un ID único para esto, por lo que se rastrea en todo el gráfico. Y luego una vez que el relevo de vista previa tiene esta respuesta, le dice al trabajador de servicio, tengo una respuesta para tu solicitud con ID algo. Y luego envía esa respuesta a tu marco de vista previa, como lo harías con un trabajador de servicio. Solo que aquí pasa por un montón de trabajadores y relevos a un servidor simulado en lugar de un servidor real. Pero luego también tenemos soporte para WebSocket, que hace algo similar. Simula el WebSocket real al sobrescribir el global con algo que llamamos un WebSocket simulado, y lo construimos completamente. Hay códigos y simulaciones donde hemos sobrescrito cada método de este WebSocket para ser compatible con NodeBox en lugar de usar WebSockets reales. Esto solo ocurre cuando es el host local o la IP local, entonces utiliza la lógica de simulación, y de lo contrario simplemente utiliza un verdadero WebSocket, porque podrías querer conectarte a un servidor web real, incluso en tu
5. Soporte de WebSocket y Construcción de un Servidor Web
Veamos cómo funciona el soporte de WebSocket en NodeBox. Comienza desde un marco de vista previa y pasa por el trabajador de servicio, el relevo y el administrador. Con todos estos bloques de construcción, puedes construir tu propio servidor web. Pruébalo en NodeBox.codesandbox.io. Tenemos plantillas para Node.js, Next.js, Vite, React, Vue, Spelt y Astro. Conéctate conmigo en Twitter en Jasper D'Amour y encuentra Codesandbox en Codesandbox.
pequeños proyectos de masterclass. Así que veamos cómo funciona. De nuevo, empezamos desde, por ejemplo, un marco de vista previa que dice, quiero enviar un mensaje de WebSocket. Y luego pasa por el trabajador de servicio de nuevo, de la misma manera que una solicitud. De hecho, el primer mensaje en un WebSocket es una solicitud de actualización. Y eso hace exactamente lo mismo que antes. Pero ahora queremos enviar un mensaje. Así que lo enviamos a través de un trabajador de servicio. El trabajador de servicio lo devuelve al relevo, y de vuelta al administrador, sabe dónde se está ejecutando ese servidor, porque primero hiciste una solicitud para iniciar un WebSocket, y luego el módulo lo manejará. Y luego respondes a él, por ejemplo, con otro WebSocket.send. Luego pasas por el trabajador, a través de main de nuevo, administrador de vista previa, relevo de vista previa, igual que antes, y luego emite esto de nuevo al trabajador de servicio, de vuelta al marco de vista. Y ahora básicamente también tenemos soporte de WebSocket.
Y con todo eso, tienes un servidor web bastante básico en funcionamiento. Por ejemplo, aquí tienes un simple hola mundo. Incluso imprime en la consola que el servidor está funcionando cuando se realiza la escucha. Con todos estos bloques de construcción, puedes construir algo como esto tú mismo. Teóricamente es idéntico a cómo funciona NodeBox. Puedes probar esto, puedes probar esto en NodeBox.codesandbox.io. Tenemos un montón de plantillas construidas sobre Sandpack con las que puedes jugar, como Node.js, Next.js, Vite, React en Vite, React en nuestro entorno de navegador Sandpack. Vue en Vite, pero también Vue en nuestro navegador entorno Sandbox. Y luego tienes, como, Spelt de nuevo a los entornos, y luego Astro que también apoyamos. Y puedes jugar con cualquier cosa que sea compatible con Node y ver si funciona. Si no funciona, siempre puedes abrir un ticket en GitHub para que lo arreglemos.
¡Gracias por escuchar! Puedes encontrarme en Twitter en Jasper D'Amour. Y también puedes encontrar Codesandbox en Twitter en Codesandbox. De nuevo, puedes jugar con todo esto en NodeBox.Codesandbox.com, y gracias de nuevo por escuchar!
Comments