Providing both default and named exports in JavaScript
I always wondered how some NPM packages provided a default export in addition to named exports. Something like this:
js
// Provide the most common use caseconst validator = require("my-validator");// Then you can use validator() or one of the components such as validateEmail()// Validate everything in oneconst isValid = validator(payload);// Or validate specific thingsconst isValidEmail = validator.validateEmail(payload.email);
Then one day I was using nock to write some tests and noticed that they do the same thing:
js
const nock = require("nock");nock.disableNetConnect();const scope = nock("http://www.example.com").get("/resource").reply(200, "path matched");
So, I went digging in the code and found that it can be accomplished by setting module.exports
to be a function, then using Object.assign
to attach new method to the function prototype:
js
// my-validator/main.jsconst validateEmail = require('./validators/email');const validatePhoneNumber = require('./validators/phone');const validateAddress,= = require('./validators/address');module.exports = function(payload){// Do validation}Object.assign(module.exports, {validateEmail,validatePhoneNumber,validateAddress,});
Now that I’ve seen it in action it makes total sense. Using named exports allows you to export useful functions from your package without people needing to require specific files (which you may choose to move in the future). Object.assign
expands your public API, providing additional value to consumers but also additional maintenance burden to you.
Now you know how to expose multiple functions from a single package as part of your public API. Now, you just need to decide what you want to expose as your public API 😀.