If the extension is basically a .js file, then we don't know what it is, then we need to look for the package.json that we are executing this file in. So we need to know the context. So Node.js tries to find the closest package.json in the directory until root. So it checks for app, my, project, package.json, and so on, so forth, until the root. If it's not found, then it's going to assume something else.
Node.js checks it, and whenever the package.json value is found, Node.js checks the type field in the package.json. And if it's module, it uses ESM loaders, the loader implementation in Node.js. And if it's not, then it's CommonJS. So if type is not present, we couldn't find the package.json, what happens? If type is not present, we check for an experimental flag, experimental detect module. This is pretty new in Node 20 or 21. It automatically checks if the file that you're running is a CommonJS file or an ESM file. This is particularly new because this is an experimental flag, and there are known issues with it, but we are working on it.
So if we have experimental detect module, then we detect if the file is a required, if it's an ESM or a CommonJS. If not, then we fall back to CommonJS. So then we know how our application starts, because we know the initial script is written in ESM or CommonJS. But the issue is, what happens if you want to require a file from ESM that's implemented in CommonJS? Or you want to call a function that's CommonJS or an ESM from a CommonJS module? So what about Node.js module depth resolution? Like if you have Node modules implemented, a package inside your dependency list, and it's implemented in either CommonJS or ESM. So Node.js checks the type field in the package.json of the dependency. If it's module, it uses ESM, otherwise CommonJS. If type is not present, it uses the type of the parent package, which is the root package that our project's package.json contains.
So let's continue with some tips to improve the loading time. Because we talked about all of these package.json loaders, system calls, we talked about the detection, the extensions, and so on and so forth. So if you want to avoid all of those things, and if you want to start Node.js as soon as possible, what you could do is that, if you have an ESM application, you can use an experimental default type, CLI flag, which will automatically eliminate all of those checks, and it will always return ESM. It will not check for the extension, it will not check for anything else, it will just load the ESM loader.
Comments