0%
JavaScript Moderno: Os Módulos ES

Módulos ES

Organização Modular do Código

10-15 min

JavaScript Moderno: Os Módulos ES

Os módulos ES (ECMAScript) são um sistema padronizado para organizar e compartilhar código JavaScript entre diferentes arquivos. Eles permitem criar aplicações mais fáceis de manter e mais modulares.

Introdução aos Módulos ES

Por que usar módulos?

  • Encapsulamento: Cada módulo tem seu próprio escopo
  • Reutilização: O código pode ser facilmente compartilhado entre arquivos
  • Dependências explícitas: As relações entre módulos são claramente definidas
  • Organização: Estrutura clara do código

Configuração básica

<!-- Dans votre HTML -->
<script type="module" src="main.js"></script>
// Dans votre package.json
{
    "type": "module"
}

Export de Módulos

Export nomeado

// mathematiques.js
export const PI = 3.14159;

export function addition(a, b) {
    return a + b;
}

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

// Alternative : export groupé
const multiplication = (a, b) => a * b;
const division = (a, b) => a / b;

export { multiplication, division };

Export padrão

// calculateur.js
class Calculateur {
    addition(a, b) {
        return a + b;
    }
    
    soustraction(a, b) {
        return a - b;
    }
}

export default Calculateur;

Combinação de exports

// utils.js
export const VERSION = "1.0.0";

export function formaterNombre(nombre) {
    return nombre.toFixed(2);
}

const Utils = {
    VERSION,
    formaterNombre
};

export default Utils;

Import de Módulos

Import nomeado

// app.js
import { addition, soustraction } from './mathematiques.js';
import { PI as MATH_PI } from './mathematiques.js';

console.log(addition(2, 3));      // 5
console.log(MATH_PI);             // 3.14159

Import padrão

// app.js
import Calculateur from './calculateur.js';

const calc = new Calculateur();
console.log(calc.addition(5, 3)); // 8

Import combinado

// app.js
import Utils, { VERSION } from './utils.js';
// ou
import Utils, * as UtilsAll from './utils.js';

console.log(Utils.formaterNombre(3.14159)); // "3.14"
console.log(VERSION);                       // "1.0.0"

Import dinâmico

// app.js
async function chargerModule() {
    try {
        const module = await import('./grand-module.js');
        console.log(module.fonctionImportante());
    } catch (erreur) {
        console.error('Erreur de chargement:', erreur);
    }
}

Organização dos Módulos

Estrutura de projeto típica

src/
├── index.js
├── modules/
│   ├── utilisateurs/
│   │   ├── index.js
│   │   ├── utilisateur.js
│   │   └── validation.js
│   ├── produits/
│   │   ├── index.js
│   │   └── produit.js
│   └── utils/
│       ├── index.js
│       ├── format.js
│       └── validation.js

Módulos barrel (Barrel modules)

// modules/utilisateurs/index.js
export { default as Utilisateur } from './utilisateur.js';
export { validerEmail, validerMotDePasse } from './validation.js';

// app.js
import { Utilisateur, validerEmail } from './modules/utilisateurs';

Módulos agregadores

// modules/index.js
export * from './utilisateurs';
export * from './produits';
export * from './utils';

// app.js
import { Utilisateur, Produit, formaterPrix } from './modules';

Padrões e boas práticas

Padrão Singleton

// config.js
class Config {
    constructor() {
        this.api = 'https://api.example.com';
        this.timeout = 5000;
    }
    
    setApi(url) {
        this.api = url;
    }
}

export default new Config();

Padrão Factory (Fábrica)

// loggerFactory.js
const createLogger = (prefix = '') => ({
    log: (message) => console.log(`${prefix}${message}`),
    error: (message) => console.error(`${prefix}${message}`),
    warn: (message) => console.warn(`${prefix}${message}`)
});

export default createLogger;

Padrão Adapter (Adaptador)

// apiAdapter.js
import axios from 'axios';
import { formatResponse } from './utils.js';

export const api = {
    async get(url) {
        const response = await axios.get(url);
        return formatResponse(response.data);
    },
    
    async post(url, data) {
        const response = await axios.post(url, data);
        return formatResponse(response.data);
    }
};

