...

/

Untitled Masterpiece

Learn about the resolving algorithm, how it prevents dependency hell, and circular dependencies.

The term dependency hell describes a situation whereby two or more dependencies of a program in turn depend on a shared dependency, but require different incompatible versions. Node.js solves this problem elegantly by loading a different version of a module depending on where the module is loaded from. All the merits of this feature go to the way Node.js package managers (such as npm or yarn) organize the dependencies of the application, and also to the resolving algorithm used in the require() function.

Let’s now get a quick overview of this algorithm. As we saw, the resolve() function takes a module name (which we will call moduleName) as input and it returns the full path of the module. This path is then used to load its code and also to identify the module uniquely. The resolving algorithm can be divided into the following three major branches:

  • File modules: If moduleName starts with /, it’s already considered an absolute path to the module, and it’s returned as it is. If it starts with ./, then moduleName is considered a relative path, which is calculated starting from the directory of the requiring module.

  • Core modules: If moduleName is not prefixed with / or ./, the algorithm first tries to search within the core Node.js modules.

  • Package modules: If no core module is found matching moduleName, then the search continues by looking for a matching module in the first node_ modules directory that is found by navigating up in the directory structure starting from the requiring module. The algorithm continues to search for a match by looking into the next node_modules directory up in the directory tree, until it reaches the root of the filesystem.

For file and package modules, both files and directories can match ...