Comprendiendo la Resolución de Paquetes en Node.js

Rate this content
Bookmark

Cada vez que importamos o requerimos un paquete, seguimos un conjunto de reglas para resolver el paquete. Esta charla cubrirá las diferentes formas en que Node.js resuelve los paquetes y cómo depurar cuando las cosas salen mal. También cubriremos las nuevas características en Node.js 20 que hacen que la resolución de paquetes sea más rápida y confiable.

 Yagiz Nizipli
Yagiz Nizipli
11 min
04 Apr, 2024

Comments

Sign in or register to post your comment.

Video Summary and Transcription

En esta charla, el orador discute la resolución de paquetes en Node.js, abordando temas como CommonJS, módulos ES, estructura de package.json y cargador de package.json. La charla también aborda la carga condicional y la resolución de extensiones de archivo, la importación y exportación de módulos, la determinación del tipo de módulo basado en las extensiones de archivo y package.json, las estrategias de resolución de módulos en Node.js y consejos para mejorar el tiempo de carga en aplicaciones ESM.

Available in English

1. Comprendiendo la resolución de paquetes en Node.js

Short description:

En esta parte, discutiremos CommonJS, módulos ES, ESM, la estructura de package.json y el cargador de package.json en Node.js. CommonJS es la estrategia de resolución de módulos más conocida en Node.js.

Hola, hoy voy a hablar sobre la comprensión de la resolución de paquetes en Node.js. Soy Yalcin Zipli. Soy un ingeniero de software senior en Sentry. Soy miembro del Comité Técnico de Node.js y miembro del Consejo de Proyectos Cruzados de la Fundación OpenJS. Puedes contactarme a través de mi cuenta de GitHub, github.com, y en Twitter, axe.com.

En resumen, hoy hablaremos sobre CommonJS, módulos ES, ESM, la estructura de package.json y el cargador de package.json en Node.js.

Comencemos con CommonJS. CommonJS es la primera y la estrategia de resolución de módulos más conocida en Node.js. Incluye archivos con implementaciones de require, exportaciones con module.export o exports. Puede tener una extensión de .cgs o .js. Las llamadas a require no tienen que incluir la extensión del archivo y la carga de un archivo es síncrona.

2. Carga condicional y resolución de extensiones de archivos

Short description:

Si deseas realizar una carga condicional donde se carga y utiliza un archivo en una función, debes usar require dentro de la función. Sin embargo, esta implementación puede bloquear la ejecución y el IOU dependiendo del tamaño del archivo. La extensión no es obligatoria y el cargador verifica las diferentes extensiones en un orden específico. Cargar un archivo sin extensión implica llamadas síncronas al sistema de archivos, lo cual puede afectar el rendimiento.

Básicamente, si deseas realizar una carga condicional, digamos que tienes una función llamada leer archivo, y justo cuando se ejecuta esta función, deseas cargar un archivo y utilizar esa implementación en tu función, entonces debes usar require dentro de esta función.

La advertencia de esta implementación es que en la primera línea de leer archivo, el módulo cargado de forma perezosa es igual a require.reader, lo cual bloqueará la ejecución de este archivo porque es una llamada síncrona. Y bloqueará el IOU dependiendo del tamaño del archivo en sí.

Como puedes ver, la extensión no es obligatoria, .reader. Esto significa que primero el cargador verificará la extensión .gs, luego .json y así sucesivamente. Y luego devolverá un valor y luego podemos ejecutar esta función.

Para cargar este archivo sin extensión, esta implementación realiza una llamada síncrona al sistema de archivos para determinar si el archivo reader.js existe. Si no existe, verifica automáticamente si existe reader.json, y así sucesivamente, y luego devolverá un error si no se encuentra.

Esto es particularmente lento porque para determinar si ese archivo existe, necesitas realizar llamadas adicionales al sistema de archivos y esto afectará tu rendimiento, ya sea pequeño o grande, lo afectará.

3. Importación y Exportación de Módulos

Short description:

