I'm testing a bunch of React JSX components. They all need to be transpiled with React, or Babel or whatever, but we have special needs for stubbing requirements, so I'm trying to override requires with a special compiler that's run with Mocha. The solution below works well, but you'll notice that we're using require.extensions[]
to capture all the .jsx
files. What concerns me is that require.extensions is locked and deprecated. Is there any better way to do this?
// Install the compiler.
require.extensions['.jsx'] = function(module, filename) {
return module._compile(transform(filename), filename);
};
Here's the whole transpiler for reference:
// Based on https://github.com/Khan/react-components/blob/master/test/compiler.js
var fs = require('fs'),
ReactTools = require('react-tools');
// A module that exports a single, stubbed-out React Component.
var reactStub = 'module.exports = require("react").createClass({render:function(){return null;}});';
// Should this file be stubbed out for testing?
function shouldStub(filename) {
if (!global.reactModulesToStub) return false;
// Check if the file name ends with any stub path.
var stubs = global.reactModulesToStub;
for (var i = 0; i < stubs.length; i++) {
if (filename.substr(-stubs[i].length) == stubs[i]) {
console.log('should stub', filename);
return true;
}
}
return false;
}
// Transform a file via JSX/Harmony or stubbing.
function transform(filename) {
if (shouldStub(filename)) {
delete require.cache[filename];
return reactStub;
} else {
var content = fs.readFileSync(filename, 'utf8');
return ReactTools.transform(content, {harmony: true});
}
}
// Install the compiler.
require.extensions['.jsx'] = function(module, filename) {
return module._compile(transform(filename), filename);
};
And some links to simalar solutions...
A solution can be forked from here: https://github.com/danvk/mocha-react
Use Import Instead of Require in Node App.
extname() method is used to get the extension portion of a file path. The extension string returned from the last occurrence of a period (.) in the path to the end of the path string. If there are no periods in the file path, then an empty string is returned.
If you want to use require module then you have to save file with '. js' extension. If you want to use import module then you have to save file with '.
You can think of the require module as the command and the module module as the organizer of all required modules. Requiring a module in Node isn't that complicated of a concept. const config = require('/path/to/file'); The main object exported by the require module is a function (as used in the above example).
There are two reasons that API has been deprecated. One, the node module resolution algorithm is VERY complicated, it has to look at the specified file, if it doesn't exist it looks for that file and all the possible extensions in the keys of require.extensions
, and if it's a directory, look for a package.json or index.js. Oh, and don't forget, if there is no ./
at the beginning, it looks in the node_modules directory, looking at the parent directory if it can't be found in that node_modules
. Ryan Dahl said he regrets making it so complicated in his talk at JsConf 2018, and uses a much simpler module resolution algorithm in his deno project. Two, it needs more filesystem calls if there are more extensions in require.extensions, because it has to match extensionless files.
A solution to the second problem is require-extension. I haven't used it myself, but it abstracts the require.extensions API and makes it much more performant.
There is no other way to do this, and this is how everybody does transpiling (babel, etc). @uni_nake's answer - to use node-hook - is OK in that it hides this from you, but it essentially uses the same mechanism: a look in it's code shows that it uses Module._extensions, but this is the same as require.extensions, as shown by a test I wrote: https://github.com/giltayar/playing/blob/1f04f6ddc1a0028974b403b4d1974afa872edba4/javascript/node/test/is-module-extensions-same-as-require-extensions.test.js
So final answer - I would assume that nobody at Node will break Babel, and if they do, they will probably give another solution for the same problem. I would not hesitate to use it!
I use node-hook to stub all .scss
calls in my tests.
You'll see from the docs that when a matching file is required it will execute the containing string instead and is really quite powerful as it also passes you the original source.
Hope that is what you're looking for.
I think you should use pirates
I think the PR when require.extensions
used in babel-register
was replaced with pirates
would be helpful.
https://github.com/babel/babel/pull/3670/files#diff-75a0292ed78043766c2d5564edd84ad2L85-L93
Hope that is what you're looking for.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With