Download as pdf or txt
Download as pdf or txt
You are on page 1of 21

Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

Basics of Modular JavaScript


Christine Rohacz Follow
Feb 7, 2017 · 14 min read

Intended Audience
This article is for those just being introduced to JavaScript. When I was first
introduced to it, I had a lot of questions about what the difference was
between ECMA and JS, transpilers and bundlers, and on webpack itself. I
couldn’t quite wrap my head around all of it. Then I found a course on
PluralSight that explained Modular JavaScript flawlessly. But there are two
problems. One is that Pluralsight is expensive and although I love their
courses, the average student or new hire can’t exactly afford a subscription
quite yet. Two, not a lot of people have time to watch a 2+ hour course
online. So, summarize here are my learnings and my newfound
understanding of the basics in modular JavaScript. I hope it helps someone.

ECMA vs. JavaScript?


ECMAScript is a standard for scripting languages and JavaScript is an
implementation of ECMAScript. The acronym ES refers to ECMAScript.
ECMA stands for European Computer Manufacturer’s Association; however,
you just need to remember that ES and JavaScript are virtually one in the
same except that JavaScript may provide some additional features.

JavaScript began as a client-side scripting language for web applications but

1 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

its earlier version such as ES5 contained many limitations that prohibited
creating classes, importing modules, etc. The first standardized version of
JavaScript was referred to as ES5. The newest version today is referred to as
ES6/ECMAScript 2015/ES2015; this is the very first update to the language
since it was standardized in 2009. ES5 originally didn’t include support for
modules. To understand why this is important, we need to understand why
developers need modules and what they give us.

Why do developers need modules?


JavaScript began as a language for building small scale websites; but today,
websites are becoming web applications and code bases and functionality
are growing to be larger. Developers needed a way to separate functionality
and simultaneously specify dependencies. Languages like C++ and Java
rely on external libraries such as as a math library to compute basic math
equations without having to rewrite them. So libraries enable languages to
not repeat code and delegate functionality and this is similar to what
modules gives JavaScript. Modules help developer’s separate
functionality and organize the codebase. One of the largest reasons for
modules is JavaScript’s global namespace which can become easily
polluted. Functions are the only thing in JavaScript that create a new scope;
thus anything not declared within a function is apart of the global
namespace. Thus every function we declare in JavaScript is available
globally and therefore its name cannot be used again. Often this leads to a
polluted namespace where names and code can be difficult to find and
reuse. But sometimes we don’t want that function to be available
everywhere. In order to make functions in one JavaScript file available to
just a single other JavaScript file, we can use modules. Although there are
many other reasons, the top reasons for modular capabilities are:

2 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

Simplifying dependency management

Code Organization: let us divide up functionality of our application,


provide encapsulation

Offers code reusability

Decoupling (easing pain in refactoring)

Code Extensibility

In sum, our applications would be pretty messy and poorly maintained


without modularity.

. . .

Modules with ES5


All modern browsers support ES5, it is the backbone of the modern web.
The point of this section is to give you familiarity with modules in ES5. The
caveat is, ES5 doesn’t support modules. So, developers have come up with
a lot of workarounds to support modularity and below are some of them.

Vanilla ES5
Sometimes you are constrained to using plain vanilla ES5 JavaScript and
cannot use any third party libraries that support modularity or even ES6. In
this case, there are two common patterns in JS to implement modules but
they have positives and negatives.

Singleton Pattern
The singleton pattern takes advantage of what we called immediately
invoked function expressions, commonly known as an IIFE. JavaScript has

3 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

function level scope so all variables and functions declared within the
function expression are not available in the global scope. The only thing in
the global scope will be the name we choose to give to the function
expression, if we choose to give it one ( we can use an anonymous function
and avoid giving it a name at all). In our case, we will assign a variable
name to a function expression which will be immediately invoked, leaving
the return value of that function to be assigned to the variable we choose.

Lets say we declare a file called scoreboard.js . In here, we create a variable

called scoreboard and assign it to a function definition which returns an


object with our public API. The object returned has a member called
showMessage which is assigned to the printMessage function declaration.
Simiarily, the return object’s updateMessage member is assigned to its
equally named function declaration. Neither showMessage or updateMessage

are available in the global namespace but the variable scoreboard is.

