Lesson 13: Modules and Imports

What You'll Learn

  • What modules are and why they matter
  • How to export code from files
  • How to import code into files
  • Named vs default exports
  • Organizing code into modules
  • CommonJS vs ES Modules

Why This Matters

As programs grow, keeping all code in one file becomes unmaintainable. Modules let you split code into logical pieces, making it easier to organize, reuse, and maintain your codebase.


Part 1: What are Modules?

A module is a file that exports code (functions, classes, variables) that other files can import and use.

Benefits:
  • Organization: Related code stays together
  • Reusability: Use same code in multiple places
  • Maintainability: Easier to find and fix bugs
  • Encapsulation: Hide implementation details

Part 2: ES Modules (Modern Way)

Modern Node.js and JavaScript use ES Modules.

Exporting from a Module

Create lesson-13/math.js:

// Named exports
export function add(a, b) {
  return a + b;
}

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

export const PI = 3.14159;

Importing from a Module

Create lesson-13/main.js:

// Import specific items
import { add, subtract, PI } from './math';

console.log(add(5, 3));        // 8
console.log(subtract(10, 4));  // 6
console.log(PI);               // 3.14159

Import Everything

// Import all exports as a namespace
import * as Math from './math';

console.log(Math.add(5, 3));      // 8
console.log(Math.subtract(10, 4)); // 6
console.log(Math.PI);              // 3.14159

Part 3: Default Exports

Each module can have ONE default export:

Create lesson-13/calculator.js:

// Default export
export default class Calculator {
  add(a, b) {
    return a + b;
  }
  
  subtract(a, b) {
    return a - b;
  }
  
  multiply(a, b) {
    return a * b;
  }
  
  divide(a, b) {
    if (b === 0) throw new Error("Division by zero");
    return a / b;
  }
}

Import default export:

// No curly braces for default import
import Calculator from './calculator';

const calc = new Calculator();
console.log(calc.add(10, 5));      // 15
console.log(calc.multiply(4, 7));  // 28

Mixing Default and Named Exports

// utils.js
export default function greet(name) {
  return `Hello, ${name}!`;
}

export function farewell(name) {
  return `Goodbye, ${name}!`;
}

export const VERSION = "1.0.0";
// main.js
import greet, { farewell, VERSION } from './utils';

console.log(greet("Alice"));     // Hello, Alice!
console.log(farewell("Bob"));    // Goodbye, Bob!
console.log(VERSION);            // 1.0.0

Part 4: Module Organization Patterns

Pattern 1: Feature-Based Structure

project/
├── users/
│   ├── user.js           (User interface/class)
│   ├── userService.js    (User business logic)
│   └── index.js          (Export all)
├── products/
│   ├── product.js
│   ├── productService.js
│   └── index.js
└── main.js
users/user.js:
// User validation utilities
export class UserValidator {
  static isValidEmail(email) {
    return email.includes("@");
  }
}

// Helper to create user objects
export function createUser(id, name, email) {
  return { id, name, email };
}
users/userService.js:
import { UserValidator } from './user';

export class UserService {
  constructor() {
    this.users = [];
  }
  
  addUser(user) {
    if (!UserValidator.isValidEmail(user.email)) {
      throw new Error("Invalid email");
    }
    this.users.push(user);
  }
  
  getUsers() {
    return this.users;
  }
}
users/index.js:
// Re-export everything
export * from './user';
export * from './userService';
main.js:
// Import from the feature folder
import { createUser, UserService } from './users';

const service = new UserService();
service.addUser(createUser(1, "Alice", "alice@example.com"));
console.log(service.getUsers());

Part 5: Practical Example - Library System

book.js

// Helper to create book objects
export function createBook(isbn, title, author, year) {
  return { 
    isbn, 
    title, 
    author, 
    year, 
    available: true 
  };
}

library.js

export class Library {
  constructor() {
    this.books = [];
  }
  
  addBook(book) {
    this.books.push(book);
  }
  
  findByISBN(isbn) {
    return this.books.find(b => b.isbn === isbn);
  }
  
  findByAuthor(author) {
    return this.books.filter(b => 
      b.author.toLowerCase().includes(author.toLowerCase())
    );
  }
  
  borrowBook(isbn) {
    const book = this.findByISBN(isbn);
    if (book && book.available) {
      book.available = false;
      return true;
    }
    return false;
  }
  
  returnBook(isbn) {
    const book = this.findByISBN(isbn);
    if (book && !book.available) {
      book.available = true;
      return true;
    }
    return false;
  }
  
  listAvailableBooks() {
    return this.books.filter(b => b.available);
  }
}

main.js

import { Library } from './library';
import { createBook } from './book';

const library = new Library();

// Add books
library.addBook(createBook("978-0-123", "JavaScript Guide", "John Doe", 2023));
library.addBook(createBook("978-0-456", "Node.js Basics", "Jane Smith", 2022));

// List available
console.log("Available books:");
library.listAvailableBooks().forEach(book => {
  console.log(`- ${book.title} by ${book.author}`);
});

// Borrow a book
library.borrowBook("978-0-123");

// List available again
console.log("\nAfter borrowing:");
library.listAvailableBooks().forEach(book => {
  console.log(`- ${book.title}`);
});

Part 6: Configuration for ES Modules

To use ES modules in Node.js:

package.json

``json

{

"name": "lesson-13",

"version": "1.0.0",

"type": "module",

"scripts": {

"start": "node main.js"

}

}

` Note: The "type": "module"` is required to use ES modules (import/export) instead of CommonJS (require/module.exports).

Practice Exercises

Exercise 1: Math Library

Create a math library module with functions for:

  • Basic operations (add, subtract, multiply, divide)
  • Advanced operations (power, square root, factorial)
  • Constants (PI, E)

Exercise 2: String Utilities

Create a string utilities module with functions like:

  • capitalize, uppercase, lowercase
  • reverse, isPalindrome
  • wordCount, charCount

Exercise 3: Validator Module

Create a validation module with functions to validate:

  • Email addresses
  • Phone numbers
  • URLs
  • Credit card numbers (basic check)

Exercise 4: Shopping Cart

Organize a shopping cart application into modules:

  • Product module
  • Cart module
  • Discount module
  • Main application

Common Mistakes

Mistake 1: Circular Dependencies

// user.js
import { createPost } from './post';

export function createUser(name) {
  return { name, posts: [] };
}

// post.js
import { createUser } from './user';  // ❌ Circular dependency!

export function createPost(author) {
  return { author };
}

// Fix: Reorganize to avoid circular dependencies

Mistake 2: Forgetting File Extension

// ❌ Wrong (in some setups)
import { add } from './math';

// ✅ Correct
import { add } from './math.js';  // Note: .js even for .js files!

Mistake 3: Default Export Naming Confusion

// math.js
export default function calculate() { }

// main.js
import anything from './math';  // Works, but confusing
import calculate from './math';  // Better - matches export name

Key Concepts Summary

Concept Syntax Purpose
Named Export export function name() {} Export specific items
Default Export export default class Name {} One main export per file
Named Import import { name } from './file' Import specific items
Default Import import Name from './file' Import default export
Namespace Import import * as Name from './file' Import everything

What You Learned

  • ✅ How to export code from modules
  • ✅ How to import code into files
  • ✅ Difference between named and default exports
  • ✅ How to organize code with modules
  • ✅ Module patterns for scalable applications
  • ✅ How to configure Node.js for ES modules
  • ✅ Common module pitfalls to avoid

What's Next?

In the next lesson, you'll learn about Classes and Object-Oriented Programming - how to create blueprints for objects with properties and methods!