Lesson Weekend

When we build our code, how does webpack know which files are dependencies? Going back to our example of the peanut butter and jelly sandwich example, how do we let webpack know that jelly.js needs blueberry.js to work properly?

We need to use import and export statements in our code. These statements are a nice piece of functionality that was added to EcmaScript6 (the technical name for JavaScript), which came out in 2015. (Later this week, we'll be diving into more ES6 features.)

Before ES6, developers used NodeJS require statements to share logic between files. We've already seen a require statement in our webpack.config.js file in the following line: const path = require('path');. Now let's take a closer look.

Here's an example. Let's say we want to include our Triangle constructor in our user interface logic (main.js).

Note: Don't add this to your own code. We are going to use the ES6 way of doing things, not require statements. This is just an example of the Node way of doing things.

triangle.js
function Triangle(side1, side2, side3) {
  this.side1 = side1;
  this.side2 = side2;
  this.side3 = side3;
}

Triangle.prototype.checkType = function() {
  return "I can't answer that yet!";
};

// Don't add this to your own code.
exports.triangleModule = Triangle; 

Let's look at the final line of code in this snippet. We take the Triangle constructor (on the right side) and assign it to exports, calling it triangleModule.

Now we can import the Triangle constructor into our user interface logic like this:

main.js
const Triangle = require('./triangle.js').triangleModule;

We use the require statement to get the triangleModule from the specified relative path. Note that the relative path will vary depending on the project. In our project, main.js and triangle.js are in the same directory so the relative path is ./. The triangleModule in saved in a variable so it can be used in this file. Now we can do something like this in main.js:

const triangle = new Triangle(3,3,3);

Here, Triangle actually refers to our triangleModule - not Triangle itself. However, since the triangleModule has been set to Triangle, they are essentially the same thing.

Importing and Exporting Code

Why bother to learn about require statements when we aren't going to use them in our own code? There are two reasons.

  • You will see require statements a lot in other code, especially server-side Node code. They are all over the place and you need to recognize them and understand how they work.

  • import and export statements, which we will be using, are just syntactic sugar for require statements. They are just using require under the hood.

Here's how we can use import and export instead. Note: Even though we will be using this in our code, you don't need to add it now - this lesson is for demonstration purposes.

triangle.js
export function Triangle(side1, side2, side3) {
  this.side1 = side1;
  this.side2 = side2;
  this.side3 = side3;
}

Triangle.prototype.checkType = function() {
  return "I can't answer that yet!";
};
main.js
import { Triangle } from './triangle.js';

We specify that we want to export the Triangle constructor in our business logic file. Then we specify that we want to import the constructor in our interface logic file. As we can see, it's a little bit cleaner than using require statements.

We can also have multiple export statements in a single file like this:

shapes.js
export function Triangle(side1, side2, side3) {
  ...
}

export function Circle(radius) {
  ...
}

export function Rectangle(side1, side2) {
  ...
}

Then we'd import all the shapes like this:

main.js
import { Triangle, Rectangle, Circle } from './shapes.js';

Note that in our own code, we will separate shapes out into their own files. However, there are plenty of situations where you might be exporting multiple things from a file (such as multiple different functions).

The exports in the examples above are called named exports. This is because the name of the thing being exported must match the name of the thing being imported. We can't say: import { Thingy } from './../js/shape.js'; and expect JavaScript to know we mean Triangle.

Default Exports

If we only plan to export one thing from a file, we can use a default export instead. For instance, let's say the only thing we plan to export from triangle.js is Triangle. We can do the following:

triangle.js
export default function Triangle(side1, side2, side3) {
  ...
}

Remember, this only works if we are exporting only one thing from a file - and we must include the default keyword.

When we use default exports, we have to make a small but significant change to our import statements as well:

main.js
import Triangle from './triangle.js';

Note that we no longer use curly braces ({ }) around the thing we are importing. In fact, because we are importing a default, we don't even need to call it Triangle. We could do something like this:

main.js
import MyTriangle from './../js/triangle.js';

This is a key thing distinguishing named exports from default exports. We can do the following with a default export: import Thingy from './../js/shape.js';. That's because JavaScript knows that only one thing is being imported from the file so we can call it whatever we want. However, it's better to keep the naming consistent to avoid confusion. That means we will generally keep the name exactly the same even though we don't have to.

Make sure you understand the difference between named exports and default exports - as well as the subtle but significant difference between the import syntax for both. These little differences trip up many developers.

While ES6's implementation of classes and modules is really just syntactic sugar over the traditional way of doing things (using require statements), utilizing these features can make your code cleaner, more organized, and easier to read. You should recognize both ways of importing and exporting code, but we'll focus on using import and export while at Epicodus.

One other thing to note: some browsers don't understand require statements or import and export statements. Evergreen browsers like Chrome do, but in the real world, many people aren't using Chrome - and may even be using a legacy browser that doesn't support this syntax. Fortunately, webpack will take care of that for us! This is where concatenating files comes into the picture. We'll cover that in the next lesson.

Lesson 11 of 48
Last updated April 8, 2021