var scoreboard = function() {

var message = 'Welcome to the game!';

function printMessage() {

console.log(message);

function updateMessage(newMessage) {

message = newMessage;

//return an object that represents our new module

return {

4 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

showMessage: printMessage,

updateMessage: updateMessage

}(); //← This is called a immediately invoked function definition,


// or IIFE

To access the scoreboard module in another file, we just simply access the
member variables that we specified in the object returned by the scoreboard
function.

scoreboard.printMessage();

scoreboard.updateMessage(“Let the game begin!”);

As you can see in the above example, it doesn’t matter what I call the
object’s members in my returned object, all that matters is that they are
assigned the value of their respective functions in order to have the correct
implementation. We also have used an immediately invoked function
definition. We want to immediately invoke the function expression assigned
to the scoreboard variable so that the return value is assigned to the
scoreboard variable and can be used without invoking any function later on.

Constructor Pattern
Another pattern that you may see is called the constructor pattern. The
main difference between this pattern and the singleton pattern is that this
function expression is no longer immediately invoked and instead must be
explicitly invoked when you wish to use the variable or module in our case.

5 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

var Scoreboard = function() {

console.log('Creating a new scoreboard...');

var message = 'Welcome to the game!';

function printMessage() {

console.log(message);

return {

printMessage: printMessage

};
/* no longer immediately executing the function -- function
definition is assigned to a variable which must later be
invoked. */

In order to use the scoreboard variable, we invoke it using the ‘new’


keyword and assign the return value of that invoked function to a new
variable.

var myScoreboard = new Scoreboard();

myScoreboard.printMessage();

Key Takeaways

These patterns are extremely useful when you are constricted to using
plain old vanilla ES5

6 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

Adds one value to the global scope per module

No system for dependency management meaning we cannot specify that


the a module called the ‘game’, will depend on the scoreboard module.

. . .

Formats and Loaders


Instead of relying on vanilla JavaScript, third party tools give us some
advantages that ES5 cannot. These tools are commonly referred to as
modules formats and loaders. A module format is a specified syntax that
requires a loader to interpret the module syntax. A loader is a third party
tool that can help interpret specific module formats. Most module formats
are not native to JavaScript language and therefore cannot be used without
a module loader. However, ES2015/ES6 includes built in support for
modules and that syntax is considered to be a native module format which
can be used without a loader. For now, I will be focusing on non-native
module formats and loaders that can be used to interpret them.

The two most popular modular formats are CommonJS and AMD. There
are different reasons for choosing one or the other but we won’t get into
that here. Another module format you might see often is called UMD. The
two most popular loaders are RequireJS, which is most commonly used to
load AMD modules, and SystemJS which supports many different module
formats. We will now look at two different combinations of the most
popular module formats and loaders, but keep in mind, there are many
other combinations to be made.

In quick summary:

7 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

AMD Format — Primarily used for JavaScript modules that need to be


included in a browser as opposed to server side JavaScript

CommonJS Format — Primarily used in server side implementations as


part of NodeJS applications

AMD & RequireJS


The AMD syntax provides us with a new function named define. The define
function takes in two parameters, an array of dependencies as the first, and
the function definition second. Define is not a function defined by
JavaScript, we are actually calling a function provided by our AMD syntax
that can then be interpreted by the loader.

Looking at our scoreboard example, we have no dependencies that we


would specify in the first parameter but we would declare the function body
in a similar way to before:

8 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

define([], function() {

console.log('Creating a new scoreboard module');

function addResult(newResult) { ... }

function updateScoreboard() { ... }

return {

addResult: addResult,

updateScoreboard: updateScoreboard

});

If we wanted to say that our game.js module depends on the scoreboard


module and player module, then we could do so like this:

define([‘./player’, ‘./scoreboard’], function(player, scoreboard) {



})

Where we pass in the file path to dependencies as an array into the first
parameter (leaving off the .js extension), and the function body is still the
second parameter taking in our specified dependencies as parameters.

In order for our browsers to be able to interpret this sort of code, we would
use a loader like RequireJS. You can go through the following steps to install
RequireJS

9 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

1. Install RequireJS as a dev dependency with npm: npm install --save

bower-requirejs

2. Include RequireJS library in your html within a script tag like so

<script data-main="js/app" src="node_modules/requirejs/require.js">


</script>

where data-main specifies the entry point for your application.

CommonJS & SystemJS


With our commonJS format, modules look quite a bit different. We declare
functions and in order to make those functions available within a module,
we add these functions as members of the module.exports object.

console.log('Creating a new scoreboard');

var results = [];

function addResult(newResult) {
results.push(newResult);
}

function updateScoreboard() {
...
}

//a little bit different way of doing it than the player module

module.exports = {

addResult: addResult,

updateScoreboard: updateScoreboard

10 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

};

And to include our new scoreboard module in another file, we would use
the require function defined by the CommonJS syntax. This function takes
in a javascript file that another file may depend on. It will import the
module and assign it to the variable scoreboard.

var scoreboard = require('./scoreboard.js');

To later use the functions in scoreboard.js, we would call

scoreboard.addResult(result);

SystemJS needs to be configured with addition javascript code to tell it


what JavaScript format it is loading and where to start loading.

We would use SystemJS in a similar way to RequireJS.

1. Install SystemJS with npm as a dev dependency npm install --save

systemjs

2. Import the SystemJS library into our html with a script tag. Then,
configure SystemJS in either in a separate JavaScript file or in our html.
We can include it in our html in between script tags like so:

<script src = "node_modules/systemjs/dist/system.js"></script>

11 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

<script>
// configure systemJS

System.config({

meta: {
format: 'cjs' //cjs refers to CommonJS format
}

});

System.import('js/app.js'); //import systemJS

</script>

System.import tells the loader where to begin loading JS files. Our import
statement specifies that the root module is app.js which requires the use of
all our other modules but is not a dependency itself. format: 'cjs' tells the
config that we are loading the commonJS format.

3. You’re all good to go!

Key Takeaways

Module formats and loaders give you the ability to manage your
dependencies. This means you can specify what files depend on what
modules before hand.

Provides a common format for modules

. . .

Modules in ES6

12 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

What’s new in ECMA2015/ES6


ES6 includes a lot of new features to extend capabilities and remove
limitations of ES5. ES6 now provides class syntax which makes OO pattern
easier to implement. Let and const are new keywords that replace var. Let
can be reassigned and const can only be assigned a value once. And finally,
ES6 added support for modules. Although ES6 has some cool new
features, a lot of these features are not compatible with most modern day
web browsers. In the meantime, developers have come up with ways to
include the features they want; tools named “transpilers” are being created
to translate new versions of ES6 code into older versions such as ES5 so that
browser can interpret this new module syntax. Most modern web
applications are using these transpilers so that their code will be compatible
with ES6 when it is released but also compatible with current web browsers
in the meantime. First I will go over what a module in ES6 would look like
and then address what tools we might need to use this new syntax.

. . .

Modules in ES6
Modules in ES6 are very simple to use. Like other usage of modules, ES6
provides a way to export modules so that they can be specified as
dependencies to other modules.

Exporting Modules
There is more than one way to export modules in ES6.

1. Include the keyword export in your function definition.

export function setName(name) { ... }

13 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

export function getName() { ... }

export function logPlayer() { ... }

2. Include an export object with the properties you want to be included in


the module.

function addResult() { ... }

function updateScoreboard() { ... }

export { addResult, updateScoreboard };

Importing Modules
There are also different syntaxes you can use to import modules in
JavaScript once they have been exported. Below are a few examples of how
we would import the modules exported above.

1. Import an entire module as scoreboard

import * as scoreboard from ‘./scoreboard.js’;

This would be equivalent to saying, “import all the properties we exported


from scoreboard.js and call the module scoreboard”. Then we can simply
call the properties of scoreboard like so:

scoreboard.updateScoreboard();

14 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

2. Import specific elements of a module

import { getName as getPlayerName, logPlayer } from ‘./player.js’;

We can also rename the properties we import from modules by using the
keyword. And we can specify which properties to import instead of
importing everything contained within the player module. So the above
import statement, would give us a function called getPlayerName which
references the function getName in player.js and a function called logPlayer
which references the logPlayer function in player.js. Since we have not
specified a name for our module, we can simply call the functions like this
from the game module:

function printGame() {

logPlayer();

console.log(getPlayerName() + “ is now playing”);

. . .

Transpilers
With the advent of modules in ES2015, we now don’t need to use any third
party libraries to create modular JavaScript code. Unfortunately, modern
day browsers don’t support ES2015 code quite yet, which means our user’s
browsers cannot render the code we write in the newest version of JS. The
solution to this has been transpilers. This word may sound similar to a

15 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

compiler. Whereas a compiler transforms source code into a form of


runnable code such as binary code, a transpiler takes source code in one
language and transforms it to its equivalent source code in another
language. What a transpiler does, is take ES6 code and translates it into ES5
code that is supported by modern browsers. This way we can write code in
the newest version of JavaScript that will be supported in the future and
can still be read by today’s applications. The most popular well known
transpiler today is babel. On babel’s site, you can even test out how it would
transpile your ES6 code into ES5 with the try it out feature. A sequence of
steps to using babel might look something like this:

1. Install with npm ` npm install --save-dev babel-cli

2. Install additional presets to apply certain transformations such as babel-


preset-es2015 like so ` npm install --save-dev babel-preset-es2015

3. To run babel, navigate to the directory in node_modules/.bin/babel

directory where babel was installed and run the command js — —

preset s es2015 — — out-dir build The out-dir will specify where to put
our transpiled JavaScript. Babel should tell you the destination of where
the transpiled code went.

Bundlers
A bundle by definition is several objects bound together, thereby making a
bundler a type of machine that does that binding. In JavaScript, a bundler
does just that. It takes a group of JavaScript files together and binds them
into a single JavaScript file. When we bind multiple JS files together, then
there are less dependencies to load at startup time. Instead of loading 12
different javascript files for one HTML page, we can instead bundle them
together and load just a single one when we load the page. But beware of

16 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

the pitfall of bundlers:

When we bundle too many files together at once, loading that one bundled
file can take so long it will interrupt the user’s experience instead of making
it smoother.

A common module bundler today is Browserify and to install and use


Browersify, you would go through the following steps:

1. Write JS code in any modular format

2. Install Browserify with npm install --save-dev browserify

3. Make a directory which you want the bundled files to be held in such as
build or bundledJS

4. Browserify was installed at node_modules/.bin/browserify directory so


we can run it from there by passing in the root module js/app.js and
use the --outfile followed by your destination directory to specify
where to put your bundled files and what to call it. Put it all together and
you would run something like this js/app.js --outfile build/bundle.js

Overall, module bundlers:

Combine modules into fewer files

Decreases the number of dependencies to load which may decrease


startup time to load the application

Webpack
Sometimes using these old Javascript formats and having a large amount of
JavaScript code can get overwhelming. Every time you bundle your JS, it

17 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

generates another file you need to include in your HTML and on top of
transpiling them with babel, things can get confusing. So in order to solve
this problem, Webpack has evolved to do everything at once. Webpack is a
tool that does bundling, transpiling and a lot more by running a single
command.

Figure 1. IMAGE REF: http://webpack.github.io/

What Figure 1 shows, is how webpack will take modules with dependencies,
even css files and images, and bundle them into static assets we can include
in our HTML code. So how exactly does webpack do this?

The Con�ig File


The webpack config files specifies everything you need to run webpack such
as the following:

An entry point for the application

An output file and location

18 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

Uses a regex expression to choose what files to run through the loader

Excludes files to not run through the loader

What type of loader to use

What presets to pass to the loader

Here is an example of one:

module.exports = {

entry: './js/app.js', //an entry point for the application

output: {

path: './build', //location for output file

filename: 'bundle.js', //name of output file

},

module: {

loaders: [{

test: /\.js$/, //run through files matching this regex

exclude: /node_modules/, //exclude these files

Loader:'babel-loader', //use a babel loader

query: {

presets: ['es2015'] //use this babel preset

}]

19 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

};

Ta da! It is that simple. With this config file, you can simply run webpack
from its location (for me that would be in the node_modules directory):

./node_modules/.bin/webpack

Then an output file is generated in the build directory, called bundle.js and
I can include this file with one line in my HTML like so:

<script src = “./build/bundle.js”></script>

Of course, running the webpack command can be automated and doesn’t


have to be done manually.

Key Takeaways

Modules are possible in plain vanilla javascript if you are constrained

Modules in earlier version of JavaScript are implemented using formats


and loaders

More commonly though, modules are being implemented in ES2015

Browsers don’t yet support modules in ES2015

Transpilers can take different module formats in code not supported by


browsers and convert it into a version of JavaScript supported by
modern day browsers

20 of 21 3/13/20, 4:56 AM
Basics of Modular JavaScript - Christine Rohacz... https://medium.com/@crohacz_86666/basics-of...

Webpack can transpile and bundle JavaScript files for your, supporting
dependency management and module clusters

References
The above code examples and most of the information were taken from a
PluralSight course called ‘JavaScript Modules’. I do not claim to have come
up this the code example on my own. This course gave me a lot of the
information that I needed to learn all about modules in JavaScript. It is a
highly recommended course, a long with many others PluralSight has to
offer.

JavaScript ES6 Learning To Code Code Pluralsight

Discover Medium Make Medium yours Become a member


Welcome to a place where Follow all the topics you care Get unlimited access to the
words matter. On Medium, about, and we’ll deliver the best stories on Medium —
smart voices and original best stories for you to your and support writers while
ideas take center stage - with homepage and inbox. Explore you’re at it. Just $5/month.
no ads in sight. Watch Upgrade

About Help Legal

21 of 21 3/13/20, 4:56 AM

You might also like