📢 Attention Salesforce Certified Trailblazers! Maintain your credentials and link your Trailhead and Webassessor accounts by April 19th. Learn more.
close

Organize Code with Modules

Organize Code with Modules

Learning Objectives

After completing this unit, you’ll be able to:

  • Describe how support for modules has evolved over the years.
  • Recognize the basic syntax used to define modules.
  • Distinguish between different importing styles.
  • Demonstrate how named exports results in read-only properties.

The Need for Better Modules

If you are a developer coming from another language, then you likely understand the importance of modular programming. Modular programming involves breaking your code up into logical chunks so that it’s easier to access. Using modules generally results in code that is easier to read and maintain. 

That’s great, but up until ES6, creating modules in JavaScript wasn’t easy. You either had to create an enclosed function and closure, or you could rely on one of the competing module specs like Asynchronous Module Definition (AMD) and Universal Module Definition (UMD), or CommonJS if you were doing Node.js development.

ES6 introduced a long-overdue native module system. But it was separate from all the other ES6 functionality and for a long time, no major browsers supported it. However, that’s finally changed and now most browsers allow you to load ES6 modules with the type="module" attribute on the HTML5 script tag.

Module Basics

Modules are pretty simple to create and use. An ES6 module is essentially just a file containing some JavaScript. Everything inside the module is scoped to that module only. If you want to make something—like a function, a variable, or a class—available somewhere else, you need to use an export statement. You then use an import statement to specify what you want to use from the exported module.

To see how this works for yourself, create a CodePen project that uses the HTML5 script tag to load modules and import a function and two variables.

  1. In your Google Chrome browser, navigate to https://codepen.io/.
  2. Click Create and New Project.
  3. CodePen projects are just for logged in users. If you already have a CodePen account, you can click Log In to enter your credentials. Otherwise, you need to click Sign Up and follow the instructions to get set up with a free account before continuing.
  4. When asked whether you want to use a template, click Basic HTML5 Structure.
  5. From the Project Root pane, expand the scripts folder and select index.js to load it into the project editor.
  6. Replace all the code with the following:
import { printMsg } from './module1.js';
import { msg2, msg1 } from './module2.js';
printMsg(msg1 + msg2);    
  1. From the Project Root folder, right-click the scripts folder and select New File to add a new JavaScript file in the scripts folder.
  2. When prompted for the name, enter module1.js.
  3. Enter the following code:
export function printMsg(message) {
  const div = document.createElement('div');
  div.textContent = message;
  document.body.appendChild(div);
}     
  1. From the Project Root folder, right-click the scripts folder and select New File to add a new JavaScript file in the scripts folder.
  2. When prompted for the name, enter module2.js.
  3. Enter the following code:
let msg1 = 'Hello World! ';
let msg2 = 'This message was loaded from a module.';
export { msg1, msg2 };     
  1. From the Project Root folder, select the index.html file to load into the code editor.
  2. Scroll down in the file and look for the script tag that loads the index.js file. Replace that line of code with the following. Notice that all that was really done was to add the type="module" attribute to the script tag.
<script type="module" src="./scripts/index.js"> </script>
  1. Click Save All + Run.
  2. The preview window should display the text, “Hello World! This message was loaded from a module” in the preview window.

CodePen editor showing a new project that was used to load modules and display a message.

Different Ways to Use Modules

In the code we’ve looked at so far, the function and variables exported were imported using the same names. That’s fine. But what if you wanted to rename the functions and variables and use different names? You can do this using an alias. In the last example we used the following code to import the variables from the module2 file. 

import { msg2, msg1 } from './module2.js';
printMsg(msg1 + msg2); 

The concatenated value of those two variables was then passed as a parameter to the printMsg function using the same variable names (msg1 + msg2). But let’s say that you want to use a different variable name for one of those variables. Something like msg3. You can just change the code like this:

import { msg2, msg1 as msg3 } from './module2.js';
printMsg(msg3 + msg2);    

At this point if you try to use the msg1 variable name you get a reference error telling you that msg1 is not defined. So just remember that once you set an alias, always use that same name.

Let’s consider another scenario. Assume now that you just want to import everything from a module and not worry about naming any of the exports. You can do that too. If you use an asterisk, everything is imported as a single object. You can see how this works if you change the code in index.js to be the following:

import { printMsg } from './module1.js';
import * as message from './module2.js';
printMsg(message.msg1 + message.msg2);  

Notice how the newly created object was assigned an alias using the as keyword. Also notice how the object name message is now referenced when accessing the values of the variables. So even though you did not have to worry about specifying the names when exporting, you still need to know what the names are before referencing them as a property of the exported object.

It’s All in the Name

When referring to module exports, we call them named exports. But what do you think is actually being exported? Is it just a reference to the exported variable, function, or class? Or is it the actual variable, function, or class?

Just the name gets exported, and you can see this for yourself. If you export a variable and then try to change the value in the imported module, you get an error. Essentially, it’s read-only. For example, if you change the code in index.js to the following and then save all the changes in CodePen, you just get a blank preview window.

import { printMsg } from './module1.js';
import { msg1, msg2 } from './module2.js';
msg1 = 'Did this variable change?';
printMsg(msg1 + msg2);  

The preview window is blank because the last line of code was never executed and an error was thrown, which you can see for yourself if you go to the console in developer tools. Access Chrome’s developer tools by right-clicking inside the browser window and selecting Inspect.

CodePen editor showing an error in the console when the code is changed to reassign an imported variable.

The thing to remember here is that you are not allowed to reassign the exported value. It can only be changed from inside the module it was exported from.

Tell Me More

  • Modules always execute in strict mode, which means that variables need to be declared.
  • They only get executed once, which is right when they are loaded.
  • Import statements get hoisted, which means that all dependencies will execute right when the module is loaded.

Resources

Understanding ES6 Modules via Their History

ECMAScript 6 modules: the final syntax

<script:> The Script Element

Import statement

Export statement

retargeting