Modules in your JavaScript projects
The thing with frontend frameworks and libraries is that you’ve got a scaffold to work against. There are set rules that you have to follow to make things work.
However, the front end by itself isn’t that useful. It might look good, but functionality-wise, it’s an isolated island. While there are APIs to connect to, sometimes, you just need to create your own backend.
In the world of node.js and backend API creation, it’s a pretty free world out there. Alternatively, you might be dreaming of a feature but don’t quite know how to implement it in a neatly packaged way. Understanding the basics of JavaScript is your path towards survival — with modules being a technic to help maintain your long term sanity.
But what is a module? How do you use and create one? These are some of the questions I’ll be answering here today.
What is a JavaScript module?
A module is more than just a buzzword. In JavaScript, it’s a piece of self-contained exportable code. To be modular means to be interchangeable. The entire code for that particular section of your application can be uplifted, moved and reused as needed.
If you’re coming from a frontend perspective, you would have already encountered modules before. It usually looks something like this:
import {anotherController} from './controllerThing.js';
export function someClassControllerThing(){}
So we know what a module sort of looks like — but how does it benefit the way you code?
When it comes to a JavaScript project that doesn’t have a framework to guide its structural integrity, you’re pretty much free to construct your app however you want.
You could, in theory, have it has one big file with global functions that have no boundaries attached to them. We’ve all been there at some point.
Originally, JavaScript code was just that — one big and long file that you had to manually trace through to figure out what was going on. Over time, as scripts became more complex in size and logic, the community decided that enough was enough and started to create ways to arrange code.
Modularity gives way to future maintainability. How? By keeping everything neatly packaged and contained, with clear domains of separation between codes.
The ability to create modules as we know it did not actually appear in JavaScript until around 2015. While the concept has been around in other languages, it wasn’t properly native until five years ago.
A collection of modules is called a library. A collection of coordinated libraries with an enforced rule for usage and implementation is called a framework. There is a little bit more to frameworks than just this, but it is beyond the intended scope for this piece.
How do you use a JavaScript module?
Using a JavaScript module is fairly simple. The thing with modules is that the creation and usage process is straightforward.
To create a module, you export it. To use a module, you import it.
By design, a module is just one file with a singular script with a specific task attached to it. Importing a module gives access to the functionality coded inside the exported module.
When it comes to JavaScript modules, it can be a class or a collection/library of functions. These modules can have different functionality and purpose in the overall app such as a factory or service class.
The point of a module is that the code inside is neatly contained, and if required, have their own set of dependencies imported in.
In a way, this can lead your application to have a web-like effect, where modules are interconnected in a way that requires them to be used together as a package.
However, it’s good to note that modules are only evaluated the first time they’re imported. This means that if the module is imported in multiple places, it is only executed once.
Things to take note of when using and creating modules —
- export only what you want accessible from the outside. This means you can have other functions and classes in the same export file, except they won’t be accessible unless it’s wrapped inside the exported function or class.
- module scripts are always deferred and will wait until the HTML document is fully ready. It doesn’t matter what size the module scripts are, it will always wait for the HTML to finish loading first
- order of scripts stills matter and if you’re coding without a framework, the order will need to be maintained in order to execute correctly.
- “bare” modules are modules without a relative or absolute URL. So you can’t write something like this:
import {randomImport} from 'randomImport';
You need to give it a proper path like this:
import {randomImport} from './randomImport';
Final thoughts
The thing with modules is that it’s an organizational and code architectural tool as much as it is a sanity keeping feature for developers — especially in spaces where there is no formalized structure.
While most frameworks and libraries already have modules baked into them, for certain projects, it’s still not a second nature thing.
When you encounter legacy projects that lacks modularity, abstracting out the code into workable modules can help with the initial scrubbing of the code. Sometimes, dirty code was clean when it was created — but time did not age it well.
Technical debt can be module related — but that’s more to do with the module’s scope and size, rather than the code not being an actual module. What a module does is put a fence around the boundary line of where a particular piece of code starts and ends. It doesn’t really have any rules around what goes inside and how things are done.
Despite this, modules are still currently one of the quickest big wins you can do for legacy code that needs to be refactored — if it’s not already done up by the previous developers.