Structure JavaScript Code Using Modules

Introduction

Most people (including myself) start out writing JavaScript code by adding function after function into a .js or HTML file. This can get job done but same time can quickly get out of control when working with a lot of code.

Without having proper structure, maintaining such code bases, can be a nightmare and that nightmare gets worse especially if you didn’t originally write that JavaScript code.

Over the years different pattern emerged to structure JavaScript codebase to avoid a bigger code-base to becoming spaghetti. Revealing Module Pattern, IFEE etc. are well known pattern for such purpose. Having such pattern in your development toolkit is a good first step in right direction.

Modern JavaScript frameworks like Angular, Vue etc. have built-in mechanism to structure JavaScript code. When not using these frameworks, we can now benefit from ES6 enhancements which supports JavaScript modules to structure our JavaScript.

In simple terms, a module is code, that we group together, for the purposes of sharing and reuse. Modules, therefore, allow us to break down complexity in our applications into small chunks. This can help with understanding the code right down to finding and fixing bugs.

ES6 has introduced a mechanism to build modules natively in JavaScript. It is supported by most of the modern browsers. We no longer have to work with IIFE or similar weird syntax to get modularity in our code. We work with these modules using two keywords export and import.

Export is the keyword we use to create the module and then import is used to consume the module.

Export/Import keywords allow us to encapsulate our code into a single protected entity.

Some considerations regarding modules are as follows:

  • Modules are singletons.
  • Properties are bound i.e. if something is exported and changed, it changes everywhere.
  • Modules are file based (one module per file).
    • If you are loading multiple modules, you’re going to request those files one at a time over HTTP (some tool e.g. webpack etc. can consolidate those in one file, however we’ll not be using webpack etc. in our learning today).

Setting the Scene

For our demos, I’ll be using the code which can be downloaded from this git repo (master branch). This is a very simple code base which uses Revealing Module pattern and we will now change this to utilize JavaScript Modules instead. You can also see the corresponding article if you want to understand more about the code and Revealing Module pattern.

You can also use your own existing code base as an alternative as well.

Here is how our current code files looks like:

and here is the index.html part

Please check this code and we will change it to use JavaScript Modules.

Creating Modules

Now we will start to create some modules using the export keyword.

We can use export keyword in different ways as mention below:

  • Named exports
  • Default exports
  • Aggregating Modules

We’ll see examples of all of these.

Named Exports

This is the simplest to start with. We’ll start with file ajaxService.js which currently has the following structure:

Let’s start by eliminating revealing-module pattern part and it will looks like following (a simple JavaScript function) after the changes:

Next, lets add the word export before the function as shown below:

That’s all needed to convert this code to a module.

Next, we’ll start with file dataService.js which currently has the following structure:

Let’s apply the same premise here and start by eliminating revealing module part and it will looks like following:

Next, we’ll move out the getUsersUrl and creatUserUrl variable outside of the outer function as well as getUsers and createUser functions. Our code will look like following after the changes:

and finally, let’s apply export to these functions which we want to expose to consuming code:

Now, we have converted both JavaScript files into modules and we used named exports style for these. We will see shortly that how to import these.

There is another variation to do the named export and we can instead use the following syntax if we like:

or we can use a different name when exporting as shown below:

So, the above shown examples are named exports. We need to know the names of these exports in order to import them in other code (we will see imports later in the post). This is a very common pattern and works well.

But, what if, we don’t want to deal with named exports, then there is another type of exports called default exports. Lets see example of that next.

Default Exports

First, lets updated ajaxService.js to introduce default export:

By adding the keyword default, now we will not need to know the name of this function when we will import this in some other code.

You can only export one thing as the default, you can’t export multiple defaults, it wouldn’t work. However we can still export named export along with default export.

The variation to above shown example is following:

The purpose of default is just to simplify how you will do your imports.

Aggregating Exports

One of the things we want to do is to make sure that our modules are compact and tight, but at the same time we don’t want to have import these whole bunch of modules individually. For example, in previous examples, we have to import things from two different files separately. However, we can aggregate those so our imports are coming from one place then.

Now, we can import functionality from one place and that can help simplifying imports.

The * symbol here means that we want to export everything from the module.

Please note that here if we can have other code inside index.js file as well and the exports we are making here won’t be included automatically in that code (coz its just an export without importing).

Now, as we have seen different ways of using exports, let see few examples of doing imports as well.

Consuming Modules

We’ll use import keyword when we want to consume the JavaScript modules.

Similar to exports, we will see examples of default and named imports.

Enabling Modules

Let’s start index.html file and enable module for app.js file by setting up its type=module as shown below:

Note that I’ve already refactored and updated app.js to use export keyword and it is now in similar shape like other modules. By using type=”module”, we turn on modules for this piece and this will allow us to use import/exports statements inside JavaScript.

Default Imports

Let’s start with dataService.js file and import functionality which is exported from ajaxService.js. We need ajax functionality inside dataService.js to make ajax calls. Following picture shows how we can import and use that functionality:

Now, if you remember, makeAjaxRequest is a default export in ajaxService.js.

but when I am importing things, I can call that whatever I want, that is why it is called default import (coz we are not importing things by name). So if I want I can import it as follows:

So, here I used a different name ajaxCall and this is what we called default imports.

Named Imports

Now we will see example of named imports. Let’s see the code in app.js which consumes functionality from dataService.js.

Notice, here we import functionality by exactly same name as it was exported from dataService.js; hence the term named imports.

Now, I’ve added another module called siteInfo.js which we can also import in app.js and here is the updated code:

Notice that we are using exactly same name when we exported and when importing functionality; hence it is called named imports.

However, a small variation of this is that we can give them a new name after we have done import. So you may also also see syntax similar to following:

Now, lets see another variation. I am here importing everything from dataService.js, I can instead use the following syntax if I like:

Here * means that we want to import everything from that module. Depending on your preference, you have can do imports in variety of different ways.

Aggregate Exports and Imports

One more variation of exports and imports, which I want to show you is related to aggregate exports. Remember we talked about that in previous sections.

Here is the index.js file, which is just re-exporting other modules:

Now, I can do imports in app.js as follows:

This was to show an example, however, I will change the imports in app.js as follows:

Testing the Application

Lets put all this functionality to test by changing the index.html

Now if refresh the application page, I can see following output in the browser’s console widow:

Our code is working as expected.

Summary

In this post, we learned that ES6 natively support export/import mechanism to bundle up functionality and consume it in different parts of our application. We saw that we can create modules using export keyword and consume modules using import keywords.

We saw different ways of exporting and importing modules.

Creating compact and focused modules help us better organize our code and it promotes security, code reusability and such code is easier to debug and maintain.

You can download the code sample from this git repository (moduleformat branch):

Let me know if you have some comments or questions. Till next time, Happy Coding.

My Recent Books

2 thoughts on “Structure JavaScript Code Using Modules”

Comments are closed.