## Why Doing require extensions correctly is essential, because: 1. Users should be able to install multiple extensions in succession, and have them work together. 2. Coverage tools like `nyc` need it to reliably supply coverage information that takes into account sourcemaps from upstream transforms. 3. Because non-standard, un-predictable behavior causes hard to solve bugs, and major headaches for project maintainers. ## What is a require extension anyways? First, it's worth remembering what default `".js"` extension does. ```js require.extenstions['.js'] = function (module, filename) { var content = fs.readFileSync(filename, 'utf8'); module._compile(internalModule.stripBOM(content), filename); } ``` Really simple. It reads the source content from the disk, and calls the `module._compile`. The default `module._compile` is a non-trivial piece of code, for simplicity I will just say it is what **actually** compiles the code. --- ## Our first custom extension Now let's install a transform that just appends the code `+ "bar"` to the end of every file (humor me as I keep things simple). This is how you would manually create that hook (in what is now widely accepted as the "right" way). ```js // append-bar.js var oldHoook = require.extensions['.js']; // 1 require.extensions['.js'] = function (module, file) { // 2 var oldCompile = module._compile; // 3 module._compile = function (code, file) { // 4 code = code + ' + "bar"'; // 5 module._compile = oldCompile; // 6 module._compile(code + ' + "bar"'); // 7 }; oldHook(module, file); // 9 }); ``` Note that this extension never reads from the disk. That is because the first extension in the chain (the system default one) handles loading from disk. If it's not obvious why that's true (it wasn't for me), keep reading. The **really important** takeaway here is that you should be implementing require extensions almost exactly as I have above. There are multiple levels of indirection, and it can be confusing. Libraries like `pirates` can simplify the process. ## Breakdown with 1 Custom Extension Here is what happens when you call `require("./foo.js")` ```js // foo.js module.exports = "foo" ``` What happens inside `require` boils down to this: ```js function pseudoRequire(filename) { var ext = path.extname(filename); // ".js" var module = new Module(); require.extensions[ext](module, filename); } ``` Now let's step through the sequence of events. 1. The system calls `require.extensions['.js'](module, './foo.js')`. This means `append-bar` is invoked with `(module, './foo.js')` 2. `append-bar` stores a reference to `module._compile` (line 3), an with its own wrapper function (line 4). `module._compile` refers to the `append-bar` wrapper function. `append-bar`'s reference to `originalCompile` refers to the **actual** compile implementation. 3. `append-bar` calls it's `oldHook` (the default `.js` extension) with the modified module and filename (line 9). 4. The default `.js` extension reads in the source (`module.exports = "foo"`), and calls `module._compile(source, filename)`. Remember `module._compile` currently points to the `append-bar` wrapper function. 5. The append-bar wrapper adds ` + "bar"` to the source (Line 5). The source is now `module.exports = "foo" + "bar"`. 6. The append-bar wrapper now replaces `module._compile` with it's `originalCompile` reference (Line 6). `module._compile` now points to the **actual** compile implementation 7. `module._compile` is called again (this time pointing to **actual**, and the source is evaled and we get our result "foobar". ## Breakdown with 2 Custom Extension Assume we have first added the `append-bar` extension from above, followed by another called `append-quz` (which is for all purposes identical, except it appends `baz` instead. 1. We install the `append-bar` extension (replacing the original hook) `append-bar#originalHook` points to the original hook. 2. We install the `append-quz` extension `append-quz#originalHook` points to the `append-bar` hook. 3. We call `require('./foo.js');` 4. `append-quz` hook is called with `(module, './foo.js')`, it replaces `module._compile` with it's wrapper function. `append-quz#originalCompile` points to the **actual** compile `module._compile` points to the `append-quz` wrapper. 5. `append-quz` calls it's `originalHook` reference, which is `append-bar`. 6. `append-bar` replaces `module._compile` with it's wrapper. `append-bar#originalCompile` points to `append-quz` wrapper. `module._compile` points to the `append-bar` wrapper. 7. The original extension is called, which loads the source from disk and calls `module._compile('module.exports = "foo"', './foo.js')` 8. At this point `module._compile` points to the `append-bar` wrapper, so the source is appended with ` + "bar"`. 9. The `append-bar` calls the `originalCompile` reference (which is the `append-quz` wrapper). 10. The `append-quz` wrapper does it's appending (so we've now got `"foo" + "bar" + "quz"`) 11. `append-quz` calls it's `originalCompile` reference, which is **actual** and we get `"foobarquz"`