# Understanding export and import in CommonJS

I'm pretty sure this is not the first time that I got confused by the various exports' syntax in CommonJS and definitely will not be the last. Hence, this article will hopefully be useful for my future self whenever I need a reference.

# Scenario

Consider a simple scenario where there you have 2 files; `index.js` and `reference.js` where `index.js` will import `reference.js` to use some object exported by `reference.js`.

```js
// reference.js
const address = {
    street: 'old middle road',
    postal: 123456
}

exports.address = address;

// index.js
const address = require('./reference.js');

console.log(address);
```

The output would be

```js
{ address: { street: 'old middle road', postal: 123456 } }
```

# Confusion

Trying to access the object value `street` by calling

```js
console.log(address.street);
```

which result as

```js
undefined
```

What happened? Essentially, the exported object actually nested another `address` object, hence, in order to access the value, I should run

```js
console.log(address.address.street);
```

Which would have resulted in

```js
old middle road
```

It's actually quite obvious when I had the imported `address` object printed out, but it just didn't register to me straightaway

# Walkthrough

Let's try to figure out what actually happens, and see how we can understand a little more what's happening

For each of the `javascript` file, we can think of it as being a standalone `module` which can be imported and exported. 

Let's take a look at `reference.js`

```js
const address = {
    street: 'old middle road',
    postal: 123456
}

console.log(module);

---

// output
Module {
  id: 'C:\\Users\\Joseph\\Desktop\\scripts\\reference.js',
  path: 'C:\\Users\\Joseph\\Desktop\\scripts',
  exports: {},
  filename: 'C:\\Users\\Joseph\\Desktop\\scripts\\reference.js',
  loaded: false,
  children: [],
  paths: [
    'C:\\Users\\Joseph\\Desktop\\scripts\\node_modules',
    'C:\\Users\\Joseph\\Desktop\\node_modules',
    'C:\\Users\\Joseph\\node_modules',
    'C:\\Users\\node_modules',
    'C:\\node_modules'
  ]
}
```

Let's zoom into `Module.exports` where we have yet to export anything from `reference.js`, hence, it shows an empty object. Now, let's export it like we did previously.

```js
const address = {
    street: 'old middle road',
    postal: 123456
}

exports.address = address;

console.log(module);

---

// output
Module {
  id: 'C:\\Users\\Joseph\\Desktop\\scripts\\reference.js',
  path: 'C:\\Users\\Joseph\\Desktop\\scripts',
  exports: { address: { street: 'old middle road', postal: 123456 } },
  filename: 'C:\\Users\\Joseph\\Desktop\\scripts\\reference.js',
  loaded: false,
  children: [],
  paths: [
    'C:\\Users\\Joseph\\Desktop\\scripts\\node_modules',
    'C:\\Users\\Joseph\\Desktop\\node_modules',
    'C:\\Users\\Joseph\\node_modules',
    'C:\\Users\\node_modules',
    'C:\\node_modules'
  ]
}
```

Notice that it now shows the `address` object being `exported` as part of the `Module` object.

As mentioned, it wasn't obvious to me before that there was another nested level of `address` object due to the way I exported the object. What I did was to add another level of property before I exported `address` object

```js
// this
const address = {
    street: 'old middle road',
    postal: 123456
}

exports.address = address;

// is the same as doing this
module.exports = {
    address: {
        street: 'old middle road',
        postal: 123456
    }
};

// or doing this
module.exports = { address };
```

And what I really wanted was 

```js
module.exports = {
    street: 'old middle road',
    postal: 123456
};

// or
module.exports = address;
```

So if this was exported correctly, the `Module` object output should be

```js
Module {
  id: 'C:\\Users\\Joseph\\Desktop\\scripts\\reference.js',
  path: 'C:\\Users\\Joseph\\Desktop\\scripts',
  exports: { street: 'old middle road', postal: 123456 },
  filename: 'C:\\Users\\Joseph\\Desktop\\scripts\\reference.js',
  loaded: false,
  children: [],
  paths: [
    'C:\\Users\\Joseph\\Desktop\\scripts\\node_modules',
    'C:\\Users\\Joseph\\Desktop\\node_modules',
    'C:\\Users\\Joseph\\node_modules',
    'C:\\Users\\node_modules',
    'C:\\node_modules'
  ]
}
```

And to use it by `importing` from another `javascript` file, it would simply be just

```js
// index.js
const address = require('./reference.js');

console.log(address.street);

// output
old middle road
```

I feel that another point of confusion was that the exported property name was defined as  `module.exports.address = address` and I had it imported as `const address = require('./reference.js');`

```js
// reference.js
module.exports.address = address

// index.js
const address = require('./reference.js');
```

Had I imported it with a different value, it would have been less confusing

```js
// index.js
const reference = require('./reference.js');

// accessing
console.log(reference.address.street); // old middle road
```


Well, that's all nice and well, but what if I need to export or import multiple objects?

One way is simply to export as multiple property

```js
const address = {
    street: 'old middle road',
    postal: 123456
}

const employment = {
    company: 'google',
    yearStart: 2000,
    yearEnd: 2011
}

module.exports.address = address;
module.exports.employment = employment;

// Module output
Module {
  exports: {
    address: { street: 'old middle road', postal: 123456 },
    employment: { company: 'google', yearStart: 2000, yearEnd: 2011 }
  }
}
```

Or to export as `module.exports` which would have resulted in the same `Module output` as above

```js
module.exports = { address, employment };
```

And import to use as such

```js
const reference = require('./reference.js');

console.log(reference.address.street); // old middle road
console.log(reference.employment.company); // google
```

Or we could use `destructure` way, in other words, `named import`

```js
const { address, employment } = require('./reference.js');

console.log(address.street); // old middle road
console.log(employment.company); // google
```

To view what is it like to import from the external file is to log out the import

```js
// given export in reference.js
module.exports.address = address;

// index.js
console.log(require('./reference.js'));

// would result in
{ address: { street: 'old middle road', postal: 123456 } }
```

```js
// given export in reference.js
module.exports.address = address;
module.exports.employment = employment;
// or
module.exports = { address, employment };

// index.js
console.log(require('./reference.js'));

// would result in
{
  address: { street: 'old middle road', postal: 123456 },
  employment: { company: 'google', yearStart: 2000, yearEnd: 2011 }
}
```

The imported object should have matched the `exports` in `Module output`

# Conclusion

I talked about how does the various export look like and exporting single or multiple values. How logging out the `Module` or `import statement` would have helped to view the exact value that was exported or imported. Hope that this gives you a little more insights of what's happening behind the scene.
