Skip to main content

JavaScript Module Syntax

Introduction

JavaScript modules are a way to organize code into separate files, allowing developers to build more maintainable applications by breaking down code into smaller, reusable pieces. In this tutorial, we'll explore the various ways to import and export code between modules using modern JavaScript syntax.

Before ES6 (ECMAScript 2015), JavaScript didn't have a native module system, relying on libraries like CommonJS or AMD. Today, modern JavaScript provides built-in module functionality with a clean, standardized syntax.

Basic Export and Import Syntax

Named Exports

Named exports allow you to export multiple values from a single module. Each export has a name, and you need to refer to that exact name when importing.

Example:

javascript
// math.js - exporting file
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export function multiply(a, b) {
return a * b;
}
javascript
// app.js - importing file
import { PI, add, multiply } from './math.js';

console.log(PI); // 3.14159
console.log(add(2, 3)); // 5
console.log(multiply(2, 3)); // 6

You can also export multiple items at once using a single export statement:

javascript
// math.js - alternative approach
const PI = 3.14159;
function add(a, b) {
return a + b;
}
function multiply(a, b) {
return a * b;
}

export { PI, add, multiply };

Default Exports

Default exports are used when a module exports only one value, or when there is a main functionality that the module provides.

Example:

javascript
// user.js
export default class User {
constructor(name, age) {
this.name = name;
this.age = age;
}

getProfile() {
return `${this.name}, ${this.age} years old`;
}
}
javascript
// app.js
import User from './user.js';

const user = new User('John', 30);
console.log(user.getProfile()); // John, 30 years old

When importing a default export, you can use any name you want:

javascript
import Person from './user.js';  // Using a different name

const person = new Person('John', 30);
console.log(person.getProfile()); // John, 30 years old

Advanced Import and Export Patterns

Importing Both Default and Named Exports

You can import both default and named exports from the same module:

javascript
// userUtils.js
export default class User {
constructor(name) {
this.name = name;
}
}

export function createUser(name) {
return new User(name);
}

export const MAX_USERS = 100;
javascript
// app.js
import User, { createUser, MAX_USERS } from './userUtils.js';

const user = createUser('Alice');
console.log(user.name); // Alice
console.log(MAX_USERS); // 100

Renaming Imports and Exports

Sometimes you may want to rename exports or imports to avoid naming conflicts:

Renaming exports:

javascript
// mathUtils.js
function add(a, b) {
return a + b;
}

function subtract(a, b) {
return a - b;
}

export {
add as sum,
subtract as difference
};

Renaming imports:

javascript
// app.js
import { sum as addition, difference as subtraction } from './mathUtils.js';

console.log(addition(5, 3)); // 8
console.log(subtraction(5, 3)); // 2

Importing All Exports

You can import all exports from a module as properties of a single object:

javascript
// mathUtils.js
export function add(a, b) {
return a + b;
}

export function subtract(a, b) {
return a - b;
}

export const PI = 3.14159;
javascript
// app.js
import * as math from './mathUtils.js';

console.log(math.add(5, 3)); // 8
console.log(math.subtract(5, 3)); // 2
console.log(math.PI); // 3.14159

Re-exporting Modules

You can re-export imported modules to create aggregated modules:

javascript
// mathOperations.js
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
javascript
// advancedMath.js
export function multiply(a, b) { return a * b; }
export function divide(a, b) { return a / b; }
javascript
// index.js - re-exporting modules
export { add, subtract } from './mathOperations.js';
export { multiply, divide } from './advancedMath.js';
export const PI = 3.14159; // adding our own export
javascript
// app.js
import { add, multiply, PI } from './index.js';

console.log(add(2, 3)); // 5
console.log(multiply(2, 3)); // 6
console.log(PI); // 3.14159

Dynamic Imports

Starting with ES2020, you can dynamically import modules using the import() function, which returns a Promise:

javascript
// app.js
const loadModule = async () => {
try {
// Module is loaded dynamically only when needed
const mathModule = await import('./mathUtils.js');
console.log(mathModule.add(5, 3)); // 8
} catch (error) {
console.error('Error loading module:', error);
}
};

// The module will be loaded when this function is called
loadModule();

This is particularly useful for:

  • Code splitting
  • Loading modules conditionally
  • Reducing initial load time

Practical Real-World Example: Building a Dashboard Component

Let's see how modules can be used in a real-world application to organize code for a simple dashboard:

javascript
// config.js - Configuration settings
export const API_URL = 'https://api.example.com/data';
export const REFRESH_INTERVAL = 60000; // 1 minute
javascript
// dataService.js - Data fetching service
import { API_URL } from './config.js';

export async function fetchUserData() {
const response = await fetch(`${API_URL}/users`);
return response.json();
}

export async function fetchAnalytics() {
const response = await fetch(`${API_URL}/analytics`);
return response.json();
}
javascript
// userPanel.js - User information panel
import { fetchUserData } from './dataService.js';

export default class UserPanel {
constructor(containerId) {
this.container = document.getElementById(containerId);
}

async render() {
const userData = await fetchUserData();
this.container.innerHTML = `
<div class="panel">
<h2>Users</h2>
<p>Total users: ${userData.total}</p>
<p>Active now: ${userData.active}</p>
</div>
`;
}
}
javascript
// dashboard.js - Main dashboard component
import { REFRESH_INTERVAL } from './config.js';
import { fetchAnalytics } from './dataService.js';
import UserPanel from './userPanel.js';

export default class Dashboard {
constructor() {
this.userPanel = new UserPanel('user-container');
}

async initialize() {
// Render user panel
await this.userPanel.render();

// Render analytics
const analyticsData = await fetchAnalytics();
document.getElementById('analytics-container').innerHTML = `
<div class="panel">
<h2>Analytics</h2>
<p>Page views: ${analyticsData.pageViews}</p>
<p>Conversion rate: ${analyticsData.conversionRate}%</p>
</div>
`;

// Set up auto-refresh
setInterval(async () => {
await this.userPanel.render();
// Update other components...
}, REFRESH_INTERVAL);
}
}
javascript
// app.js - Application entry point
import Dashboard from './dashboard.js';

document.addEventListener('DOMContentLoaded', async () => {
const dashboard = new Dashboard();
await dashboard.initialize();
console.log('Dashboard initialized!');
});

This example demonstrates how modules help organize a complex application:

  • Configuration is separated in config.js
  • Data fetching logic is encapsulated in dataService.js
  • UI components are in their own modules
  • Each file has a single responsibility

Summary

JavaScript module syntax provides powerful tools for organizing code, with several key features:

  • Named exports allow exporting multiple values from a module
  • Default exports are useful for modules with a primary function
  • Imports can be renamed to avoid naming conflicts
  • Dynamic imports enable loading modules on demand
  • Modules can be re-exported to aggregate functionality

Using modules effectively leads to more maintainable, reusable code that's easier to test and debug.

Additional Resources

Exercises

  1. Create a module that exports utility functions for string manipulation (e.g., capitalize, reverse, countWords).
  2. Create a module with a default export for a Calculator class and named exports for basic math operations.
  3. Build a simple app with three modules: a data service module, a UI rendering module, and a main app module that uses both.
  4. Refactor existing code to use dynamic imports to load heavy functionality only when needed.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)