Home

Implementing Modules in Node

What are Modules?

Modules are reusable pieces of code in a file that can be exported and then imported for use in another file.
A modular program is one whose components can be separated, used individually, and recombined to create a complex system.

module.exports

To create a module, you simply have to create a new file where the functions can be declared.
Then, to make these functions available to other files, add them as properties to the built-in module.exports object. For Example...

* Inside a file called - converters.js */
function celsiusToFahrenheit(celsius) {
   return celsius * (9/5) + 32;
}

module.exports.celsiusToFahrenheit = celsiusToFahrenheit;

module.exports.fahrenheitToCelsius = function(fahrenheit) {
 return (fahrenheit - 32) * (5/9);
};


The module.exports... command will add the methods/functions to the module.exports object, which can then be used by other files (modules).

The code snippet on the left demonstrates two ways of exporting functions from a module. For Example...

At the top of the new file, converters.js, the function celsiusToFahrenheit() is declared.

After that function, on the next line of code, the first approach for exporting a function from a module is shown.
In this case, the already-defined function celsiusToFahrenheit() is assigned to module.exports.celsiusToFahrenheit.

Below that, an alternative approach for exporting a function from a module is shown.
In this second case, a new function expression is declared and assigned to module.exports.fahrenheitToCelsius.
This new method is designed to convert Fahrenheit values back to Celsius.

Both approaches successfully store a function within the module.exports object.

module.exports is an object that is built-in to the Node.js runtime environment.

Other files can now import this object, and make use of these two functions, with another feature that is built-in to the Node.js runtime environment: the require() function.

Top

The require() function

The require() function accepts a string as an argument.
That string provides the file path to the module you would like to import and is used when creating an object for it in your code. Eg...
const converters = require('./converters.js');

For Example, in water-limits.js we need to import and use the functions from converters.js, so...we need to grab them from the module.exports object within converters.js:

/* water-limits.js */
const converters = require('./converters.js');

const freezingPointC = 0;
const boilingPointC = 100;

const freezingPointF = converters.celsiusToFahrenheit(freezingPointC);
const boilingPointF = converters.celsiusToFahrenheit(boilingPointC);

console.log(`The freezing point of water in Fahrenheit is ${freezingPointF}`);
console.log(`The boiling point of water in Fahrenheit is ${boilingPointF}`);

In this case, ./ is a relative path indicating that converters.js is stored in the same folder as water-limits.js.
When you use require(), the entire module.exports object is returned and stored in the variable converters.

This means that both the .celsiusToFahrenheit() and .fahrenheitToCelsius() methods can be used in this program!

So, for Node Modules, the EXPORTING code looks like...

module.exports.celsiusToFahrenheit = celsiusToFahrenheit;

OR

module.exports.fahrenheitToCelsius = function(fahrenheit) {
 return (fahrenheit - 32) * (5/9);
};


And the IMPORTING code looks like...

const { celsiusToFahrenheit } = require('./converters.js'); OR if there were more than one function to use you would say... const { celsiusToFahrenheit, secondFunction, ...etc... } = require('./converters.js');

OR you could even create them individually like this...
const allModules = require('./converters.js');

const celsiusToFahrenheit = allModules.celsiusToFahrenheit;
const secondFunction = allModules.secondFunction;
const myThirdFunction = allModules.thirdFunction;

Top

Implementations of Modules in JavaScript: Node.js vs ES6

In JavaScript, there are two runtime environments and each has a preferred module implementation:-

The Node runtime environment and the module.exports and require() syntax.
The browser’s runtime environment and the ES6 import/export syntax.

Above is the NODE RUNTIME environment.

Starting below is the (ES6) runtime browser environment, eg Chrome Browser.

Top

Runtime environment and the ES6 import/export syntax.

For this example I will use the file dom-functions.js which holds a couple of commands... then exports the commands, enabling them to be imported to another .js file as and when they are needed.

I will also use the file secret-messages.js which imports from dom-functions.js and uses them inside its own routines.

dom-functions.js
const toggleHiddenElement = (domElement) => {
   if (domElement.style.display === 'none') {
      domElement.style.display = 'block';
   } else {
      domElement.style.display = 'none';
   }
}

const changeToFunkyColor = (domElement) => {
   const r = Math.random() * 255;
   const g = Math.random() * 255;
   const b = Math.random() * 255;

   domElement.style.background = `rgb(${r}, ${g}, ${b})`;
}

export { toggleHiddenElement, changeToFunkyColor };

secret-messages.js
import { toggleHiddenElement, changeToFunkyColor } from './dom-functions.js';

const buttonElement = document.getElementById('secret-button');
const pElement = document.getElementById('secret-p');

buttonElement.addEventListener('click', () => {
   toggleHiddenElement(pElement);
   changeToFunkyColor(buttonElement);
});

Note...
If you need to import a method/function and change its name (maybe you have 2 different files that have identically named methods) then you can change the name(s) by...

import {validate as validateUsername} from "./username-validation.js/";
import {validate as validatePassword} from "./password-validation.js/";


And apparently you can import everything from a file by...
import * as MyClasses from "./MyClass.js"
// use MyClasses.MyClass, MyClasses.MyOtherClass, MyClasses.More



And to demonstrate this I will add a BUTTON which will toggle a <p id="secret-p"> element, see below...

NOTE...
In order to include the secret-messages.js module file in to your .html file you will need to include the script that calls it...
<script type="module" src="./Scripts/secret-messages.js"></script>




NOTE...
This does not work when running on a local machine but when running from a server the clicking of the button seems to work.
So it works when running via github... so you can try clicking HERE to run it


Top

Comments

Using default when exporting/importing.

ES6 provides two ways to export a module from a file: named export and default export.

Named Export: (export)

With named exports, you can have multiple named exports per file.
Then import the specific exports you want surrounded in braces - {}.
The name of imported module has to be the same as the name of the exported module.

// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}



// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";

// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";

// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";

//Import all the named exports onto an object:
import * as MainComponents from "./MyComponent";
// use MainComponents.MyComponent and MainComponents.MyComponent2 here

Default Export: (export default)

You can have ONLY ONE default export per file.
When we import we have to specify a name and import like:

// export
const MyComponent = () => {}
export default MyComponent;

// import
import MyDefaultComponent from "./MyDefaultExport.js";
//The naming of import is completely independent in default export and we can use any name we like.


So, for EXPORTING, we use braces {} when exporting one or more named methods, eg...
export {method1, method2, method3, ...};

And/Or we could export it at the time of creating the method...
export const MyComponent = (domElement) => {return ...};

and do not use braces for the default export...
export default MyDefaultMethod;


And, for IMPORTING, we use braces {} with named imports, eg...
import {method1, method2, ...} from "./MyModules.js"

and do not use braces for the default import...
import MyDefaultMethodName from "./MyModules.js"
(Note... on default imports we need to name the default method and we can name it anything we like, it is completely independent from the .js file)

You could read the MDN Web Document on JavaScript Modules HERE if you like.

And you could read the Codecademy Document on getting user input in Node.js HERE if you like.

Top