Asked  7 Months ago    Answers:  5   Viewed   27 times

I've found the following contract in a Node.js module:

module.exports = exports = nano = function database_module(cfg) {...}

I wonder whats the different between module.exports and exports and why both are used here.

 Answers

87

Setting module.exports allows the database_module function to be called like a function when required. Simply setting exports wouldn't allow the function to be exported because node exports the object module.exports references. The following code wouldn't allow the user to call the function.

module.js

The following won't work.

exports = nano = function database_module(cfg) {return;}

The following will work if module.exports is set.

module.exports = exports = nano = function database_module(cfg) {return;}

console

var func = require('./module.js');
// the following line will **work** with module.exports
func();

Basically node.js doesn't export the object that exports currently references, but exports the properties of what exports originally references. Although Node.js does export the object module.exports references, allowing you to call it like a function.


2nd least important reason

They set both module.exports and exports to ensure exports isn't referencing the prior exported object. By setting both you use exports as a shorthand and avoid potential bugs later on down the road.

Using exports.prop = true instead of module.exports.prop = true saves characters and avoids confusion.

Tuesday, June 1, 2021
 
ritch
answered 7 Months ago
68

module is a plain JavaScript object with an exports property. exports is a plain JavaScript variable that happens to be set to module.exports. At the end of your file, node.js will basically 'return' module.exports to the require function. A simplified way to view a JS file in Node could be this:

var module = { exports: {} };
var exports = module.exports;

// your code

return module.exports;

If you set a property on exports, like exports.a = 9;, that will set module.exports.a as well because objects are passed around as references in JavaScript, which means that if you set multiple variables to the same object, they are all the same object; so then exports and module.exports are the same object.
But if you set exports to something new, it will no longer be set to module.exports, so exports and module.exports are no longer the same object.

Tuesday, June 8, 2021
 
revive
answered 6 Months ago
71

You can export a single class in TypeScript like this:

class Person {

  private firstName: string;
  private lastName: string;

  constructor(firstName: string, lastName: string) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  public getFullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

export = Person;

And here is how it's going to be used:

var Person = require('./dist/commonjs/Person.js');

var homer = new Person('Homer', 'Simpson');
var name = homer.getFullName();

console.log(name); // Homer Simpson

To be complete, here is my tsconfig.json (I am using TypeScript v2.0.3):

{
  "compilerOptions": {
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "dist/commonjs",
    "rootDir": "src/ts",
    "target": "es5"
  },
  "exclude": [
    "dist",
    "node_modules"
  ]
}
Tuesday, July 27, 2021
 
viper
answered 5 Months ago
77

TL;DR

You can use:

exports.x = 1;
exports.y = 2;
exports.z = 3;

as a shorter way of writing:

module.exports.x = 1;
module.exports.y = 2;
module.exports.z = 3;

The only advantage is less typing.

But you have to write:

module.exports = {
    x: 1,
    y: 2,
    z: 3
};

as this will not work:

exports = {
    x: 1,
    y: 2,
    z: 3
};

because it wouldn't change the module.exports and it's module.exports that actually gets exported.

Explanation

Your module gets wrapped in an implicit closure that gets some variables passed as parameters. One of those variables is called exports that is an empty object and another one is called module and it includes exports as one of its properties:

module.exports === exports

When you write:

exports.x = 10;

then you change the property of the provided object (the object is still the same object, but it is mutated) and everything is fine. The value x is available as both exports.x and module.exports.x.

But if you write:

exports = {x: 10};

then you assign a new object to exports while the module.exports is still pointing to the original (empty) object. That way you have exports.x set correctly but you don't have module.exports.x set as well, because now:

module.exports !== exports

If you want to make a new object instead of using the empty one that you got in exports then you have to assign it to module.exports:

module.exports = {x: 10};

Now module.exports and exports are different as well:

module.exports !== exports

But it's module.exports that's actually exported so everything is fine.

After assigning a new object to module.exports you could assign it to exports as well:

module.exports = {x: 10};
exports = module.exports;

or do it the other way around:

exports = {x: 10};
module.exports = exports;

so you could still use the shortcut of assigning new properties with:

exports.y = 20;

but I haven't seen that in practice.

Real examples

Exporting some functions (public) but not others (private). Let's say you have those functions:

function private1() {
    // ...
}
function private2() {
    // ...
}
function public1() {
    // ...
}
function public2() {
    // ...
}

You have few options to export two public functions:

This works

module.exports.public1 = public1;
module.exports.public2 = public2;

or:

exports.public1 = public1;
exports.public2 = public2;

or:

module.exports = {
    public1: public1,
    public2: public2
};

or:

module.exports = {
    public1,
    public2
};

This doesn't work

exports = {
    public1: public1,
    public2: public2
};

or:

exports = {
    public1,
    public2
};

Summary

In other words, exports is just for convenience so that you don't have to write module.exports every time, but it doesn't work for cases when you want to export a different object than the one provided to you originally. In that case you need to set the module.exports to that new object.

See also

See also this answer:

  • What is the difference between module.export and export
Wednesday, August 11, 2021
 
Anax
answered 4 Months ago
61

UPDATED:

From the documentation:

A module prefixed with '/' is an absolute path to the file. For example, require('/home/marco/foo.js') will load the file at /home/marco/foo.js.

A module prefixed with './' is relative to the file calling require(). That is, circle.js must be in the same directory as foo.js for require('./circle') to find it.

Without a leading '/' or './' to indicate a file, the module is either a "core module" or is loaded from a node_modules folder.

If the given path does not exist, require() will throw an Error with its code property set to 'MODULE_NOT_FOUND'.


Here’s the original answer, which refers to require.paths (which is no longer supported):

From the documentation:

In node, require.paths is an array of strings that represent paths to be searched for modules when they are not prefixed with '/', './', or '../'.

(emphasis mine)

Tuesday, September 28, 2021
 
Greg Malcolm
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share