En CommonJS, se incluyen módulos adicionales utilizando requires y exports. Los módulos de ES utilizan las declaraciones import y export. La declaración import devuelve una promesa y se debe evitar si está dentro de una función. Los módulos se pueden exportar con export o export default. Las extensiones de archivo para los módulos de ES pueden ser .mgs o .gs.

A pesar de la implementación de CommonJS, como dije, CommonJS, para incluir módulos adicionales con CommonJS, necesitas llamarlo con requires. Dentro de la función que deseas requerir, necesitas exportar la implementación con module.express y así sucesivamente. Por lo tanto, puede tener una extensión de .cgs, que es CommonJS, y .jsimplementation. Pero en los módulos de ES, es muy diferente, la idea detrás de ello. Se introdujo en Node.js 8.5.0 con una bandera experimental. Para incluir archivos, necesitas llamarlo con import. Si esta declaración de importación está en la parte superior de la implementación, como si no estuviera dentro de la función, entonces puedes usar import blah blah. Pero si está dentro de una función, debes evitar la declaración de importación porque import devuelve una promesa. Exporta implementaciones con export y export default, y puede tener una extensión de .mgs o .gs y carga asíncrona de un archivo de módulo.

4. Tipo de Módulo y Package.json

Short description:

Para cargar módulos de forma condicional, utiliza lazyLoadedModule?equal y evita la declaración de importación. Esto permite la carga asíncrona sin bloquear la E/S. Node.js determina el tipo de módulo en función de las extensiones de archivo y la presencia de un archivo package.json. El atributo type en el package.json especifica si es un módulo o un CommonJS.

Entonces, en esencia, es una estructura de carga asíncrona. Para cargar el módulo de forma condicional, al igual que en la implementación anterior, necesitas llamarlo con lazyLoadedModule?equal, evadir la importación y esto hace que esta función en particular sea una llamada asíncrona, ya sea que lazyLoadedModule.haga algo de forma asíncrona o no. Esta es la razón principal por la que, cuando evades un módulo de importación, no bloquea la E/S.

Además de eso, hablamos sobre las extensiones de archivo CommonJS y las extensiones de archivo MGS, entonces, ¿cómo sabemos realmente qué está sucediendo? Así que tenemos este archivo package.json en todos nuestros proyectos. Contiene metadatos sobre un proyecto, pero a Node.js solo le importan 5 de esos campos. Nombre, principal, imports, exports y type. Por el bien de esta presentación, me voy a centrar solo en el atributo type. El tipo puede ser un módulo o un CommonJS. Así que creo que estás entendiendo hacia dónde voy con esto. En este ejemplo, tenemos un nombre node-congress-2024, tenemos un atributo principal y tenemos un tipo, que corresponde a modules. Entonces, ¿cómo sabe Node.js si estás usando ESM o CommonJS? Primero, verifica las extensiones de archivo, Node.js verifica las extensiones de archivo. Si es MGS, entonces es ESM. Si es CGS o JS, entonces es CommonJS. Entonces, encontrando el package.json, primero verificamos las extensiones.

5. Resolución de Módulos y Consejos

Short description:

Si la extensión es un archivo .js, Node.js verifica la existencia de package.json en el directorio del archivo. Si se encuentra, verifica el campo type en package.json. Si el tipo es module, utiliza los cargadores ESM; de lo contrario, es CommonJS. Si el tipo no está presente, Node.js verifica la bandera experimental detect module. Para archivos requeridos desde ESM implementado en CommonJS, Node.js sigue la resolución de profundidad de módulos. Para mejorar el tiempo de carga, utiliza la bandera experimental default type CLI para aplicaciones ESM.

Si la extensión es básicamente un archivo .js, entonces no sabemos qué es, entonces necesitamos buscar el package.json en el que estamos ejecutando este archivo. Así que necesitamos conocer el contexto. Por lo tanto, Node.js intenta encontrar el package.json más cercano en el directorio hasta la raíz. Por lo tanto, verifica app, my, project, package.json, y así sucesivamente, hasta la raíz. Si no se encuentra, entonces asumirá algo más.

