Your Page Title
🔍

    REQUIRE, EXPORTS AND MODULE PATTERNS

    module.exports-

    module.exports is the actual object that is returned when another file requires a module. It defines what a module exposes externally. Unlike exports, you can assign any valid JavaScript entity directly, like a function, object, or class. If you assign something directly to module.exports, any assignments to exports will be ignored unless reconnected.

    SYNTAX-

    module.exports = function greet(name) {
    return Hello, ${name};
    };

    require-

    require is a function provided by Node.js to import external modules, whether built-in, user-defined, or installed via npm. When called, it reads the module file, executes it, and returns the exported content, allowing you to use it in your current file. Node caches the module after the first load, so repeated calls return the same object unless manually refreshed.

    SYNTAX-

    const moduleName = require(‘module-name’); // Built-in or npm module
    const custom = require(‘./custom-module.js’); // User-defined modul

    exports-

    exports is a shortcut reference to module.exports, used for exposing multiple properties or methods from a module. Anything attached to exports becomes available when the module is required. It’s ideal for exporting several named functions or constants without overwriting the entire export object.

    SYNTAX-

    exports.add = function(a, b) { return a + b; };
    exports.sub = function(a, b) { return a – b; };

    MODULE PATTERNS

    Modules in Node.js are designed to promote organized, reusable, and maintainable code. As applications grow in size and complexity, simply exporting functions isn’t always sufficient. That’s where module patterns come in. These are design techniques that define how modules are structured, what they expose, and how they behave when reused across files or reloaded in runtime.

    Different patterns solve different problems—some focus on preserving state across imports, while others aim to provide fresh instances or control visibility of internal logic. Understanding these patterns helps developers write more predictable, scalable, and efficient Node.js code, especially in multi-module and multi-developer projects.

    Use Case & Behaviour-

    1. Singleton Pattern

    • Description: When a module is loaded with require, Node caches it and returns the same instance on subsequent loads.
    • Use Case: Ideal for maintaining shared state or configurations.
    • Behavior: Only one instance is maintained throughout the application.

    EXAMPLE

    // config.js
    module.exports = { appName: “MyApp”, version: “1.0.0” };

    // Anywhere else
    const config = require(‘./config’); // Always returns the same object

    2. Factory Pattern

    • Description: A module exports a function that returns a new instance of an object or logic each time it’s called.
    • Use Case: Useful when you need multiple independent instances (e.g., for database connections).
    • Behavior: Generates fresh data or object per invocation.

    EXAMPLE-

    // userFactory.js
    module.exports = function createUser(name) {
    return { name, createdAt: Date.now() };
    };

    // Usage
    const createUser = require(‘./userFactory’);
    const user1 = createUser(‘Alice’);
    const user2 = createUser(‘Bob’);

    3. Revealing Module Pattern

    • Description: Encapsulates private logic and exposes only selected properties or methods.
    • Use Case: Prevents direct access to internal variables, promoting secure APIs.
    • Behavior: Only intended parts of the module are accessible externally.

    EXAMPLE-

    // mathModule.js
    const _privateMultiplier = 2;

    function add(a, b) {
    return a + b;
    }

    function multiply(a) {
    return a * _privateMultiplier;
    }

    module.exports = { add, multiply };

    4. IIFE-Based Module (Closure Pattern)

    • Description: Uses an Immediately Invoked Function Expression to define private and public members.
    • Use Case: Fine-grained control over visibility of internal state.
    • Behavior: Private variables remain hidden inside closure.

    EXAMPLE-

    // timerModule.js
    module.exports = (() => {
    let counter = 0;

    function increment() {
    counter++;
    return counter;
    }

    function reset() {
    counter = 0;
    }

    return { increment, reset };
    })();

    5. Hybrid Pattern

    • Description: Combines multiple patterns—for example, singleton state with factory methods.
    • Use Case: Useful in complex applications needing flexibility.
    • Behavior: Balances shared state and dynamic generation.

    EXAMPLE-

    // service.js
    const config = { env: ‘production’ };

    function createLogger(prefix) {
    return {
    log: (msg) => console.log([${prefix}] ${msg})
    };
    }

    module.exports = { config, createLogger };

    BENEFITS OF USING MODULE PATTERNS-

    1. Code Reusability

    • Encourages reuse of logic across multiple parts of the application.
    • Reduces duplication, making code DRY (Don’t Repeat Yourself).

    2. Maintainability

    • Well-defined patterns promote organized code, making it easier to update or debug.
    • Isolation of functionality prevents unintended side effects.

    3. Scalability

    • Suitable for growing applications—new features can be added without disrupting existing modules.
    • Patterns like factory and hybrid allow flexible expansion.

    4. Encapsulation and Abstraction

    • Revealing or IIFE patterns help encapsulate private logic, exposing only essential interfaces.
    • Enhances control over what parts of the module are publicly accessible.

    5. Testability

    • Patterns that isolate state and expose defined interfaces make unit testing more straightforward.
    • Factory and revealing patterns simplify mocking components.

    6. Performance Optimization

    • Singleton patterns reduce overhead by sharing loaded instances across modules.
    • Cached modules avoid repeated initializations, improving runtime performance.

    7. Consistency and Team Collaboration

    • Encourages consistent coding practices across teams.
    • Makes onboarding and collaborative development smoother with predictable structure.

    8. Design Flexibility

    • Developers can choose patterns suited to the specific needs of a module.
    • Enables mixing and matching of design strategies (e.g., combining singleton for config with factory for services).