10.

Importing and Exporting

Whether we’re writing code to be run in web browsers, the console, or anywhere else, having a system for sharing code between files is essential for building projects. Imagine needing to write and read thousands of lines of code in a single file, or using multiple files but needing to copy functions to every file where they need to be used. What horror! This lesson is about the import and export system specifically with Node.js, familiarly known as “node”.

Exporting

JavaScript code in our files is never automatically exported. In order to be able to share code from one file to another, we need to explicitly write which code can be shared. Every JavaScript file that is run with node has a hidden variable called module.exports. If we don’t explicitly set this variable to any value, its value is an empty object {}. Whatever value we give to module.exports is what the file is exporting (meaning it can be imported by another file). The reason for the name module.exports is because node considers every JavaScript file a module. It is most common to export an object because, as we’ve seen, objects allow us to package many things into one value.

Let’s look at an example.

const a = 1;
const b = 2;

module.exports = {
  c: 3
};

If we have a file with the above code, the file is exporting an object with a single property c: 3. The variables a and b are not being exported, thus they are not being shared with any other file. If we want to share them, we can add them to the exports as well:

const a = 1;
const b = 2;

module.exports = {
  a: a,
  b: b,
  c: 3
};

It is common to use shorthand notation in the object for this.

const a = 1;
const b = 2;

module.exports = {
  a,
  b,
  c: 3
};

Importing

The special function for importing a module in node is require(). When we call require() with the name of a module (a JavaScript file), it runs all the code in that module then retrieves the module.exports value of that module. Now we can look at complete examples. Keep in mind that if you want to try these examples out, you will have to create separate files (suggested file names are given).

// Inside numbers.js:

const a = 1;
const b = 2;

module.exports = {
  a,
  b,
  c: 3
};
// Inside index.js:

const someNumbers = require('./numbers.js');

console.log(someNumbers.a); // 1
console.log(someNumbers.b); // 2
console.log(someNumbers.c); // 3

In the above example, we want to run the index.js file, since running numbers.js will not produce any output. So we run the command: node index.js. (The name “index” is commonly used for the main file, for historical reasons.) It is important in this example that we write require('./numbers.js') instead of require('numbers.js') because we want to import a local file; the latter tells node to import an external module from a different place, which is explained in the next section.

Object destructuring is commonly used when importing because it skips the step of needing to give the export object a name and it allows us to selectively import properties.

// Inside numbers.js:

const a = 1;
const b = 2;

module.exports = {
  a,
  b,
  c: 3
};
// Inside index.js:

// Import only a and c from the numbers module
const {a, c} = require('./numbers.js');

console.log(a); // 1
console.log(c); // 3

Finally, let’s look at a more realistic example: sharing a little library of functions.

//Inside functions.js:

const fToC = ftemp => (ftemp - 32) / 1.8;
const cToF = ctemp => (ctemp * 1.8) + 32;

const convertTemperature = (temp, conv) => {
  if (conv === 'FtoC') {
    return fToC(temp);
  } else {
    return cToF(temp);
  }
};

const isEven = x => x % 2 === 0;
const isOdd = (x) => !isEven(x);

module.exports = {
  convertTemperature,
  isEven,
  isOdd
};
// Inside index.js:

const {
  isEven,
  convertTemperature
} = require('./functions.js');

const x = 24;

if (isEven(x)) {
  console.log(convertTemperature(x, 'CtoF')); // 75.2
}

It is generally considered good practice to put exports at the bottom of a file and imports at the top of a file.

Built-in Modules

Now that we’ve seen how to import code from a module that we created, let’s look at importing code from a module that we own but didn’t create. Node comes with built-in modules that are available for us to use but only if we import them. One such example is the fs module, for dealing with the file system. Importing a built-in module is the same as importing a module that we created, except the argument we give to require() should have the name of the module without the path; node knows where to look for built-in modules on our system.

const {readFileSync} = require('fs'); // No dots or slashes before the module name

const fileContents = readFileSync('my-test-file.txt', 'utf8'); // Read the contents of a file
console.log(fileContents); // Print the file's contents

The above example will read the contents of a file named my-test-file.txt that exists in the same directory as the JavaScript file we’re running this code from, then print it out.

Top