Node.js lo verifica y cuando se encuentra el valor package.json, Node.js verifica el campo type en package.json. Si es module, utiliza los cargadores ESM, la implementación de cargadores en Node.js. Y si no lo es, entonces es CommonJS. Entonces, si el tipo no está presente, no pudimos encontrar el package.json, ¿qué sucede? Si el tipo no está presente, se verifica una bandera experimental, experimental detect module. Esto es bastante nuevo en Node 20 o 21. Verifica automáticamente si el archivo que estás ejecutando es un archivo CommonJS o un archivo ESM. Esto es particularmente nuevo porque es una bandera experimental y hay problemas conocidos con ella, pero estamos trabajando en ello.

Entonces, si tenemos experimental detect module, entonces detectamos si el archivo es requerido, si es un ESM o un CommonJS. Si no, entonces volvemos a CommonJS. Entonces, sabemos cómo comienza nuestra aplicación, porque sabemos que el script inicial está escrito en ESM o CommonJS. Pero el problema es, ¿qué sucede si quieres requerir un archivo desde ESM que está implementado en CommonJS? ¿O quieres llamar a una función que es CommonJS o un ESM desde un módulo CommonJS? Entonces, ¿qué pasa con la resolución de profundidad de módulos de Node.js? Como si tienes módulos de Node implementados, un paquete dentro de tu lista de dependencias, y está implementado en CommonJS o ESM. Node.js verifica el campo type en el package.json de la dependencia. Si es module, utiliza ESM, de lo contrario, CommonJS. Si el tipo no está presente, utiliza el tipo del paquete padre, que es el paquete raíz que contiene el package.json de nuestro proyecto.

Continuemos con algunos consejos para mejorar el tiempo de carga. Porque hablamos de todos estos cargadores de package.json, llamadas al sistema, hablamos de la detección, las extensiones, y así sucesivamente. Entonces, si quieres evitar todas esas cosas y si quieres iniciar Node.js lo antes posible, lo que puedes hacer es, si tienes una aplicación ESM, puedes usar la bandera experimental default type CLI, que eliminará automáticamente todas esas comprobaciones y siempre devolverá ESM. No verificará la extensión, no verificará nada más, simplemente cargará el cargador ESM. Para proyectos existentes, utiliza un campo type en package.json para especificar el tipo de módulo. Si no tienes un tipo CommonJS, entonces asumimos que es CommonJS, pero si lo tienes, te recomiendo que lo uses. Para scripts de una sola vez, digamos que quieres ejecutar Node.index.js y no tienes package.json ni nada más. Así que si estás ejecutando un script de una sola vez, asegúrate de tener en el mismo directorio o en el directorio padre, un package.json con un campo type para que sepamos si es un ESM o un CommonJS, y no tengamos que recorrer todo el sistema de archivos en una ruta de archivo para entender si es ESM o CommonJS. Si no quieres hacer eso, si no quieres tener un package.json, debes usar .mgs para ESM y .cgs para CommonJS. Por supuesto, esto nos indica si es un ESM o un CommonJS. Además, puedes usar experimental detect module si solo quieres escribir .gs, pero no quieres preocuparte por las extensiones o package.json, siempre puedes usar experimental detect module. Pero ten en cuenta que esta es una bandera experimental y tiene algunos problemas. Además, lo primero que puedes hacer es usar experimental default module para ESM si quieres ir directamente al camino ESM. Para mejorar la resolución de módulos, como dije, por defecto, verificamos .gs, .json, y así sucesivamente. Siempre usa extensiones en las llamadas de importación requeridas. Esto es extremadamente importante. En ESM, esto es requerido. En CommonJS, no lo es. Pero te recomendamos que siempre uses extensiones. Gracias por escuchar y espero que hayas aprendido algo hoy.

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.
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
DevOps.js Conf 2022DevOps.js Conf 2022
31 min
pnpm – a Fast, Disk Space Efficient Package Manager for JavaScript
You will learn about one of the most popular package managers for JavaScript and its advantages over npm and Yarn.A brief history of JavaScript package managersThe isolated node_modules structure created pnpmWhat makes pnpm so fastWhat makes pnpm disk space efficientMonorepo supportManaging Node.js versions with pnpm
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?

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.