Module support in JavaScript has gone through major changes over the years. This article covers how to create a JavaScript module that works in both NodeJS and a modern browser.

If you need to work with older code, I will provide links at the end of this article for resources.

This article was tested using a Mac. You may have to adapt some of the command-line instructions for working with Windows.

Step 1. Install NodeJS

To test in NodeJS via the command line you will need to make sure that NodeJS and npm or yarn is installed.

For information on how to install NodeJS and npm see this link:

Step 2. Install Chrome

The code in this article should work with most modern browsers. I prefer to test everything in Chrome.

For information on how to install the latest Chrome browser see this link:

Step 3. Install an IDE

You can just use a text editor. But if you don't have an IDE (Integrated Development Environment) - in other words a code editor - I recommend Visual Code (it's free!):

For information on how to install Visual Code see this link:

Step 4. Create a Simple Module

The simplest type of module that can be created is one that by default exports an empty object. This exercise shows how to export an object from a module, assign it to a variable, and add a property to it.

To setup your project, open up a terminal window and type following at the command line:

$ mkdir -p ~/projects
$ cd ~/projects
$ mkdir js-module-01
$ cd js-module-01
$ touch my-mod.js index.js

The touch command created empty JavaScript files in the new folder.

Open up my-mod.js in a text or JavaScript editor, add the code below, then save it.

Open up index.js in a text or JavaScript editor, add the code below, then save it.

The module is imported, which will return to obj an empty object. Then a name property is tacked on to it. This differs from other languages where adding properties after an object is created would not be allowed.

Step 5. Test the project with NodeJS

Open up a command line, change to the folder where the file is and run the following:

$ node index.js

You should see an error like this:

SyntaxError: Cannot use import statement outside a module

For this code to work you need a way to tell NodeJS that this is a module. To do that using npm do the following in the root of your project:

$ npm init -y

This creates a default package.json file in the root of your project.

The -y flag skips over a series of questions and just enters default values that you can edit later. But you still need to add a line to tell NodeJS that this is a module.

  • Edit package.json and add this line after the description and save it:
"type": "module",

Your package.json file should now look like this:

Try running the code again:

$ node index.js

You should now see output like this:

My name is Droid

Step 6. Test the project in the Chrome browser

To test the project in the Chrome browser you will need to add a new HTML file.

In the root of your project create a file called index.html (either via the touch command or your code editor).

For example on a Mac:

$ touch index.html
  • Paste the following into index.html and save the file:

The type="module" attribute is required to tell the browser that the file is a module. This is similar to how you had to specify the type in package.json.

You can't just open the file in the browser and expect it to work. If you try it and look at the browser JavaScript console you will get errors similar to this:

Access to script at 'file:///Users/mitch/projects/js-module-01/index.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

Followed by something like this:

Failed to load resource: net::ERR_FAILED

You have to run the code through a local Web server.

  • On a Mac you can serve the files from the current folder using this command:
python -m SimpleHTTPServer $PORT || 8000
  • Leave that command running
  • Open up the Chrome browser and browse to:
http://localhost:8000/

The browser is blank because the action is happening behind the scenes in the console.

  • Right-click in the browser window
  • Select Inspect
  • Click console

You should see a message like this:

My name is Droid

You will also see a benign error like this:

Failed to load resource: the server responded with a status of 404 (File not found) 8000/favicon.ico:1 

That's just the browser warning you that there is no icon file to draw a logo next to the tab title. It can be ignored.

If you hit Enter again in the address bar it goes away. It will return when you reload and refresh the browser.

Step 7. Export a function

Most of the time you will be exporting more than an empty object. For this example I will show you how to export a factory function - a function that returns a new object.

  • Add this function above the existing export in my-mod.js and save the file:
  • Modify the import command in index.js so that it looks like this:

Run the file again and you should see the same result as before (in the browser refresh).

  • Add this code to the bottom of index.js:

If you rerun node index.js or refresh the browser (Command-Shift-R) you should see output like this:

My name is Droid
My name is Robbie
My name is B9

Conclusion

In this article I showed you how to create, export and import a JavaScript module using the latest NodeJS and browser support.

Below I will give you references to modern resources as well as info on working with older technology. The first reference is to a book I wrote a few years ago before the current way of doing things became standard.

Instead of updating the book I decided to leave it in place for people working with legacy code. Instead of a new book I'm just going to post updated content here online.

Source Code

References

  • How to Design and Create Node.js Modules - if you need to work with legacy code, this is my book that covers the old way of doing things
  • JavaScript export - [1]
  • JavaScript import - [2]
  • JavaScript closures - [3]
  • microbundle npm package - [4]