Level: intermediate
Understanding Package Resolution in Node.js
From Author:
Everytime we import or require a package, we follow a set of rules to resolve the package. This talk will cover the different ways Node.js resolves packages and how to debug when things go wrong. We will also cover the new features in Node.js 20 that make package resolution faster and more reliable.
This talk has been presented at Node Congress 2024, check out the latest edition of this Tech Conference.
FAQ
Yalcin Zipli is a senior software engineer at Sentry, a Node.js Technical Stream Committee member, and an OpenJS Foundation Cross-Project Council member.
You can reach Yalcin Zipli through his GitHub account at github.com and on Twitter at axe.com.
The talk covers CommonJS, ES modules (ESM), package.json structure, and package.json loader in Node.js.
CommonJS is a module resolution strategy in Node.js that includes files with require, and exports implementations with module.exports or exports. It can use extensions such as .cgs or .js and loads files synchronously.
The main difference is that CommonJS uses require and synchronous loading, while ES modules (ESM) use import and asynchronous loading. ESM also returns a promise and can use extensions like .mgs or .js.
Node.js cares about the following five fields in package.json: name, main, imports, exports, and type.
Node.js first checks the file extensions. If it's .mgs, it's ESM; if it's .cgs or .js, it's CommonJS. If the extension is .js, Node.js looks for the type field in the nearest package.json file. If type is not present, it uses an experimental flag or defaults to CommonJS.
The experimental detect module flag in Node.js automatically detects whether a file is CommonJS or ESM. This feature is new and still has known issues.
You can improve module loading time by using the experimental default type CLI flag for ESM, specifying the type field in package.json, using .mgs for ESM and .cgs for CommonJS, and always including file extensions in require and import calls.
Using file extensions in require and import calls helps Node.js avoid additional file system calls, improving performance and clarity in module resolution.
Video Transcription
1. Understanding Package Resolution in Node.js
In this part, we will discuss CommonJS, ES modules, ESM, package.json structure, and package.json loader in Node.js. CommonJS is the most widely known module resolution strategy in Node.js.
Hi, I'm going to be talking about understanding package resolution in Node.js today. I'm Yalcin Zipli. I am a senior software engineer at Sentry. I am a Node.js Technical Stream Committee member and an OpenJS Foundation Cross-Project Council member. You can reach me from my GitHub account, github.com, and from Twitter, axe.com.
So in summary, today we're going to talk about CommonJS, ES modules, ESM, package.json structure, and package.json loader in Node.js.
Let's start with CommonJS. CommonJS is the first and the most widely known module resolution strategy in Node.js. It includes files with require, export implementations with module.export or exports. It can have an extension of .cgs or .js. Require calls does not have to include the extension of the file, and loading a file is synchronous.
2. Conditional Loading and File Extension Resolution
If you want to do conditional loading where a file is loaded and used in a function, you need to use require inside the function. However, this implementation can block the execution and IOU depending on the file size. The extension is not required, and the loader checks for different extensions in a specific order. Loading a file without an extension involves synchronous calls to the file system, which can impact performance.
So basically, if you want to do a conditional loading, let's say you have a function called read file, and just when this function is executed, you want to load a file and use that implementation in your function, then you need to use require inside this function.
The caveat of this implementation is that in the first line of read file, the lazy loaded module is equal require.reader, that's going to block the execution of this file because it's a synchronous call. And it's going to block the IOU depending on the size of the file itself.
As you can see, the extension is not required, .reader. This means that first the loader is going to check for .gs extension, then .json and so on and so forth. And then it will return a value and then we can run this function.
So in order to load this file without an extension, this implementation makes a synchronous call to the file system in order to understand if reader.js file exists. If not, it automatically checks for reader.json, if it exists and so on and so forth, and then it will return an error if it's not found.
This is particularly slow because in order to understand if that file exists, you need to make additional file system calls and it will impact your performance, small or big, it will impact it.
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
Workshops on related topic
Level: intermediate
In this workshop you'll learn how to develop APIs with Fastify and deploy them to the Platformatic Cloud.
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
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.
Comments