JavaScript modules

In JavaScript, the word module has changed over the years. A module used to be any piece of code that was distinct and self-contained. A few years ago, you might have expressed several modules within the same file like so:

// main.js

// The Dropdown Module
var dropdown = /* ... definition ... */;

// The Data Fetcher Module
var dataFetcher = /* ... definition ...*/;

Nowadays, however, the word module tends to refer to Modules (capital M) as prescribed by the ECMAScript specification. These Modules are distinct files imported and exported across a code base via import and export statements. Using such Modules, we might have a DropdownComponent.js file that looks like this:

// DropdownComponent.js
class DropdownComponent {}
export default DropdownComponent;

As you can see, it uses the export statement to export its class. If we wish to use this class as a dependency, we would import it like so:

// app.js
import DropdownComponent from './DropdownComponent.js';
ECMAScript Modules are slowly gaining more support across various environments. To make use of them within the browser, you can provide an entry script tag with a type of module, that is, <script type="module" />. Within Node.js, at the time of writing, ES Modules are still an experimental feature, so you can either rely on the old style of importing (const thing = require('./thing')) or you can enable experimental modules by using the --experimental-modules flag and using the .mjs extension on all of your JavaScript files.

Both the import and export statements permit a variety of syntaxes. These allow you to define the names of what you're exporting or importing. In a scenario where a Module is only exporting one item, it is conventional to use export default [item] as we have done in DropdownComponent.js. This ensures that any dependents of the Module can import it and name it as they wish, as shown in this example:

import MyLocallyDifferentNameForDropdown from './DropdownComponent.js';

In contrast to this, you can specifically name your exports by declaring them within curly braces and using the as keyword:

export { DropdownComponent as TheDropdown };

This will mean that any importers will need to specifically specify the name of TheDropdown, like so:

import { TheDropdown } from './DropdownComponent.js'; 

Alternatively, you can export named items by having specific declarations inline with your export statements, such as var, const, let, function declarations, or class definitions:

// things.js
export let x = 1;
export const y = 2;
export var z = 3;
export function myFunction() {}
export class MyClass {}

On the importing side, such named exports can be imported by, again, using curly braces:

import { x, y, z, myFunction, MyClass } from './things.js'; 

When importing, you can also optionally designate the local name of that import with the as keyword to have its local name be different to its exported named (this is especially useful in cases of naming conflicts):

import { MyClass as TheClass } from './things.js';
TheClass; // => The class
MyClass; // ! ReferenceError

It's conventional to aggregate exports in areas of your code that provide several related abstractions. For example, if you have composed a small Component library, where each Component exports itself as default, then you could have index.js that exposes all of the Components together:

// components/index.js
export {default as DropdownComponent} from './DropdownComponent.js';
export {default as AccordianComponent} from './AccordianComponent.js';
export {default as NavigationComponent} from './NavigationComponent.js';
In Node.js, an index.js/index.mjs file is imported by default if you try to import an entire directory. That is, if you import './components/', it would first look for the index file and, if available, would import it. In the browser, no such convention currently exists. All imports must be fully qualified filenames.

We can, very conveniently, now import our entire set of Components by using the asterisk with our import statement:

// app.js
import * from 'components/index.js';

// Make use of the imported components:
new DropdownComponent();
new AccordianComponent();
new NavigationComponent();

There are some additional nuances and complexities around modules in JavaScript, especially when considering the legacies of Node.js, that we, unfortunately, don't have time to go into, but what we've covered so far should give you a good enough coverage of the topic to be productive and nicely paves the way for us to explore the topic of modular design patterns.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.185.147