In this lesson, you will learn how to intercept and modify the standard module resolution and loading process by creating a custom loader.
What is a Custom Loader?
Normally, when you write import or require, Node.js follows a fixed set of rules to find, read, and interpret your files. A custom loader acts as a middleman in this pipeline. By using the --loader flag, you can hook into these steps to transform source code on-the-fly, handle non-standard file extensions, or even fetch modules from a remote server instead of your local disk.
The Hook Pipeline
Custom loaders work through "hooks." There are two primary hooks you should know:
resolve: Tells Node.js where to find the file. You can use this to rewrite file paths, such as mapping a virtual import to a real file on your hard drive.load: Tells Node.js how to read and format the file content. This is where you can transform code (e.g., compiling TypeScript or injecting code) before Node executes it.
Practical Example
Imagine you want to force all imported .js files to be treated as if they were written in a specific format or simply to add a log message every time a file is loaded. You would create a loader.js file:
// loader.js
export async function load(url, context, defaultLoad) {
const result = await defaultLoad(url, context);
// Intercept the source and append a log
const newSource = `${result.source}\nconsole.log('Loaded: ${url}');`;
return {
...result,
source: newSource,
};
}
To use this, you would run your application with the flag:
node --loader ./loader.js index.js
Why use this?
While you’ve learned about monkey-patching in previous lessons, custom loaders are much safer and more robust. Unlike monkey-patching, which modifies the runtime behavior of existing objects, a loader alters the module before it is even parsed by the engine. This allows you to handle specialized use cases—like transpiling legacy code, adding instrumentation, or redirecting imports—without polluting your core application logic.
Key Takeaway: Custom loaders allow you to intercept the module loading lifecycle, enabling you to transform or redirect module resolution before the code is executed by Node.js.