Casos de uso práticos

Aplicação modular

// modules/auth/auth.service.js
export class AuthService {
    async login(credentials) {
        // Logique d'authentification
    }
    
    async logout() {
        // Logique de déconnexion
    }
}

// modules/auth/index.js
export { AuthService } from './auth.service.js';

// app.js
import { AuthService } from './modules/auth';
const auth = new AuthService();

Gerenciamento de estado modular

// store/counter.js
let count = 0;
const listeners = new Set();

export const getCount = () => count;

export const increment = () => {
    count++;
    notifyListeners();
};

export const decrement = () => {
    count--;
    notifyListeners();
};

export const subscribe = (listener) => {
    listeners.add(listener);
    return () => listeners.delete(listener);
};

function notifyListeners() {
    listeners.forEach(listener => listener(count));
}

// app.js
import { getCount, increment, subscribe } from './store/counter.js';

subscribe((newCount) => {
    console.log('Nouveau compte:', newCount);
});

Plugins modulares

// plugins/logger.js
export const loggerPlugin = {
    install(app) {
        app.logger = {
            log: console.log,
            error: console.error
        };
    }
};

// plugins/storage.js
export const storagePlugin = {
    install(app) {
        app.storage = {
            get: key => localStorage.getItem(key),
            set: (key, value) => localStorage.setItem(key, value)
        };
    }
};

// app.js
import { loggerPlugin } from './plugins/logger.js';
import { storagePlugin } from './plugins/storage.js';

class App {
    constructor() {
        this.plugins = new Map();
    }
    
    use(plugin) {
        plugin.install(this);
        this.plugins.set(plugin.name, plugin);
    }
}

const app = new App();
app.use(loggerPlugin);
app.use(storagePlugin);

Exercícios práticos

  1. Criação de uma biblioteca utilitária
// utils/string.js
export const capitalize = (str) => 
    str.charAt(0).toUpperCase() + str.slice(1);

export const reverse = (str) => 
    str.split('').reverse().join('');

// utils/array.js
export const unique = (arr) => 
    [...new Set(arr)];

export const groupBy = (arr, key) => 
    arr.reduce((acc, item) => {
        (acc[item[key]] = acc[item[key]] || []).push(item);
        return acc;
    }, {});

// utils/index.js
export * from './string.js';
export * from './array.js';

// app.js
import { capitalize, unique } from './utils';

console.log(capitalize('hello')); // "Hello"
console.log(unique([1, 2, 2, 3])); // [1, 2, 3]
  1. Sistema de plugins modular
// plugin-system.js
export class PluginSystem {
    constructor() {
        this.plugins = new Map();
    }
    
    register(name, plugin) {
        if (this.plugins.has(name)) {
            throw new Error(`Plugin ${name} déjà enregistré`);
        }
        this.plugins.set(name, plugin);
        
        if (plugin.install) {
            plugin.install(this);
        }
    }
    
    use(name) {
        const plugin = this.plugins.get(name);
        if (!plugin) {
            throw new Error(`Plugin ${name} non trouvé`);
        }
        return plugin;
    }
}

// plugins/validation.js
export const validationPlugin = {
    name: 'validation',
    install(system) {
        system.validate = {
            email: (email) => /^.+@.+\..+$/.test(email),
            required: (value) => value !== undefined && value !== ''
        };
    }
};

// app.js
import { PluginSystem } from './plugin-system.js';
import { validationPlugin } from './plugins/validation.js';

const system = new PluginSystem();
system.register(validationPlugin.name, validationPlugin);

console.log(system.validate.email('test@example.com')); // true

Conclusão

Os módulos ES são uma ferramenta fundamental para:

  • Organizar o código de maneira modular e de fácil manutenção
  • Gerenciar de forma eficiente as dependências entre as diferentes partes da aplicação
  • Criar sistemas extensíveis por meio de plugins
  • Melhorar a reutilização do código

No próximo tutorial, vamos explorar as estruturas de dados modernas, como Map e Set.


Precisa revisar Promises e async/await? Consulte nosso tutorial anterior sobre programação assíncrona.

Comentários

Os comentários são alimentados pelo GitHub Discussions

Conecte-se com o GitHub para participar da discussão

Link copiado!