La próxima vez que el mismo módulo se cargue nuevamente sin cambios, si el navegador no se actualiza, típicamente solo reutilizará el bytecode leído desde el disco. Al igual que la compilación de análisis en los navegadores típicamente ocurre fuera del hilo. Además, la mayoría de los motores de JavaScript construidos para navegadores no analizan sus funciones en los módulos al principio, como aquí. La asignación de constantes de nivel superior se analizará y compilará completamente cuando se cargue el módulo. Pero la función add no se analizará ni compilará completamente hasta que se invoque por primera vez. Node también ha comenzado a soportar la caché de compilación en disco desde la versión 22, aunque actualmente se actualiza a través de la variable no-compile-cache o la API module enable-compile-cache, o la opción use-code-cache si estás construyendo una aplicación no-sync-code. El bytecode también solo se reutiliza cuando el módulo no ha cambiado y se ejecuta en la misma versión de Node. Y al igual que la compilación de análisis en Node ocurre en el hilo principal. Actualmente, Node también solo pre-analiza sus funciones y no genera código para ellas hasta que se invocan, aunque esto también puede hacerse configurable en el futuro porque Node usualmente proporciona más extensiones de bajo nivel que los navegadores.
Así que después de la compilación, tenemos el bytecode de un módulo, ¿qué sigue? Necesitamos avanzar y manejar sus dependencias, si las hay. Por ejemplo, aquí tenemos un módulo, main.js, que importa un paquete. Ese paquete a su vez carga el módulo incorporado Node path y otro módulo utils. Necesitamos iterar a través de estas solicitudes de módulo, necesitamos resolver sus especificadores a URLs, cargar el código fuente desde las URLs resueltas, analizar y compilar su código, y repetir hasta que el gráfico de dependencias se cargue transitivamente. En esta etapa, si alguna de las dependencias transitivas no puede resolverse, cargarse o analizarse, Node lanzará un error porque cualquier código de módulo en el gráfico, antes de que cualquier código de módulo en el gráfico se ejecute. Como aquí, por ejemplo, si el paquete utils.js no existe, falla al resolver, y Node dará un error y no ejecutarás ningún código, incluso si lo colocas antes de las declaraciones de importación, como el primer console log aquí no se ejecutará porque según la especificación del lenguaje, las declaraciones de importación se elevan y el código ejecutable se ejecutará mucho más tarde antes de que las dependencias se carguen, independientemente de las ubicaciones de origen.
Y después de compilar todo el gráfico transitivamente, la siguiente etapa es la instanciación. Esto es cuando V8 intenta emparejar las importaciones y exportaciones y busca desajustes. En la especificación del lenguaje, esta etapa ha sido renombrada a vinculación. Según la terminología de Node y V8, esto todavía se llama instanciación, así que también lo llamamos instanciación por ahora. Aquí, por ejemplo, main.js importa un nombre, add, de un paquete y el paquete no tiene una exportación llamada add. Así que estas referencias se unirán, y el paquete a su vez importa n underscore add de otro paquete, y también importa la exportación predeterminada del módulo incorporado node path. Y estas referencias también se unirán por V8 durante la instanciación. Y en esta etapa, si un módulo importa un nombre de otro módulo que no lo exporta, V8 lanzará un error. Y es por eso que lo llamamos instanciación, porque si es un módulo que no lo exporta, V8 lanzará un error. Y nuevamente, esto sucede antes de que se ejecute cualquier código. Como aquí, si main.js importa el nombre que no se exporta de un paquete, la declaración console.log antes de la declaración de importación no se ejecutaría. Así que antes hablamos sobre el uso de module.register.hooks en la codificación, pero ¿qué tal personalizar las etapas desde el análisis hasta la instanciación? Estas etapas son más especiales en ESM y no pueden compartir primitivas con CommonJS a través de la misma API module.register.hooks. Tenemos la API de módulos VM. Ha sido utilizada por algunos marcos de prueba para aislamiento ligero. Esta fue la razón por la que el soporte de ESM en Jest todavía es experimental, porque dependen de esta API que ha sido experimental desde 2017.
Comments