DEV Community

Joe Shindelar
Joe Shindelar

Posted on • Originally published at Medium

Use Module.exports to Keep Node.js Code Organized

Use Module.exports to Keep Node.js Code Organized

Photo by frank mckenna on Unsplash

Written by Jon Church and Joe Shindelar. Originally published on Medium.

Node doesn’t care if we write our entire project in one huge index.js file. But if you want people to be able to read your code, you need to organize it in a way that makes sense and is easy to maintain. Enter Node’s module system!

What exactly is a module? Modules organize related functions together into a file, that we can import later when we need to use them. A module encapsulates related code into a single unit, usually stored in a file. Every file in Node can be considered a module, and each has its own module global object available in the file that we will use to expose code for importing in another file.

In this tutorial we’ll:

  • Learn about module.exports
  • Export helper functions from a file
  • Include our helper functions in another file using require

By the end of this tutorial you should be able to use Node’s module system to create your own modules so you can reuse code in your project.

Goal

Import helper functions from helpers.js in another file, index.js.

What is module.exports?

To export code from a file, we assign values to the file's module.exports object. Each JavaScript file in Node has a module.exports object in its global scope that represents that specific file. That object will hold any code that we want to export from the file. We can assign an object, a single function, or any value to module.exports to be used again in another file.

This is part of the module system in Node. Each file has a global object in its scope called module , which holds information about that specific file. We can expose code from that file by assigning it to module.exports.

What is require?

Require helps us load modules. To import code from a file, we must pass the file’s path to require: require('./filepath'). Calling require on a JavaScript file will run the code in the file, and return the value of module.exports.

This is actually very similar to what happens when you require an npm module. Except in this instance, we are passing require a path to a file instead of the name of a package. When you require an npm package, the same thing is happening behind the scenes in your node_modules/ folder, where the package is installed to.

Here we export a string from a file called testModule.js:

// testModule.js
module.exports = "This is a test!"

// index.js
const test = require('./testModule.js')
console.log(test) // => "This is a test!"
Enter fullscreen mode Exit fullscreen mode

In any given file, we can assign things to module.exports to allow us to import them in another file using a require statement.

When the require is called with a file path, the code in that file will be evaluated and module.exports will be returned.

// helpers.js
console.log('I got required!)
module.exports = "Exported!"
// index.js
const exportedValue = require('./helpers.js')
Enter fullscreen mode Exit fullscreen mode

The above code will output “I got required!” to the console, and exportedValue will be equal to “Exported!” .

If we rerun the require statement (after the first instance), we would still get the exported value of module.exports, but the console.log would not run again. This is because require statements are cached; they are run once, and then calling them again will just return the value of module.exports.

You might also see ES6 code like this at some point:

// helpers.js
export default = "I'm an export!"

// index.js
import helpers from './helpers.js'
Enter fullscreen mode Exit fullscreen mode

This uses ES6 module syntax, and currently no Node engine supports this by default. You can use this style if working with something like Babel that transpiles your code for you. But for now, know that we are talking about the CommonJS syntax of exports, module.exports .

Creating a Helpers File

So let’s use module.exports to export some functions from a helpers.js file to do some simple math, and then use them in another file, index.js, with the help of require.
One option is to export a single anonymous function from a file.

Let’s export a single function that multiplies a number by 2 and use it in our index.js file:

// helpers.js
module.exports = function(x) {
    return x * 2
}

// index.js
const helpers = require('./helpers.js')
helpers(4) // => 8
Enter fullscreen mode Exit fullscreen mode

We set the value of module.exports to the function we want to import, and require it in index.js.
Handy, but what if you want to export several functions at once? Well, we can export an object literal that holds several functions, then access the functions by their names. This is also called Named Exports, because we can choose to later import only the properties we want by name.

// helpers.js
module.exports = {
    multiplyByTwo: function(x) { return x *2 },
    divideByTwo: function(x) { return x / 2}
}

// index.js
const helpers = require('./helpers.js')
helpers.multiplyByTwo(10) // => 5
// or, you can import just the named property you need
const divideByTwo = require('./helpers.js').divideByTwo
divideByTwo(18) // => 9
Enter fullscreen mode Exit fullscreen mode

Requiring the file returns the object we exported with module.exports . You can also import only the property you need, by using dot syntax after the require statement.

Instead of having to declare the functions all in one place, we can make use of a different syntax. Here, we directly export a named property on the module.exports object.

// helpers.js
module.exports.multiplyByTwo = function(x) { return x * 2 }
module.exports.divideByTwo = function(x) { return x / 2 }
function nonExportedFunction(x) {
    return x * 3
}
// index.js
const helpers = require('./helpers.js/)
const divideByTwo = require('./helpers.js').divideByTwo
Enter fullscreen mode Exit fullscreen mode

In the code above, module.exports will look the same as the object we exported in the previous example. Both will be an object with two keys, multiplyByTwo and divideByTwo. The only difference is that we assigned them one at a time.

Note: Make sure you don’t mix the above syntax with exporting an object directly. If you assign something to module.exports later in your file, it will overwrite anything you had already exported.

// helpers.js
module.exports.multiplyByTwo = function(x) { return x * 2 }
module.exports.divideByTwo = function(x) { return x / 2 }
module.exports = "I just overwrote all my exports! Don't mix these styles!"
Enter fullscreen mode Exit fullscreen mode

Passing arguments to a module

We can have a little fun with our math helpers by using some currying. Currying is a concept from functional programming: you call a function with a variable and get another function back that has that variable baked in already. It’s a sort of configuration, if you will. That’s a simple way to put it, but it can be very powerful.

Let’s make our math functions center around a single number to do operations with. We can pass in that number when requiring the file, and get back functions that multiply, divide, or add with the number we initially passed to our curry function.

// curryHelpers.js
module.exports = function(x) {
    return {
    multiply: function(y) { return y * x },
    divide: function(y) { return y / x },
    add: function(y) { return y + x }
    }
}

// index.js
const byTwo = require('./curryHelpers.js')(2)
const byTen = require('./curryHelpers.js')(10)

byTwo.multiply(5) // => 10
byTwo.divide(14) // => 7
byTwo.add(9) // => 11

byTen.multiply(5) // => 50
Enter fullscreen mode Exit fullscreen mode

This is an example of passing a variable into a file’s scope using require and module.exports. We passed the number 2 into the curryHelpers file’s scope by calling the function returned by require. The object of functions we exported are now configured to multiply, divide, and add any number passed to it by the initial number we passed in, 2. We did the same thing with the number 10, and got back an object of functions configured with the number 10.

exports as shorthand for module.exports

Finally, a shorthand for module.exports can be used. The exports object is globally available as well, and points to the same object as module.exports.

So the following code is equivalent:

// assigning named exports
module.exports.pizza = true
exports.pizza = true

// exporting an object
module.exports = {}
exports = {}
Enter fullscreen mode Exit fullscreen mode

Wrapping up

Node is a very modular language, and you can take advantage of that yourself by using module.exports to help export and reuse code in your project. Using require, you can import that code in any other file in your project. The idea of importing modules is very common in Node and understanding module.exports will help you navigate that modular approach.

I hope you’re able to use some of these patterns in your code!

If you want to learn more about module.exports and how it works, you could learn about module scope and the CommonJS module system.


Lullabot Education is ramping up our Node.js training. Sign up for our newsletter and learn about upcoming guides and tutorials — and help shape the future of Node.js education.

Top comments (1)

Collapse
 
qm3ster profile image
Mihail Malo

Does exports = {} actually work?
I thought that's when you MUST use module.exports = {}.