Aprenda a trabalhar com módulos CommonJS e ES6, manipular arquivos e compreender o módulo fs
Esta seção é para alunos que estão começando com um computador que SÓ TEM O VS CODE INSTALADO.
Se você já fez a Aula 1 e tem o Node.js funcionando, pode pular para a introdução.
O que fazer:
https://nodejs.orgO que você vai ver:
🎯 IMPORTANTE: Escolha sempre o LTS!
LTS significa "Long Term Support" (Suporte de Longo Prazo). É a versão mais estável e recomendada para aprender.
Passo a passo:
node-v20.x.x-x64.msi (Windows)Processo de instalação:
Durante a instalação:
Como abrir o terminal:
💡 Atalho rápido:
Você também pode pressionar Ctrl + ` (Ctrl + crase) para abrir o terminal rapidamente!
Digite este comando no terminal:
Depois pressione Enter
✅ Se deu certo, você vai ver algo assim:
(O número pode ser diferente, mas deve começar com "v")
❌ Se deu erro, você vai ver algo assim:
Se isso acontecer, vá para a seção "Problemas Comuns" no final desta aula!
O que é NPM?
NPM é como uma "loja de aplicativos" para programadores. Ele vem junto com o Node.js automaticamente!
Digite este comando no terminal:
Depois pressione Enter
✅ Se deu certo, você vai ver algo assim:
(O número pode ser diferente)
Onde criar a pasta:
aula-2-nodejsComo abrir no VS Code:
💡 Atalho rápido:
Você também pode pressionar Ctrl + K, Ctrl + O para abrir uma pasta rapidamente!
Se você chegou até aqui e todos os comandos funcionaram, seu computador está preparado para a aula!
Agora você pode continuar com a introdução da aula. Vamos aprender sobre módulos! 🚀
NPM significa "Node Package Manager" (Gerenciador de Pacotes do Node). É como uma "loja de aplicativos" para programadores!
Analogia: Imagine que você está montando um computador. Em vez de criar cada peça do zero, você compra peças prontas (processador, memória, etc.) e monta tudo junto. O NPM faz isso com código!
O package.json é como a "carteira de identidade" do seu projeto! Ele guarda informações importantes como:
Se o terminal não estiver aberto, pressione Ctrl + ' (aspas simples) ou vá no menu Terminal → New Terminal
Digite este comando para ver onde você está:
✅ Resultado esperado: Deve mostrar o caminho da pasta do seu projeto
Digite exatamente este comando:
🤓 Explicação do comando:
npm = chama o gerenciador de pacotesinit = inicializa um novo projeto-y = responde "sim" para todas as perguntas automaticamente✅ O que deve acontecer:
Olhe na barra lateral do VS Code. Você deve ver:
Clique no arquivo package.json na barra lateral para abri-lo. Você verá algo parecido com isto:
{
"name": "meu-projeto",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
🎉 Perfeito! Este é o "RG" do seu projeto. Não se preocupe em entender tudo agora, vamos usar isso mais para frente!
Causa: Node.js não foi instalado corretamente
Solução: Volte na seção anterior e reinstale o Node.js
Causa: Pasta sem permissão de escrita
Solução: Crie a pasta em um local diferente (ex: Desktop)
Causa: Você não está na pasta correta
Solução: Use cd nome-da-pasta para entrar na pasta do projeto
Antes de continuar, confirme que você tem:
node --version)npm --version)🎉 Tudo certo? Agora sim podemos começar a aprender sobre módulos!
Na Aula 1, você aprendeu o que é o Node.js, instalou ele no seu computador e criou seu primeiro programa! Lembra do famoso "Hello World"? 😊
Hoje vamos dar o próximo passo: aprender a organizar nosso código de forma inteligente usando módulos.
Resposta simples: Módulos são como gavetas organizadas onde você guarda diferentes tipos de código!
Imagine sua mesa de estudos: você tem uma gaveta para canetas, outra para papéis, outra para calculadora... Módulos fazem a mesma coisa com seu código JavaScript! 📝
Pense no seu celular: você não tem um único app gigante que faz tudo, né? Você tem vários apps pequenos, cada um com sua função específica! 📲
Módulo que cuida das imagens
Módulo que cuida das mensagens
Módulo que cuida da música
💡 Sacou a ideia? Cada app tem sua responsabilidade, mas todos funcionam no mesmo celular. No Node.js é igual: cada módulo tem sua função, mas todos trabalham juntos no mesmo projeto!
Em vez de ter tudo bagunçado em um arquivo gigante, você separa cada coisa no seu lugar. Fica muito mais fácil de encontrar o que você precisa!
Criou uma função legal? Coloque em um módulo e use em vários projetos! É como ter uma receita de bolo que você pode fazer sempre que quiser.
Cada módulo fica "na sua", sem interferir nos outros. É como ter gavetas separadas - as coisas não se misturam!
Quando você trabalha com outras pessoas, cada um pode cuidar de um módulo diferente. Ninguém atrapalha ninguém!
Pense no seu celular: você tem um app para fotos, outro para mensagens, outro para música. Cada app é como um módulo - tem sua função específica, mas todos trabalham juntos no mesmo sistema!
No Node.js, fazemos a mesma coisa: criamos "apps" (módulos) para diferentes funções do nosso projeto.
Definição Simples: Módulos são arquivos JavaScript que contêm código específico e podem ser reutilizados em outros arquivos.
Analogia: É como ter uma caixa de ferramentas. Cada ferramenta (função) fica organizada e você pega apenas o que precisa para cada trabalho!
Imagina que quando você instala o Node.js, ele já vem com uma caixa de ferramentas cheia de coisas úteis! Você não precisa comprar nada extra, já está tudo lá esperando você usar.
🔧 Algumas ferramentas que já vêm na caixa:
fs
Para mexer com arquivos (criar, ler, deletar)
http
Para criar sites e APIs
path
Para trabalhar com endereços de arquivos
os
Para saber informações do computador
💡 Dica: É como quando você compra um celular novo - ele já vem com apps básicos instalados (câmera, calculadora, etc.). O Node.js funciona igual!
meu-logger-projeto# Navegue até onde quer criar (exemplo: Área de Trabalho)
cd Desktop
# Crie a pasta
mkdir meu-logger-projeto
# Entre na pasta
cd meu-logger-projeto
meu-logger-projeto para dentro do VS Codemeu-logger-projeto# Dentro da pasta do projeto
code .
logger.js// logger.js - Sistema de Logger para nossa aplicação
// Este arquivo cria uma "classe" que sabe como salvar mensagens em arquivos
// 1. IMPORTAÇÕES - Trazendo as ferramentas que vamos usar
const fs = require('fs').promises; // Sistema de arquivos (jeito moderno que não trava)
const path = require('path'); // Manipulação de caminhos
// 2. CLASSE LOGGER - Nossa "fábrica" de logs
class Logger {
// CONSTRUTOR - Executa quando criamos um novo Logger
constructor(logFile = 'app.log') {
// __dirname = pasta atual do arquivo
// path.join = junta caminhos de forma segura
this.logFile = path.join(__dirname, logFile);
console.log(`📝 Logger criado! Arquivo: ${this.logFile}`);
}
// MÉTODO PRINCIPAL - Escreve qualquer tipo de log
async log(message, level = 'INFO') {
// Cria um "carimbo de data e hora" (tipo: 2024-01-15 às 10:30:45)
const timestamp = new Date().toISOString(); // Pega a data/hora atual e transforma em texto
// Monta a linha do log: [DATA] NÍVEL: MENSAGEM
const logEntry = `[${timestamp}] ${level}: ${message}\n`;
try {
// appendFile = "cola" no final do arquivo (como escrever no final de um caderno)
await fs.appendFile(this.logFile, logEntry);
console.log(`✅ Log salvo: ${level} - ${message}`);
} catch (error) {
console.error('❌ Erro ao escrever log:', error.message);
}
}
// MÉTODO DE CONVENIÊNCIA - Para logs informativos
async info(message) {
await this.log(message, 'INFO');
}
// MÉTODO DE CONVENIÊNCIA - Para logs de erro
async error(message) {
await this.log(message, 'ERROR');
}
// MÉTODO EXTRA - Para logs de aviso
async warn(message) {
await this.log(message, 'WARN');
}
}
// EXPORTA a classe para outros arquivos usarem
module.exports = Logger;
Ctrl+S (Windows) ou Cmd+S (Mac)PASSO 4.1: Crie o arquivo test-logger.js
test-logger.jsDigite este código no arquivo test-logger.js:
// test-logger.js - Arquivo para testar nosso logger
// ATENÇÃO: Este arquivo deve estar na MESMA PASTA que o logger.js
// LINHA 1: Importa nossa classe Logger do arquivo logger.js
// O './' significa "na mesma pasta que este arquivo"
const Logger = require('./logger');
// LINHA 2: Função que vai testar nosso logger
// 'async' significa que esta função pode "esperar" outras operações
async function testarLogger() {
console.log('🚀 Iniciando teste do Logger...');
// LINHA 3: Cria um novo logger que vai salvar no arquivo 'teste.log'
const logger = new Logger('teste.log');
// LINHA 4: Testa diferentes tipos de mensagem
// Cada linha vai aparecer no console E ser salva no arquivo
// IMPORTANTE: Usamos 'await' para esperar cada operação terminar
await logger.info('Aplicação iniciada com sucesso!');
await logger.warn('Esta é uma mensagem de aviso');
await logger.error('Simulando um erro de teste');
console.log('✅ Teste concluído! Verifique o arquivo teste.log');
}
// LINHA 5: Executa nossa função de teste
testarLogger();
PASSO 4.2: Salve o arquivo
Ctrl+S (Windows) ou Cmd+S (Mac)PASSO 4.3: Execute no terminal
Ctrl+Shift+` (acento grave)# Digite este comando e pressione Enter:
node test-logger.js
PASSO 4: Resultado esperado
🚀 Iniciando teste do Logger...
📝 Logger criado! Arquivo: C:\sua\pasta\teste.log
✅ Log salvo: INFO - Aplicação iniciada com sucesso!
✅ Log salvo: WARN - Esta é uma mensagem de aviso
✅ Log salvo: ERROR - Simulando um erro de teste
✅ Teste concluído! Verifique o arquivo teste.log
Problema sem async/await: O código pode terminar antes de salvar todos os logs no arquivo.
Solução com async/await: Esperamos cada operação terminar antes de continuar.
💡 Analogia: É como esperar cada pessoa entrar no elevador antes de fechar a porta, em vez de fechar a porta enquanto alguém ainda está entrando!
async function e await nas chamadas do loggerÀs vezes você precisa de uma ferramenta específica que não existe na caixa do Node.js. Então você mesmo faz essa ferramenta! É como criar sua própria chave de fenda especial.
🎯 Exemplo prático: Você cria um arquivo calculadora.js com funções para somar,
multiplicar, etc. Depois usa essas funções em outros arquivos do seu projeto.
💡 É como fazer uma receita de bolo e guardar numa pasta. Sempre que quiser fazer o bolo, você pega a receita e usa!
Imagina uma loja gigante onde programadores do mundo todo deixam suas ferramentas de graça para você usar!
Essa loja se chama NPM. Você "baixa" essas ferramentas com o comando npm install.
🎪 Algumas ferramentas famosas da "loja":
express
Para criar sites super rápido
lodash
Funções úteis para facilitar sua vida
colors
Para colorir texto no terminal
moment
Para trabalhar com datas facilmente
💡 Dica: É como baixar apps no seu celular - você não precisa criar o WhatsApp, só baixa e usa!
Vamos aprender na prática como "baixar" e usar uma ferramenta da "loja" NPM.
Vamos usar o pacote colors para deixar nossos textos coloridos no terminal!
# Instala o pacote 'colors' no seu projeto
npm install colors
O que cada parte significa:
npm = O "entregador" que busca pacotes na lojainstall = "Instalar" ou "baixar"colors = Nome do pacote que queremosnpm WARN deprecated colors@1.4.0: Please use...
added 1 package, and audited 2 packages in 2s
found 0 vulnerabilities
Não se preocupe com warnings! São só avisos, o pacote foi instalado com sucesso.
node_modules no seu projetopackage.json agora tem uma seção "dependencies"package-lock.json (é normal!)Clique com o botão direito na pasta do projeto → "Novo Arquivo" → digite "teste-cores.js"
// teste-cores.js - Testando o pacote 'colors'
// IMPORTA o pacote que acabamos de instalar
const colors = require('colors');
// FUNÇÃO PRINCIPAL - Testa diferentes cores
function testarCores() {
console.log('🎨 Testando o pacote Colors!');
console.log(''); // Linha em branco
// Textos coloridos básicos
console.log('Este texto é vermelho!'.red);
console.log('Este texto é verde!'.green);
console.log('Este texto é azul!'.blue);
console.log('Este texto é amarelo!'.yellow);
console.log('Este texto é magenta!'.magenta);
console.log('Este texto é ciano!'.cyan);
console.log(''); // Linha em branco
// Textos com estilos
console.log('Este texto está em negrito!'.bold);
console.log('Este texto está sublinhado!'.underline);
console.log('Este texto está invertido!'.inverse);
console.log(''); // Linha em branco
// Combinando cores e estilos
console.log('Texto verde e negrito!'.green.bold);
console.log('Texto azul e sublinhado!'.blue.underline);
console.log('Texto vermelho invertido!'.red.inverse);
console.log(''); // Linha em branco
// Usando cores de fundo
console.log('Texto com fundo vermelho'.bgRed);
console.log('Texto com fundo verde'.bgGreen);
console.log('Texto branco com fundo azul'.white.bgBlue);
console.log(''); // Linha em branco
console.log('🎉 Teste concluído! Seu terminal agora tem cores!'.rainbow);
}
// EXECUTA a função
testarCores();
# Executa nosso arquivo de teste
node teste-cores.js
🎨 Testando o pacote Colors!
Este texto é vermelho!
Este texto é verde!
Este texto é azul!
Este texto é amarelo!
Este texto é magenta!
Este texto é ciano!
Este texto está em negrito!
Este texto está sublinhado!
🎉 Teste concluído! Seu terminal agora tem cores!
Nota: No terminal real, as cores serão muito mais vibrantes!
const colors = require('colors');
"Importa" o pacote colors para usar no nosso código
'texto'.red
O pacote "adiciona" métodos às strings para colorir
'texto'.green.bold
Você pode "encadear" estilos (verde + negrito)
node_modules/
Pasta onde ficam todos os pacotes instalados
🎯 Conceito importante: Quando você faz require('colors'),
o Node.js automaticamente procura na pasta node_modules e encontra o pacote!
Marque o que você conseguiu fazer:
npm install colors sem errosnode_modules no meu projetoteste-cores.jsnode teste-cores.jsrequire('colors') funciona🎉 Se você marcou todos os itens, parabéns! Você acabou de usar seu primeiro pacote NPM externo!
Imagine que você está organizando uma festa. Você precisa de uma lista com:
O package.json é exatamente isso para seu projeto! É um arquivo que diz:
Ctrl+Shift+` (acento grave)
💡 Dica: O terminal deve mostrar o caminho da sua pasta do projeto.
Se não estiver, navegue até ela com cd caminho/para/sua/pasta
# O comando mágico que cria o package.json
npm init -y
O que significa cada parte:
npm = O "assistente" que gerencia pacotesinit = "Inicializar" um novo projeto-y = "Yes" para tudo (aceita as configurações padrão)Wrote to C:\sua\pasta\package.json:
{
"name": "meu-logger-projeto",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
"name": Nome do seu projeto (como o nome da festa)
Vai ser o nome da pasta por padrão
"version": Versão do seu projeto (como "versão 1.0")
Começa sempre com 1.0.0
"description": Descrição do que o projeto faz
Está vazio, você pode preencher depois
"main": Arquivo principal do projeto
Por padrão é "index.js" (você pode mudar)
"scripts": Comandos que você pode executar
Como atalhos para tarefas comuns
"author": Quem criou o projeto (você!)
Pode adicionar seu nome depois
package.json na sua pasta (lado esquerdo do VS Code)🎉 Parabéns! Agora seu projeto está "oficialmente" configurado como um projeto Node.js. É como se você tivesse criado a "certidão de nascimento" do seu projeto!
node --version e npm --versionmkdir meu-primeiro-modulocd meu-primeiro-modulocode .No VS Code: Clique com o botão direito na área de arquivos → "New File" → Digite "math.js"
// math.js - Módulo de operações matemáticas
// Este arquivo contém funções para cálculos básicos
// Função para somar dois números
function somar(a, b) {
console.log(`Somando ${a} + ${b}`);
return a + b; // Retorna o resultado da soma
}
// Função para multiplicar dois números
function multiplicar(a, b) {
console.log(`Multiplicando ${a} × ${b}`);
return a * b; // Retorna o resultado da multiplicação
}
// Função para dividir dois números
function dividir(a, b) {
if (b === 0) {
console.log('Erro: Não é possível dividir por zero!');
return null;
}
console.log(`Dividindo ${a} ÷ ${b}`);
return a / b;
}
// IMPORTANTE: Exportando as funções para outros arquivos poderem usar
// É como "emprestar" suas ferramentas para outros arquivos
module.exports = {
somar,
multiplicar,
dividir
};
// Explicação do module.exports:
// - É a forma de "disponibilizar" suas funções para outros arquivos
// - Sem isso, outros arquivos não conseguem usar suas funções
// - É como colocar suas ferramentas numa caixa para emprestar
No VS Code: Crie outro arquivo chamado "app.js" (este será nosso arquivo principal)
// app.js - Arquivo principal que usa o módulo math.js
// Este arquivo vai "importar" e usar as funções do math.js
// IMPORTANDO o módulo que criamos
// O './' significa "na mesma pasta"
const math = require('./math.js');
// Agora podemos usar as funções do módulo math!
console.log('=== TESTANDO NOSSO MÓDULO MATEMÁTICO ===');
// Testando a função somar
const resultadoSoma = math.somar(10, 5);
console.log('Resultado da soma:', resultadoSoma);
// Testando a função multiplicar
const resultadoMultiplicacao = math.multiplicar(4, 7);
console.log('Resultado da multiplicação:', resultadoMultiplicacao);
// Testando a função dividir
const resultadoDivisao = math.dividir(20, 4);
console.log('Resultado da divisão:', resultadoDivisao);
// Testando divisão por zero (para ver o tratamento de erro)
const divisaoPorZero = math.dividir(10, 0);
console.log('Divisão por zero:', divisaoPorZero);
console.log('=== TESTE CONCLUÍDO ===');
meu-primeiro-modulo)node app.jsVocê acabou de criar e usar seu primeiro módulo Node.js! Agora você entende como:
module.exportsCausa: O arquivo math.js não existe ou está em outra pasta
Solução: Verifique se o arquivo math.js está na mesma pasta que app.js
Causa: A função não foi exportada corretamente
Solução: Verifique se você colocou a função dentro do module.exports
Causa: Você pode estar na pasta errada
Solução: Use ls (Mac/Linux) ou dir (Windows) para ver se os arquivos estão na pasta atual
Imagine que você tem uma biblioteca pessoal e quer emprestar livros para amigos:
CommonJS foi criado especificamente para o Node.js quando JavaScript ainda não tinha um sistema oficial de módulos. É como o "jeito antigo" que funciona muito bem.
ES6 Modules é o sistema "oficial" que veio depois, criado pelos criadores do JavaScript. É mais moderno e será o padrão do futuro.
O jeito "tradicional" do Node.js - como uma "lojinha" que vende e compra coisas
🏪 Analogia da Lojinha:
• module.exports = "Prateleira da loja" (o que você está vendendo)
• require = "Ir comprar" na loja de outro arquivo
É como se cada arquivo fosse uma lojinha que pode vender suas funções para outros arquivos!
// pessoa.js - Criando nosso "produto" para vender
// Jeito 1: Exportar um objeto completo
module.exports = {
nome: 'João',
idade: 30,
falar: function() {
return `Olá, eu sou ${this.nome}`;
}
};
// Jeito 2: Exportar uma função
// module.exports = function(nome) {
// return `Olá, ${nome}!`;
// };
// app.js - "Comprando" o que a pessoa.js está vendendo
// Importar tudo que pessoa.js exporta
const pessoa = require('./pessoa');
// Agora posso usar:
console.log(pessoa.nome); // João
console.log(pessoa.idade); // 30
console.log(pessoa.falar()); // Olá, eu sou João
O jeito "moderno" do JavaScript - como um "supermercado" mais organizado
🛒 Analogia do Supermercado:
• export = "Colocar produtos nas prateleiras" (organizados por seção)
• import = "Pegar só o que precisa" do carrinho
É mais organizado que a lojinha - você pode pegar só os itens específicos que quer!
// pessoa.js - Como um "supermercado" vendendo itens organizados
// JEITO 1: Exportar itens individuais (como colocar produtos em prateleiras separadas)
export const nome = 'João';
export const idade = 30;
export function falar() {
return `Olá, eu sou ${nome}`;
}
// JEITO 2: Exportar um item "principal" (default) - como o "produto em destaque"
export default {
nome: 'João',
idade: 30,
falar() {
return `Olá, eu sou ${this.nome}`;
}
};
// app.js - "Fazendo compras" no supermercado
// OPÇÃO 1: Importar itens específicos (como pegar só pão e leite)
import { nome, idade, falar } from './pessoa.js';
console.log(nome); // João
console.log(falar()); // Olá, eu sou João
// OPÇÃO 2: Importar o item principal (como pegar o "produto em destaque")
import pessoa from './pessoa.js';
console.log(pessoa.nome); // João
console.log(pessoa.falar()); // Olá, eu sou João
// OPÇÃO 3: Importar tudo (como levar o carrinho inteiro)
import * as todasAsCoisas from './pessoa.js';
console.log(todasAsCoisas.nome); // João
Por padrão, o Node.js fala "CommonJS" (a linguagem da lojinha). Para usar ES6 modules (linguagem do supermercado), você precisa "ensinar" uma nova linguagem ao Node.js!
🗣️ Analogia da Linguagem:
É como se o Node.js só soubesse falar "português" (CommonJS). Para ele entender "inglês" (ES6), você precisa dar um "dicionário" para ele!
É como dar um "manual de instruções" para o Node.js!
package.json na pasta do projeto:{
"name": "meu-projeto-es6",
"version": "1.0.0",
"type": "module",
"description": "Projeto usando ES6 modules"
}
🔑 A Linha Mágica: "type": "module" é como dizer ao Node.js:
"Oi Node.js! A partir de agora, fale a linguagem do supermercado (ES6), não da lojinha!"
É como colocar uma "etiqueta especial" nos arquivos para o Node.js saber que são "supermercado":
Renomeie seus arquivos de .js para .mjs:
pessoa.js → pessoa.mjsapp.js → app.mjs
👍 Vantagem: Não precisa criar o "manual" (package.json)
👎 Desvantagem: Extensão diferente pode confundir (como ter dois tipos de arquivo)
Vamos criar um exemplo usando a extensão .mjs:
Passo 1: Crie uma pasta e os arquivos iniciais:
# Crie e entre na pasta
mkdir teste-mjs
cd teste-mjs
code .
Passo 2: Crie o arquivo pessoa.js (com código ES6):
// pessoa.js - Arquivo inicial com ES6
export function criarPessoa(nome, idade) {
return {
nome: nome,
idade: idade,
apresentar() {
return `Olá, eu sou ${this.nome} e tenho ${this.idade} anos!`;
}
};
}
export const saudacao = "Bem-vindo ao ES6 modules!";
Passo 3: Crie o arquivo app.js (que usa pessoa.js):
// app.js - Arquivo que importa pessoa.js
import { criarPessoa, saudacao } from './pessoa.js';
console.log(saudacao);
const pessoa1 = criarPessoa('Maria', 25);
const pessoa2 = criarPessoa('João', 30);
console.log(pessoa1.apresentar());
console.log(pessoa2.apresentar());
Passo 4: Agora renomeie os arquivos para .mjs:
# No Windows (PowerShell ou CMD):
ren pessoa.js pessoa.mjs
ren app.js app.mjs
# No Linux/Mac:
mv pessoa.js pessoa.mjs
mv app.js app.mjs
Passo 5: Atualize o import no app.mjs:
// app.mjs - Atualize a linha de import
import { criarPessoa, saudacao } from './pessoa.mjs'; // ← Mudou para .mjs
console.log(saudacao);
const pessoa1 = criarPessoa('Maria', 25);
const pessoa2 = criarPessoa('João', 30);
console.log(pessoa1.apresentar());
console.log(pessoa2.apresentar());
Passo 6: Execute o arquivo .mjs:
node app.mjs
Agora vamos ver como fazer com package.json:
# Crie e entre na pasta
mkdir teste-es6-modules
cd teste-es6-modules
# Abra no VS Code
code .
Passo 2: Crie o arquivo package.json:
{
"name": "teste-es6-modules",
"version": "1.0.0",
"type": "module",
"description": "Testando ES6 modules"
}
Passo 3: Crie o arquivo utils.js (com ES6 export):
// utils.js - Funções utilitárias usando ES6 modules
// Exportando funções individuais (named exports)
export function cumprimentar(nome) {
return `Olá, ${nome}! Bem-vindo ao ES6 modules!`;
}
export function calcularIdade(anoNascimento) {
const anoAtual = new Date().getFullYear();
return anoAtual - anoNascimento;
}
export const PI = 3.14159;
// Exportando uma função como padrão (default export)
export default function despedir(nome) {
return `Tchau, ${nome}! Até a próxima!`;
}
Passo 4: Crie o arquivo app.js (com ES6 import):
// app.js - Usando ES6 imports
// Importando funções específicas (named imports)
import { cumprimentar, calcularIdade, PI } from './utils.js';
// Importando a função padrão (default import)
import despedir from './utils.js';
// Testando as funções
console.log('=== TESTANDO ES6 MODULES ===');
// Usando named imports
console.log(cumprimentar('Maria'));
console.log('Idade:', calcularIdade(1990));
console.log('Valor de PI:', PI);
// Usando default import
console.log(despedir('Maria'));
console.log('=== TESTE CONCLUÍDO ===');
Passo 5: Execute o teste:
node app.js
{
"name": "meu-projeto",
"version": "1.0.0",
"type": "module", ← Adicione esta linha
"main": "app.js"
}
Agora TODOS os arquivos .js usarão ES6 modules
📝 IMPORTANTE: Primeiro você precisa criar os arquivos com código ES6, depois renomeá-los!
Passo a passo:
# Exemplo: depois de criar os arquivos, renomeie:
pessoa.js → pessoa.mjs
app.js → app.mjs
# Execute assim:
node app.mjs
Apenas arquivos .mjs usarão ES6 modules (sem precisar do package.json)
💡 Dica Principal: SEMPRE crie os arquivos primeiro, depois configure! Não importa qual opção você escolher, você sempre precisa:
Antes de criar os arquivos, vamos organizar nosso projeto:
mkdir calculadora-projeto cd calculadora-projeto
code .
npm init -y
✅ Isso cria o arquivo package.json automaticamente!
💡 Por que fazer isso? O Node.js usa CommonJS por padrão, então nosso código com require() e module.exports funcionará perfeitamente!
No seu editor de código, crie um novo arquivo chamado calculadora.js:
// calculadora.js - Versão CommonJS
// Função para somar dois números
function somar(a, b) {
return a + b; // Retorna a soma de a + b
}
// Função para subtrair dois números
function subtrair(a, b) {
return a - b; // Retorna a subtração de a - b
}
// Função para multiplicar dois números
function multiplicar(a, b) {
return a * b; // Retorna a multiplicação de a * b
}
// Função para dividir dois números
function dividir(a, b) {
if (b === 0) {
return 'Erro: Divisão por zero!'; // Evita erro matemático
}
return a / b; // Retorna a divisão de a / b
}
// Exportar todas as funções para outros arquivos poderem usar
module.exports = {
somar, // Mesma coisa que somar: somar
subtrair, // Mesma coisa que subtrair: subtrair
multiplicar, // Mesma coisa que multiplicar: multiplicar
dividir // Mesma coisa que dividir: dividir
};
Agora crie outro arquivo para testar nossa calculadora:
// teste-calculadora.js - Testando nossa calculadora
// Importar todas as funções da calculadora
const calc = require('./calculadora');
// Testar cada função
console.log('=== TESTANDO NOSSA CALCULADORA ===');
console.log('');
// Teste da soma
console.log('Soma:');
console.log('5 + 3 =', calc.somar(5, 3)); // Resultado: 8
console.log('10 + 7 =', calc.somar(10, 7)); // Resultado: 17
console.log('');
// Teste da subtração
console.log('Subtração:');
console.log('10 - 4 =', calc.subtrair(10, 4)); // Resultado: 6
console.log('15 - 8 =', calc.subtrair(15, 8)); // Resultado: 7
console.log('');
// Teste da multiplicação
console.log('Multiplicação:');
console.log('4 × 3 =', calc.multiplicar(4, 3)); // Resultado: 12
console.log('7 × 6 =', calc.multiplicar(7, 6)); // Resultado: 42
console.log('');
// Teste da divisão
console.log('Divisão:');
console.log('15 ÷ 3 =', calc.dividir(15, 3)); // Resultado: 5
console.log('10 ÷ 2 =', calc.dividir(10, 2)); // Resultado: 5
console.log('10 ÷ 0 =', calc.dividir(10, 0)); // Resultado: Erro!
console.log('');
console.log('=== TESTE CONCLUÍDO ===');
No terminal, navegue até a pasta do projeto e execute:
node teste-calculadora.js
=== TESTANDO NOSSA CALCULADORA === Soma: 5 + 3 = 8 10 + 7 = 17 Subtração: 10 - 4 = 6 15 - 8 = 7 Multiplicação: 4 × 3 = 12 7 × 6 = 42 Divisão: 15 ÷ 3 = 5 10 ÷ 2 = 5 10 ÷ 0 = Erro: Divisão por zero! === TESTE CONCLUÍDO ===
💡 Dica para Iniciantes: Comece com CommonJS (require/module.exports) porque é mais simples. Quando se sentir confortável, experimente ES6 Modules!
Se você quiser experimentar a sintaxe moderna, aqui está como converter nosso exercício:
Edite o arquivo package.json e adicione esta linha:
{
"name": "calculadora-projeto",
"version": "1.0.0",
"type": "module", ← Adicione esta linha!
"main": "index.js",
// ... resto do arquivo
}
// calculadora.js - Versão ES6 Modules
// Funções da calculadora (iguais!)
function somar(a, b) {
return a + b;
}
function subtrair(a, b) {
return a - b;
}
function multiplicar(a, b) {
return a * b;
}
function dividir(a, b) {
if (b === 0) {
return 'Erro: Divisão por zero!';
}
return a / b;
}
// MUDANÇA: export em vez de module.exports
export {
somar,
subtrair,
multiplicar,
dividir
};
// teste-calculadora.js - Versão ES6 Modules
// MUDANÇA: import em vez de require
import * as calc from './calculadora.js';
// O resto do código fica igual!
console.log('=== TESTANDO NOSSA CALCULADORA ===');
console.log('');
console.log('Soma:');
console.log('5 + 3 =', calc.somar(5, 3));
console.log('10 + 7 =', calc.somar(10, 7));
// ... resto igual ao exemplo anterior
"type": "module" no package.jsonimport em vez de require()export em vez de module.exports.js no final dos imports
Na aula 1, você aprendeu a fazer o Node.js mostrar coisas na tela com console.log().
Agora vamos aprender a fazer ele mexer com arquivos do seu computador! 🎉
💡 Pense assim: Antes você só sabia "falar" com o Node.js. Agora vai aprender a pedir para ele "pegar" e "guardar" coisas!
Imagina que você tem um robô super obediente que pode fazer estas coisas:
"Robô, me conta o que está escrito naquele arquivo!"
"Robô, escreve isso num arquivo novo!"
"Robô, esse arquivo existe?"
"Robô, organiza isso numa pasta nova!"
fs significa "File System" (Sistema de Arquivos). É como se fosse o "manual de instruções" para o seu robô Node.js mexer com arquivos! 🤖📚
🧠 Lembra: Na aula 1 você usou console.log() para mostrar coisas na tela.
Agora vai usar fs para mexer com arquivos. É só mais uma ferramenta!
Quando você pede para o robô Node.js ler um arquivo, existem duas maneiras:
Você fala: "Robô, vai buscar aquele arquivo!" e você fica parado esperando ele voltar. Não faz mais nada até ele trazer o arquivo.
⚠️ Problema: Se o arquivo for muito grande, você fica "travado" esperando!
Você fala: "Robô, vai buscar aquele arquivo e me avisa quando trouxer!" Enquanto isso, você continua fazendo outras coisas.
✨ Vantagem: Você não fica "travado" e pode fazer várias coisas ao mesmo tempo!
Você fala: "Robô, vai buscar aquele arquivo!" e você continua fazendo outras coisas. Quando ele trouxer, ele te avisa.
🧠 Resumindo: É como a diferença entre ficar parado esperando o elevador VS apertar o botão e ir fazer outras coisas até ele chegar!
O programa para tudo e espera terminar de ler o arquivo
// 1. Chama o robô fs
const fs = require('fs');
// 2. Fala para o usuário o que vai fazer
console.log('🤖 Vou ler o arquivo agora...');
// 3. PARA TUDO e espera ler o arquivo
const texto = fs.readFileSync('meuarquivo.txt', 'utf8');
// 4. Só executa DEPOIS de ler o arquivo
console.log('📄 Li o arquivo:', texto);
console.log('✅ Pronto!');
O programa continua fazendo outras coisas enquanto lê o arquivo
// 1. Chama o robô fs
const fs = require('fs');
// 2. Fala para o usuário o que vai fazer
console.log('🤖 Vou PEDIR para ler o arquivo...');
// 3. Pede para ler, mas NÃO espera!
fs.readFile('meuarquivo.txt', 'utf8', (erro, texto) => {
// Esta parte só roda QUANDO o arquivo for lido
console.log('📄 Arquivo lido:', texto);
});
// 4. Esta linha roda IMEDIATAMENTE (não espera!)
console.log('🏃♂️ Continuei fazendo outras coisas!');
// Resultado: linha 2 → linha 4 → linha 3
É rápido como o Jeito 2, mas fácil de entender como o Jeito 1!
🍕 Analogia da Pizza (palavras mágicas):
// 🍕 PASSO 1: Chama o "app da pizzaria" (versão moderna do fs)
const fs = require('fs').promises; // Jeito moderno de mexer com arquivos
// 🍕 PASSO 2: Cria uma função especial para "pedir pizza" (async)
async function lerMeuArquivo() {
console.log('📱 Abrindo o app para pedir pizza (ler arquivo)...');
// 🍕 PASSO 3: "Aguarda" a pizza chegar (await)
const texto = await fs.readFile('meuarquivo.txt', 'utf8');
console.log('🍕 Pizza chegou! (arquivo lido):', texto);
console.log('😋 Vou comer! (terminei)');
}
// 🍕 PASSO 4: Faz o pedido da pizza
lerMeuArquivo();
console.log('📱 Enquanto isso, vou mexer no celular!');
// 📱➡️🍕 Resultado: abrir app → mexer no celular → pizza chega → comer
Como fazer o Node.js "abrir" e "ler" um arquivo de texto
Primeiro, vamos criar um arquivo de texto para o robô ler:
🖱️ Como fazer (passo a passo):
dados.txt📄 Conteúdo do arquivo dados.txt:
Olá! Este é um arquivo de teste.
Esta é a segunda linha.
E esta é a terceira linha!
⚠️ Importante: O arquivo dados.txt deve estar na MESMA pasta que o seu código JavaScript!
// 📁 ler-arquivo.js
// 🤖 PASSO 1: Chama o robô que sabe ler arquivos
const fs = require('fs').promises; // .promises = jeito moderno (como pedir pizza pelo app)
// 🤖 PASSO 2: Ensina o robô como ler arquivos
async function lerMeuArquivo() {
try {
console.log('🤖 Robô: "Vou tentar ler o arquivo arquivo-criado.txt..."');
// 📖 PASSO 3: Robô lê o arquivo (utf8 = "leia como texto normal")
const conteudo = await fs.readFile('arquivo-criado.txt', 'utf8');
console.log('✅ Robô: "Consegui ler! Aqui está:"');
console.log('📄 Conteúdo que o robô encontrou:');
console.log('─'.repeat(40));
console.log(conteudo);
console.log('─'.repeat(40));
} catch (error) {
console.error(`❌ Robô: "Ops! Deu problema:"`, error.message);
// 🆘 Robô explica o que pode ter dado errado
if (error.code === 'ENOENT') {
console.log('🤖 Robô: "O arquivo arquivo-criado.txt não existe!"');
console.log('💡 Dica: Execute o script de escrever primeiro.');
}
}
}
// 🚀 PASSO 4: Manda o robô trabalhar!
lerMeuArquivo();
Agora vamos fazer o robô trabalhar!
💻 Como executar (passo a passo):
node ler-arquivo.js
✅ Resultado esperado:
🤖 Robô: "Vou tentar ler o arquivo dados.txt..." ✅ Robô: "Consegui ler! Aqui está:" 📄 Conteúdo que o robô encontrou: ────────────────────────────── Olá! Este é um arquivo de teste. Esta é a segunda linha. E esta é a terceira linha! ──────────────────────────────
❌ Se der erro:
dados.txt existeComo fazer o Node.js "criar" ou "modificar" um arquivo
// escrever-arquivo.js
const fs = require('fs').promises;
// Função para escrever arquivo
async function escreverMeuArquivo() {
try {
console.log('✍️ Criando um novo arquivo...');
// Conteúdo que queremos escrever
const meuTexto = `Arquivo criado pelo Node.js!
Data: ${new Date().toLocaleString()}
Este arquivo foi gerado automaticamente.`;
// Escrever o arquivo (se não existir, cria; se existir, substitui)
await fs.writeFile('arquivo-criado.txt', meuTexto, 'utf8');
console.log('✅ Arquivo "arquivo-criado.txt" criado com sucesso!');
console.log('📄 Conteúdo escrito:');
console.log('─'.repeat(40));
console.log(meuTexto);
console.log('─'.repeat(40));
} catch (error) {
console.error('❌ Erro ao escrever arquivo:', error.message);
}
}
// Executar a função
escreverMeuArquivo();
appendFile em vez de writeFileComo "perguntar" ao sistema se um arquivo está lá
// verificar-arquivo.js
const fs = require('fs').promises;
// Função para verificar se arquivo existe
async function verificarArquivo(nomeArquivo) {
try {
console.log(`🔍 Verificando se "${nomeArquivo}" existe...`);
// Tenta "acessar" o arquivo
await fs.access(nomeArquivo);
console.log(`✅ O arquivo "${nomeArquivo}" existe!`);
return true;
} catch (error) {
console.log(`❌ O arquivo "${nomeArquivo}" NÃO existe.`);
return false;
}
}
// Função principal para testar vários arquivos
async function testarArquivos() {
console.log('=== VERIFICANDO ARQUIVOS ===\n');
// Lista de arquivos para verificar
const arquivos = [
'dados.txt',
'arquivo-criado.txt',
'arquivo-inexistente.txt',
'package.json'
];
// Verificar cada arquivo
for (const arquivo of arquivos) {
await verificarArquivo(arquivo);
console.log(''); // Linha em branco
}
console.log('=== VERIFICAÇÃO CONCLUÍDA ===');
}
// Executar os testes
testarArquivos();
// Exemplo mais avançado: verificar e criar se não existir
async function garantirArquivo(nomeArquivo, conteudoPadrao) {
const existe = await verificarArquivo(nomeArquivo);
if (!existe) {
console.log(`📝 Criando arquivo "${nomeArquivo}" com conteúdo padrão...`);
await fs.writeFile(nomeArquivo, conteudoPadrao, 'utf8');
console.log(`✅ Arquivo "${nomeArquivo}" criado!`);
}
}
// Teste da função avançada
async function exemploAvancado() {
await garantirArquivo('config.txt', 'configuracao=padrao\nversao=1.0');
}
Como criar e listar pastas
// trabalhar-pastas.js
const fs = require('fs').promises;
// Função para criar uma pasta
async function criarPasta(nomePasta) {
try {
console.log(`📁 Criando pasta "${nomePasta}"...`);
// Criar a pasta
await fs.mkdir(nomePasta);
console.log(`✅ Pasta "${nomePasta}" criada com sucesso!`);
} catch (error) {
if (error.code === 'EEXIST') {
console.log(`⚠️ A pasta "${nomePasta}" já existe.`);
} else {
console.error('❌ Erro ao criar pasta:', error.message);
}
}
}
// Função para listar arquivos de uma pasta
async function listarArquivos(nomePasta) {
try {
console.log(`📋 Listando arquivos da pasta "${nomePasta}":`);
// Ler conteúdo da pasta
const arquivos = await fs.readdir(nomePasta);
if (arquivos.length === 0) {
console.log(' (pasta vazia)');
} else {
arquivos.forEach((arquivo, index) => {
console.log(` ${index + 1}. ${arquivo}`);
});
// Código continua normalmente aqui
}
} catch (error) {
console.error(`❌ Erro ao listar pasta "${nomePasta}":`, error.message);
}
}
// Função principal
async function exemploComPastas() {
console.log('=== TRABALHANDO COM PASTAS ===\n');
// Criar uma pasta de teste
await criarPasta('minha-pasta-teste');
console.log('');
// Listar arquivos da pasta atual
await listarArquivos('.');
console.log('');
// Listar arquivos da pasta que criamos
await listarArquivos('minha-pasta-teste');
console.log('\n=== EXEMPLO CONCLUÍDO ===');
}
// Executar o exemplo
exemploComPastas();
Problema: O arquivo ou pasta não existe
Soluções:
C:\\Users\\SeuNome\\arquivo.txtProblema: Sem permissão para acessar o arquivo
Soluções:
Problema: Tentando criar algo que já existe
Soluções:
fs.access() para verificar antes de criar{ recursive: true } para pastasImagine que os arquivos no computador são como casas em uma cidade:
Imagina que você é um carteiro 📮 e precisa entregar cartas em casas diferentes. O módulo path é como seu "manual do carteiro" que te ensina:
💡 Em outras palavras: O path te ajuda a trabalhar com "endereços de arquivos" no computador de forma inteligente!
Imagina que você está mandando uma carta 📬 Cada país tem um jeito diferente de escrever endereços:
Escrevem endereços assim:
• Usa \\ (barra "para trás")
• Tem "letras de gaveta" (C:, D:, E:)
Escrevem endereços assim:
• Usa / (barra "normal")
• Sempre começa com /
🎯 É aqui que o path salva o dia! Ele é como um "tradutor automático" que escreve o endereço no jeito certo para cada computador! 🤖
É como montar um quebra-cabeça de endereço! 🧩 Você tem os pedaços e o path.join() cola tudo certinho.
// 🧩 Montando endereços como quebra-cabeça
const path = require('path');
console.log('🏠 === MONTANDO ENDEREÇOS ===\n');
// 1️⃣ Juntando pedaços simples (como montar: "pasta1 + pasta2 + arquivo")
const endereco1 = path.join('pasta1', 'pasta2', 'arquivo.txt');
console.log('📁 Endereço 1:', endereco1);
// 🪟 No Windows fica: pasta1\\pasta2\\arquivo.txt
// 🐧 No Linux fica: pasta1/pasta2/arquivo.txt
// 2️⃣ Começando da pasta onde estou agora (o "." significa "aqui")
const endereco2 = path.join('.', 'documentos', 'relatorio.pdf');
console.log('📄 Endereço 2:', endereco2);
// Resultado: "aqui/documentos/relatorio.pdf"
// 3️⃣ Subindo uma pasta (o ".." significa "pasta de cima")
const endereco3 = path.join('..', 'backup', 'dados.json');
console.log('💾 Endereço 3:', endereco3);
// Resultado: "pasta-de-cima/backup/dados.json"
// 4️⃣ Endereço bem grande (como montar um endereço completo)
const endereco4 = path.join('usuarios', 'joao', 'projetos', 'meu-app', 'index.js');
console.log('🚀 Endereço 4:', endereco4);
// O path.join() monta tudo certinho automaticamente!
❌ Jeito errado (quebra!):
☝️ Isso quebra no Windows porque ele usa \\ em vez de /
✅ Jeito certo (sempre funciona!):
☝️ O path.join() é inteligente e escolhe a barra certa!
É como pedir o endereço completo! 📮 Você fala "casa do João" e ele te dá "Rua das Flores, 123, São Paulo, SP, Brasil"
// caminho-absoluto.js
const path = require('path');
console.log('=== CAMINHOS ABSOLUTOS ===\n');
// Descobrir onde estamos agora
console.log('📂 Pasta atual:', process.cwd());
console.log('');
// Resolver caminho relativo para absoluto
const absoluto1 = path.resolve('documentos', 'arquivo.txt');
console.log('📄 Arquivo 1 (absoluto):', absoluto1);
// Resultado: /caminho/completo/para/sua/pasta/atual/documentos/arquivo.txt
// Resolver múltiplos caminhos
const absoluto2 = path.resolve('..', 'backup', 'dados.json');
console.log('📄 Arquivo 2 (absoluto):', absoluto2);
// Resultado: /caminho/completo/para/pasta/pai/backup/dados.json
// Se já for absoluto, retorna como está
const absoluto3 = path.resolve('/home/usuario/arquivo.txt');
console.log('📄 Arquivo 3 (já absoluto):', absoluto3);
// Resultado: /home/usuario/arquivo.txt
// Exemplo prático: arquivo de configuração
const configPath = path.resolve('config', 'database.json');
console.log('⚙️ Configuração:', configPath);
console.log('\n=== DIFERENÇA ENTRE JOIN E RESOLVE ===');
console.log('join("docs", "file.txt") :', path.join('docs', 'file.txt'));
console.log('resolve("docs", "file.txt"):', path.resolve('docs', 'file.txt'));
Como "quebrar" um caminho em pedaços úteis
// extrair-info.js
const path = require('path');
console.log('=== EXTRAINDO INFORMAÇÕES ===\n');
// Caminho de exemplo
const arquivoCompleto = '/home/usuario/projetos/meu-app/src/index.js';
console.log('📁 Caminho original:', arquivoCompleto);
console.log('');
// Extrair o nome do arquivo (com extensão)
const nomeArquivo = path.basename(arquivoCompleto);
console.log('📄 Nome do arquivo:', nomeArquivo);
// Resultado: index.js
// Extrair o nome sem extensão
const nomeSemExtensao = path.basename(arquivoCompleto, '.js');
console.log('📝 Nome sem extensão:', nomeSemExtensao);
// Resultado: index
// Extrair a extensão
const extensao = path.extname(arquivoCompleto);
console.log('🏷️ Extensão:', extensao);
// Resultado: .js
// Extrair a pasta pai (diretório)
const pastaPai = path.dirname(arquivoCompleto);
console.log('📂 Pasta pai:', pastaPai);
// Resultado: /home/usuario/projetos/meu-app/src
console.log('\n=== EXEMPLO PRÁTICO ===');
// Função para analisar qualquer arquivo
function analisarArquivo(caminhoArquivo) {
console.log(`\n🔍 Analisando: ${caminhoArquivo}`);
console.log('─'.repeat(50));
console.log('📄 Nome completo :', path.basename(caminhoArquivo));
console.log('📝 Nome sem ext. :', path.basename(caminhoArquivo, path.extname(caminhoArquivo)));
console.log('🏷️ Extensão :', path.extname(caminhoArquivo));
console.log('📂 Pasta :', path.dirname(caminhoArquivo));
console.log('📍 Absoluto :', path.resolve(caminhoArquivo));
}
// Testar com diferentes arquivos
analisarArquivo('documento.pdf');
analisarArquivo('fotos/ferias.jpg');
analisarArquivo('../backup/dados.json');
analisarArquivo('C:\\Users\\João\\Desktop\\apresentacao.pptx');
Um programa que organiza arquivos por tipo usando path
// organizador-arquivos.js
const path = require('path');
const fs = require('fs').promises;
// Função para organizar arquivos por extensão
async function organizarArquivos() {
try {
console.log('📁 ORGANIZADOR DE ARQUIVOS\n');
// Ler todos os arquivos da pasta atual
const arquivos = await fs.readdir('.');
// Filtrar apenas arquivos (não pastas)
const apenasArquivos = [];
for (const item of arquivos) {
const stats = await fs.stat(item);
if (stats.isFile()) {
apenasArquivos.push(item);
}
}
console.log(`📋 Encontrados ${apenasArquivos.length} arquivos:`);
// Analisar cada arquivo
for (const arquivo of apenasArquivos) {
const extensao = path.extname(arquivo);
const nome = path.basename(arquivo, extensao);
const tamanho = (await fs.stat(arquivo)).size;
console.log(`\n📄 ${arquivo}`);
console.log(` 📝 Nome: ${nome}`);
console.log(` 🏷️ Tipo: ${extensao || '(sem extensão)'}`);
console.log(` 📏 Tamanho: ${tamanho} bytes`);
// Sugerir pasta de destino baseada na extensão
let pastaDestino;
switch (extensao.toLowerCase()) {
case '.jpg':
case '.png':
case '.gif':
pastaDestino = 'imagens';
break;
case '.pdf':
case '.doc':
case '.docx':
pastaDestino = 'documentos';
break;
case '.js':
case '.html':
case '.css':
pastaDestino = 'codigo';
break;
default:
pastaDestino = 'outros';
}
console.log(` 📂 Sugestão: mover para pasta "${pastaDestino}"`);
// Mostrar como seria o caminho final
const caminhoFinal = path.join(pastaDestino, arquivo);
console.log(` 📍 Caminho final: ${caminhoFinal}`);
}
console.log('\n✅ Análise concluída!');
console.log('💡 Dica: Este é apenas um exemplo. Para mover os arquivos de verdade,');
console.log(' você precisaria usar fs.rename() ou fs.copyFile().');
} catch (error) {
console.error('❌ Erro:', error.message);
}
}
// Executar o organizador
organizarArquivos();
path.extname() para identificar tipos de arquivopath.basename() para extrair nomespath.join() para criar novos caminhospath.join() em vez de concatenar stringspath.resolve() quando precisar de caminhos absolutos__dirname para referenciar a pasta do seu script'pasta' + '/' + 'arquivo' (quebra no Windows)'C:\\pasta\\arquivo' (quebra no Linux/Mac)// Pasta onde está o seu script
console.log('Script está em:', __dirname);
// Arquivo atual (com nome)
console.log('Arquivo atual:', __filename);
// Pasta de trabalho atual
console.log('Pasta de trabalho:', process.cwd());
// Separador do sistema (/ ou \\)
console.log('Separador:', path.sep);
Agora vamos colocar a mão na massa! Estes exercícios vão te ajudar a praticar tudo que aprendemos sobre módulos, arquivos e caminhos. Não se preocupe se parecer difícil no início - vamos explicar cada linha de código!
exercicios-aula2C:\Users\SeuNome\Desktop\exercicios-aula2>dir (Windows) ou ls (Mac/Linux) no terminal, deve mostrar uma pasta vaziacode.visualstudio.comcd Desktop\exercicios-aula2 para navegarO que vamos fazer: Criar um sistema que salva mensagens em um arquivo de log. É como um "diário" do seu programa - tudo que acontece fica registrado!
// logger.js - Sistema de Logger para nossa aplicação
// 1. IMPORTAÇÕES - Trazendo as ferramentas que vamos usar
const fs = require('fs').promises; // Sistema de arquivos (jeito moderno que não trava)
const path = require('path'); // Manipulação de caminhos
// 2. CLASSE LOGGER - Nossa "fábrica" de logs
class Logger {
// CONSTRUTOR - Executa quando criamos um novo Logger
constructor(logFile = 'app.log') {
// __dirname = pasta atual do arquivo
// path.join = junta caminhos de forma segura
this.logFile = path.join(__dirname, logFile);
console.log(`📝 Logger criado! Arquivo: ${this.logFile}`);
}
// MÉTODO PRINCIPAL - Escreve qualquer tipo de log
async log(message, level = 'INFO') {
// Cria um "carimbo de data e hora" (tipo: 2024-01-15 às 10:30:45)
const timestamp = new Date().toISOString(); // Pega a data/hora atual e transforma em texto
// Monta a linha do log: [DATA] NÍVEL: MENSAGEM
const logEntry = `[${timestamp}] ${level}: ${message}\n`;
try {
// appendFile = "cola" no final do arquivo (como escrever no final de um caderno)
await fs.appendFile(this.logFile, logEntry);
console.log(`✅ Log salvo: ${level} - ${message}`);
} catch (error) {
console.error('❌ Erro ao escrever log:', error.message);
}
}
// MÉTODO DE CONVENIÊNCIA - Para logs informativos
async info(message) {
await this.log(message, 'INFO');
}
// MÉTODO DE CONVENIÊNCIA - Para logs de erro
async error(message) {
await this.log(message, 'ERROR');
}
// MÉTODO EXTRA - Para logs de aviso
async warn(message) {
await this.log(message, 'WARN');
}
}
// EXPORTA a classe para outros arquivos usarem
module.exports = Logger;
Vamos criar um "explorador" que encontra todos os arquivos dentro de uma pasta e suas subpastas. É como um "buscar arquivos" do Windows, mas feito por nós!
// fileExplorer.js - Explorador de arquivos recursivo
// IMPORTAÇÕES - Ferramentas que vamos usar
const fs = require('fs').promises; // Sistema de arquivos (versão Promise)
const path = require('path'); // Manipulação de caminhos
// FUNÇÃO PRINCIPAL - Lista todos os arquivos recursivamente
async function listarArquivos(diretorio) {
console.log(`🔍 Explorando: ${diretorio}`);
// Array para guardar todos os arquivos encontrados
const arquivos = [];
try {
// Lê o conteúdo do diretório (lista tudo que tem dentro)
const items = await fs.readdir(diretorio);
console.log(`📂 Encontrados ${items.length} itens em: ${diretorio}`);
// Para cada item encontrado...
for (const item of items) {
// Monta o caminho completo do item
const fullPath = path.join(diretorio, item);
// Pega informações sobre o item (é pasta ou arquivo?)
const stats = await fs.stat(fullPath);
// Se for uma pasta (diretório)...
if (stats.isDirectory()) {
console.log(`📁 Pasta encontrada: ${item}`);
// RECURSÃO: a função chama ela mesma (como bonecas russas, uma dentro da outra)
const subArquivos = await listarArquivos(fullPath);
// Adiciona todos os arquivos da subpasta ao nosso array
// O "..." espalha os elementos (como despejar uma caixa dentro de outra)
arquivos.push(...subArquivos);
} else {
// Se for um arquivo, adiciona ao array
console.log(`📄 Arquivo encontrado: ${item}`);
arquivos.push(fullPath);
}
}
} catch (error) {
// Se der erro (pasta não existe, sem permissão, etc.)
console.error(`❌ Erro ao explorar ${diretorio}:`, error.message);
}
return arquivos;
}
// FUNÇÃO AUXILIAR - Mostra os resultados de forma organizada
function mostrarResultados(arquivos) {
console.log('\n📊 RELATÓRIO FINAL:');
console.log(`Total de arquivos encontrados: ${arquivos.length}`);
if (arquivos.length > 0) {
console.log('\n📋 Lista de arquivos:');
arquivos.forEach((arquivo, index) => {
console.log(`${index + 1}. ${arquivo}`);
});
}
}
// EXPORTA as funções para outros arquivos usarem
module.exports = {
listarArquivos,
mostrarResultados
};
1. Crie um arquivo de teste (test-explorer.js):
// test-explorer.js - Teste do explorador de arquivos
// Importa nossas funções
const { listarArquivos, mostrarResultados } = require('./fileExplorer');
const path = require('path');
// Função principal de teste
async function testarExplorador() {
console.log('🚀 Iniciando teste do Explorador de Arquivos...');
// Testa com a pasta atual (onde está o arquivo)
const pastaAtual = __dirname;
console.log(`📂 Pasta a ser explorada: ${pastaAtual}`);
try {
// Executa a exploração
const arquivos = await listarArquivos(pastaAtual);
// Mostra os resultados
mostrarResultados(arquivos);
console.log('\n✅ Teste concluído com sucesso!');
} catch (error) {
console.error('❌ Erro durante o teste:', error.message);
}
}
// Executa o teste
testarExplorador();
2. Execute no terminal:
# Execute o teste
node test-explorer.js
3. Exemplo de resultado:
🚀 Iniciando teste do Explorador de Arquivos...
📂 Pasta a ser explorada: C:\sua\pasta
🔍 Explorando: C:\sua\pasta
📂 Encontrados 3 itens em: C:\sua\pasta
📄 Arquivo encontrado: logger.js
📄 Arquivo encontrado: fileExplorer.js
📄 Arquivo encontrado: test-explorer.js
📊 RELATÓRIO FINAL:
Total de arquivos encontrados: 3
✅ Teste concluído com sucesso!
Tente modificar o código para:
Vamos criar um sistema completo para a Padaria Doce Sabor usando TUDO que aprendemos nesta aula: módulos, arquivos, caminhos e organização de código. Este será nosso primeiro projeto "real"!
Primeiro, vamos criar uma estrutura organizada. É como organizar uma casa - cada coisa tem seu lugar!
mkdir padaria-doce-sabor (cria a pasta principal)cd padaria-doce-sabor# Comandos para criar a estrutura completa
mkdir src
mkdir src\models
mkdir src\controllers
mkdir src\utils
mkdir src\config
mkdir data
mkdir logs
mkdir tests
padaria-doce-sabor/
├── 📁 src/ ← Código principal
│ ├── 📁 models/ ← "Moldes" dos dados (Produto, Categoria)
│ │ ├── 📄 Product.js ← Define como é um produto
│ │ └── 📄 Category.js ← Define como é uma categoria
│ ├── 📁 controllers/ ← "Controladores" (lógica de negócio)
│ │ ├── 📄 productController.js ← Gerencia produtos
│ │ └── 📄 categoryController.js ← Gerencia categorias
│ ├── 📁 utils/ ← Ferramentas auxiliares
│ │ ├── 📄 logger.js ← Sistema de logs
│ │ └── 📄 fileHelper.js ← Ajuda com arquivos
│ └── 📁 config/ ← Configurações
│ └── 📄 database.js ← Config do "banco de dados"
├── 📁 data/ ← Dados salvos (JSON)
│ ├── 📄 products.json ← Lista de produtos
│ └── 📄 categories.json ← Lista de categorias
├── 📁 logs/ ← Arquivos de log
├── 📁 tests/ ← Testes do sistema
├── 📄 package.json ← Informações do projeto
└── 📄 app.js ← Arquivo principal
Antes de criar os arquivos de código, precisamos "avisar" ao Node.js que este é um projeto oficial!
O package.json é como o "documento de identidade" do nosso projeto.
Sem ele, o Node.js não consegue entender direito nosso sistema!
# Certifique-se de estar na pasta do projeto
cd padaria-doce-sabor
# Inicializar o projeto Node.js
npm init -y
O comando npm init -y criará automaticamente o arquivo package.json
com configurações padrão. O -y significa "sim para tudo"!
Foi criado o arquivo package.json na raiz do projeto com informações como:
Agora sim podemos criar nossos arquivos .js!
Vamos criar "moldes" para organizar nossos dados! É como ter uma ficha padrão para cada produto da padaria. 📋
🍞 Exemplo simples: Quando você vai comprar pão na padaria, o vendedor sempre pergunta as mesmas coisas:
💡 O molde é isso: uma "fichinha" que sempre tem os mesmos campos para preencher!
🍞 Vamos criar nossa "fichinha" de produto! Cada produto da padaria vai ter as mesmas informações.
Imagine que você tem uma fichinha para cada produto da padaria:
Vamos criar linha por linha, explicando cada pedacinho:
// src/models/Product.js
// 📝 Este arquivo é nossa "fichinha" de produto
// 🏗️ PASSO 1: Criamos a "classe" (o molde)
class Product {
// 🎯 PASSO 2: O "constructor" é como preencher a fichinha
// Quando alguém criar um produto, vai dar essas informações:
constructor(id, name, description, price, categoryId, imageUrl) {
// 📋 PASSO 3: Guardamos as informações que a pessoa deu
this.id = id; // 🔢 Número do produto (1, 2, 3...)
this.name = name; // 📝 Nome ("Pão Francês")
this.description = description; // 📖 Descrição ("Pão fresquinho")
this.price = price; // 💰 Preço (0.50)
this.categoryId = categoryId; // 📂 Tipo (1 = Pães)
this.imageUrl = imageUrl; // 📷 Foto ("pao.jpg")
// 🤖 PASSO 4: O computador preenche algumas coisas sozinho
this.available = true; // ✅ Está disponível? (sempre sim no início)
this.createdAt = new Date(); // 📅 Quando foi criado (agora)
this.updatedAt = new Date(); // 📅 Última vez que mudou (agora)
}
// 🎯 PASSO 5: Funções úteis para trabalhar com o produto
// 💾 Função para salvar no arquivo (transforma em JSON)
toJSON() {
// JSON é como uma "lista organizada" que o computador entende
return {
id: this.id,
name: this.name,
description: this.description,
price: this.price,
categoryId: this.categoryId,
imageUrl: this.imageUrl,
available: this.available,
createdAt: this.createdAt,
updatedAt: this.updatedAt
};
}
// ✏️ Função para mudar informações do produto
update(newData) {
// Só muda o que a pessoa mandou mudar
if (newData.name) this.name = newData.name; // Novo nome?
if (newData.description) this.description = newData.description; // Nova descrição?
if (newData.price) this.price = newData.price; // Novo preço?
if (newData.categoryId) this.categoryId = newData.categoryId; // Nova categoria?
if (newData.imageUrl) this.imageUrl = newData.imageUrl; // Nova foto?
if (newData.available !== undefined) this.available = newData.available; // Disponível?
// 📅 Sempre marca quando foi a última mudança
this.updatedAt = new Date();
}
// 💰 Função para mostrar o preço bonitinho (R$ 1,50)
getFormattedPrice() {
// Transforma 1.5 em "R$ 1,50"
return `R$ ${this.price.toFixed(2).replace('.', ',')}`;
}
// ✅ Função para ver se o produto está disponível
isAvailable() {
return this.available === true;
}
}
// 📤 PASSO 6: Deixa outros arquivos usarem esta "fichinha"
// É como emprestar o molde para outros arquivos
module.exports = Product;
Agora vamos criar um pão de verdade usando nosso molde:
// 🥖 PASSO 1: Pegar nosso molde de produto
const Product = require('./models/Product');
// 🥖 PASSO 2: Criar um pão francês usando o molde
const paoFrances = new Product(
1, // Número da fichinha
'Pão Francês', // Nome do pão
'Pão fresquinho do dia', // O que tem de especial
0.50, // Quanto custa (50 centavos)
1, // Que tipo é (1 = Pães)
'pao-frances.jpg' // Foto do pão
);
// 🎯 PASSO 3: Vamos ver como ficou!
console.log('Preço bonitinho:', paoFrances.getFormattedPrice()); // "R$ 0,50"
console.log('Está disponível?', paoFrances.isAvailable()); // true
// 🎉 Pronto! Nossa fichinha de pão está funcionando!
💡 O que aconteceu aqui?
Criamos uma "fichinha" de pão francês com todas as informações importantes. É como preencher uma etiqueta de produto na padaria!
🏷️ O que é uma Categoria?
É como as "seções" da padaria: Pães, Bolos, Doces, etc. Cada seção agrupa produtos parecidos!
🎯 PASSO 1: Criando o molde da "seção"
Vamos fazer uma fichinha para cada seção da padaria (Pães, Bolos, etc.)
// 📂 PASSO 1: Criando o molde de uma "seção" da padaria
class Category {
// 🏗️ PASSO 2: Função que roda quando criamos uma nova seção
constructor(id, name, description, icon) {
// 📝 Informações que a pessoa precisa dar:
this.id = id; // Número da seção (1, 2, 3...)
this.name = name; // Nome da seção ("Pães", "Bolos"...)
this.description = description; // O que tem nesta seção
this.icon = icon; // Emoji da seção (🍞, 🎂...)
// 🤖 Informações que o computador preenche sozinho:
this.active = true; // Seção está funcionando?
this.createdAt = new Date(); // Quando foi criada
this.productCount = 0; // Quantos produtos tem aqui
}
// 🎯 PASSO 3: Funções úteis para trabalhar com a seção
// 💾 Função para salvar no arquivo (transforma em JSON)
toJSON() {
// JSON é como uma "lista organizada" que o computador entende
return {
id: this.id,
name: this.name,
description: this.description,
icon: this.icon,
active: this.active,
createdAt: this.createdAt,
productCount: this.productCount
};
}
// ✏️ Função para mudar informações da seção
update(newData) {
// Só muda o que a pessoa mandou mudar
if (newData.name) this.name = newData.name; // Novo nome?
if (newData.description) this.description = newData.description; // Nova descrição?
if (newData.icon) this.icon = newData.icon; // Novo emoji?
if (newData.active !== undefined) this.active = newData.active; // Ativar/desativar?
}
// ➕ Função para quando colocamos um produto na seção
addProduct() {
this.productCount++; // Conta +1 produto
}
// ➖ Função para quando tiramos um produto da seção
removeProduct() {
if (this.productCount > 0) {
this.productCount--; // Conta -1 produto (se tiver algum)
}
}
}
// 📤 PASSO 4: Deixa outros arquivos usarem esta "fichinha de seção"
// module.exports = como colocar nossa "fichinha" numa "caixinha" para outros usarem
module.exports = Category;
Agora vamos criar a seção de pães da nossa padaria:
// 🍞 PASSO 1: Pegar nosso molde de seção
const Category = require('./models/Category');
// 🍞 PASSO 2: Criar a seção de pães
const secaoPaes = new Category(
1, // Número da seção
'Pães', // Nome da seção
'Pães frescos e quentinhos', // O que tem de especial
'🍞' // Emoji da seção
);
// 🎯 PASSO 3: Vamos colocar um produto na seção!
secaoPaes.addProduct(); // Colocamos 1 pão
console.log('Quantos produtos temos?', secaoPaes.productCount); // 1
// 🎉 Pronto! Nossa seção de pães está funcionando!
💡 O que aconteceu aqui?
Criamos uma "seção" da padaria e colocamos um produto nela. É como organizar os produtos em prateleiras!
🔧 O que é um FileHelper?
É como um "assistente" que nos ajuda a trabalhar com arquivos. Ele sabe ler, escrever e organizar arquivos!
// 🔧 Pegamos as ferramentas que vamos usar
const fs = require('fs').promises; // Para mexer com arquivos
const path = require('path'); // Para trabalhar com endereços
// 🛠️ Nosso assistente para arquivos
// static = funções que funcionam sem precisar criar um objeto primeiro
class FileHelper {
// 📖 PASSO 1: Função para LER um arquivo JSON (como ler uma receita)
static async readJSON(filePath) {
try {
// 📄 Lê o arquivo como se fosse um texto normal
const data = await fs.readFile(filePath, 'utf8');
// 🔄 JSON.parse = "tradutor" que transforma texto em informações que o computador entende
// É como pegar uma receita escrita à mão e digitar no computador!
return JSON.parse(data);
} catch (error) {
console.error('❌ Robô: "Ops! Não consegui ler este arquivo:", error);
return null; // Retorna "nada" se deu erro
}
}
// ✏️ PASSO 2: Função para ESCREVER um arquivo JSON (como escrever uma receita)
static async writeJSON(filePath, data) {
try {
// 🔄 JSON.stringify = "tradutor" que transforma informações do computador em texto
// É como pegar uma lista no computador e imprimir numa folha de papel!
const jsonData = JSON.stringify(data, null, 2);
// 💾 Salva o texto no arquivo (como guardar a receita numa gaveta)
await fs.writeFile(filePath, jsonData, 'utf8');
return true; // Deu certo!
} catch (error) {
console.error('❌ Robô: "Ops! Não consegui salvar este arquivo:", error);
return false; // Deu erro!
}
}
// 📁 Função para CRIAR uma pasta (se não existir)
static async ensureDirectory(dirPath) {
try {
// Cria a pasta (e todas as pastas "de dentro" se precisar)
// recursive = "vai criando pastas uma dentro da outra se precisar"
await fs.mkdir(dirPath, { recursive: true });
return true; // Deu certo!
} catch (error) {
console.error('❌ Ops! Não consegui criar a pasta:', error);
return false; // Deu erro!
}
}
}
// 📤 PASSO 4: Deixa outros arquivos usarem nosso "assistente de arquivos"
// module.exports = como colocar o assistente numa "caixinha" para outros usarem
module.exports = FileHelper;
💡 Para que serve isso?
Este assistente nos ajuda a salvar e carregar as informações da padaria (produtos, categorias) em arquivos no computador!
🔄 O que é JSON? É como uma "linguagem universal" que o computador entende. Como se fosse um "dicionário" que traduz nossas listas para o computador!
Agora vamos criar os controladores que irão gerenciar as operações dos produtos e categorias:
const Product = require('../models/Product');
const FileHelper = require('../utils/FileHelper');
const path = require('path');
class ProductController {
constructor() {
this.dataPath = path.join(__dirname, '..', 'data', 'products.json');
this.fileHelper = new FileHelper();
}
// Criar um novo produto
async createProduct(productData) {
try {
// Carregar produtos existentes
const products = await this.getAllProducts();
// Criar novo produto
const newProduct = new Product(
productData.name,
productData.price,
productData.category,
productData.description
);
// Adicionar à lista
products.push(newProduct);
// Salvar no arquivo
await this.fileHelper.writeJSON(this.dataPath, products);
console.log(`✅ Produto "${newProduct.name}" criado com sucesso!`);
return newProduct;
} catch (error) {
console.error('❌ Erro ao criar produto:', error.message);
throw error;
}
}
// Listar todos os produtos
async getAllProducts() {
try {
const products = await this.fileHelper.readJSON(this.dataPath);
return products || [];
} catch (error) {
console.log('📁 Arquivo de produtos não encontrado, criando novo...');
return [];
}
}
// Buscar produto por ID
async getProductById(id) {
try {
const products = await this.getAllProducts();
const product = products.find(p => p.id === id);
if (!product) {
throw new Error(`Produto com ID ${id} não encontrado`);
}
return product;
} catch (error) {
console.error('❌ Erro ao buscar produto:', error.message);
throw error;
}
}
// Atualizar produto
async updateProduct(id, updateData) {
try {
const products = await this.getAllProducts();
const productIndex = products.findIndex(p => p.id === id);
if (productIndex === -1) {
throw new Error(`Produto com ID ${id} não encontrado`);
}
// Atualizar dados
products[productIndex] = { ...products[productIndex], ...updateData };
// Salvar no arquivo
await this.fileHelper.writeJSON(this.dataPath, products);
console.log(`✅ Produto "${products[productIndex].name}" atualizado!`);
return products[productIndex];
} catch (error) {
console.error('❌ Erro ao atualizar produto:', error.message);
throw error;
}
}
// Deletar produto
async deleteProduct(id) {
try {
const products = await this.getAllProducts();
const productIndex = products.findIndex(p => p.id === id);
if (productIndex === -1) {
throw new Error(`Produto com ID ${id} não encontrado`);
}
const deletedProduct = products.splice(productIndex, 1)[0];
// Salvar no arquivo
await this.fileHelper.writeJSON(this.dataPath, products);
console.log(`🗑️ Produto "${deletedProduct.name}" deletado!`);
return deletedProduct;
} catch (error) {
console.error('❌ Erro ao deletar produto:', error.message);
throw error;
}
}
// Buscar produtos por categoria
async getProductsByCategory(categoryName) {
try {
const products = await this.getAllProducts();
return products.filter(p => p.category.toLowerCase() === categoryName.toLowerCase());
} catch (error) {
console.error('❌ Erro ao buscar produtos por categoria:', error.message);
throw error;
}
}
}
module.exports = ProductController;
const Category = require('../models/Category');
const FileHelper = require('../utils/FileHelper');
const path = require('path');
class CategoryController {
constructor() {
this.dataPath = path.join(__dirname, '..', 'data', 'categories.json');
this.fileHelper = new FileHelper();
}
// Criar nova categoria
async createCategory(categoryData) {
try {
const categories = await this.getAllCategories();
// Verificar se categoria já existe
const existingCategory = categories.find(c =>
c.name.toLowerCase() === categoryData.name.toLowerCase()
);
if (existingCategory) {
throw new Error(`Categoria "${categoryData.name}" já existe!`);
}
const newCategory = new Category(
categoryData.name,
categoryData.description
);
categories.push(newCategory);
await this.fileHelper.writeJSON(this.dataPath, categories);
console.log(`✅ Categoria "${newCategory.name}" criada com sucesso!`);
return newCategory;
} catch (error) {
console.error('❌ Erro ao criar categoria:', error.message);
throw error;
}
}
// Listar todas as categorias
async getAllCategories() {
try {
const categories = await this.fileHelper.readJSON(this.dataPath);
return categories || [];
} catch (error) {
console.log('📁 Arquivo de categorias não encontrado, criando novo...');
return [];
}
}
// Buscar categoria por ID
async getCategoryById(id) {
try {
const categories = await this.getAllCategories();
const category = categories.find(c => c.id === id);
if (!category) {
throw new Error(`Categoria com ID ${id} não encontrada`);
}
return category;
} catch (error) {
console.error('❌ Erro ao buscar categoria:', error.message);
throw error;
}
}
// Deletar categoria
async deleteCategory(id) {
try {
const categories = await this.getAllCategories();
const categoryIndex = categories.findIndex(c => c.id === id);
if (categoryIndex === -1) {
throw new Error(`Categoria com ID ${id} não encontrada`);
}
const deletedCategory = categories.splice(categoryIndex, 1)[0];
await this.fileHelper.writeJSON(this.dataPath, categories);
console.log(`🗑️ Categoria "${deletedCategory.name}" deletada!`);
return deletedCategory;
} catch (error) {
console.error('❌ Erro ao deletar categoria:', error.message);
throw error;
}
}
}
module.exports = CategoryController;
Vamos criar um sistema simples para registrar as operações do sistema:
const fs = require('fs').promises;
const path = require('path');
class Logger {
constructor() {
this.logPath = path.join(__dirname, '..', 'logs', 'system.log');
this.ensureLogDirectory();
}
// Garantir que o diretório de logs existe
async ensureLogDirectory() {
try {
const logDir = path.dirname(this.logPath);
await fs.mkdir(logDir, { recursive: true });
} catch (error) {
console.error('Erro ao criar diretório de logs:', error.message);
}
}
// Registrar log
async log(level, message, data = null) {
try {
const timestamp = new Date().toISOString();
const logEntry = {
timestamp,
level: level.toUpperCase(),
message,
data
};
const logLine = JSON.stringify(logEntry) + '\n';
await fs.appendFile(this.logPath, logLine);
// Também exibir no console
const emoji = this.getEmojiForLevel(level);
console.log(`${emoji} [${timestamp}] ${level.toUpperCase()}: ${message}`);
} catch (error) {
console.error('Erro ao escrever log:', error.message);
}
}
// Obter emoji para o nível do log
getEmojiForLevel(level) {
const emojis = {
info: 'ℹ️',
success: '✅',
warning: '⚠️',
error: '❌',
debug: '🐛'
};
return emojis[level.toLowerCase()] || '📝';
}
// Métodos de conveniência
async info(message, data = null) {
await this.log('info', message, data);
}
async success(message, data = null) {
await this.log('success', message, data);
}
async warning(message, data = null) {
await this.log('warning', message, data);
}
async error(message, data = null) {
await this.log('error', message, data);
}
async debug(message, data = null) {
await this.log('debug', message, data);
}
// Ler logs
async readLogs(lines = 50) {
try {
const content = await fs.readFile(this.logPath, 'utf8');
const logLines = content.trim().split('\n');
return logLines.slice(-lines).map(line => {
try {
return JSON.parse(line);
} catch {
return { message: line };
}
});
} catch (error) {
console.log('📁 Arquivo de log não encontrado');
return [];
}
}
}
module.exports = Logger;
Agora vamos criar o arquivo principal que irá demonstrar todo o sistema funcionando:
const ProductController = require('./controllers/productController');
const CategoryController = require('./controllers/categoryController');
const Logger = require('./utils/logger');
class PadariaSystem {
constructor() {
this.productController = new ProductController();
this.categoryController = new CategoryController();
this.logger = new Logger();
}
// Inicializar sistema
async init() {
try {
console.log('🍞 ===== SISTEMA DA PADARIA =====');
console.log('🚀 Inicializando sistema...');
await this.logger.info('Sistema da Padaria iniciado');
// Criar categorias padrão
await this.createDefaultCategories();
// Criar produtos de exemplo
await this.createSampleProducts();
// Demonstrar funcionalidades
await this.demonstrateFeatures();
console.log('\n✅ Sistema inicializado com sucesso!');
} catch (error) {
await this.logger.error('Erro ao inicializar sistema', { error: error.message });
console.error('❌ Erro ao inicializar:', error.message);
}
}
// Criar categorias padrão
async createDefaultCategories() {
console.log('\n📂 Criando categorias padrão...');
const defaultCategories = [
{ name: 'Pães', description: 'Pães frescos e artesanais' },
{ name: 'Doces', description: 'Doces e sobremesas deliciosas' },
{ name: 'Salgados', description: 'Salgados assados e fritos' },
{ name: 'Bebidas', description: 'Bebidas quentes e frias' }
];
for (const categoryData of defaultCategories) {
try {
await this.categoryController.createCategory(categoryData);
await this.logger.success(`Categoria criada: ${categoryData.name}`);
} catch (error) {
if (error.message.includes('já existe')) {
console.log(`⚠️ Categoria "${categoryData.name}" já existe`);
} else {
await this.logger.error(`Erro ao criar categoria ${categoryData.name}`, { error: error.message });
}
}
}
}
// Criar produtos de exemplo
async createSampleProducts() {
console.log('\n🥖 Criando produtos de exemplo...');
const sampleProducts = [
{ name: 'Pão Francês', price: 0.50, category: 'Pães', description: 'Pão francês tradicional' },
{ name: 'Pão de Açúcar', price: 4.50, category: 'Pães', description: 'Pão doce com açúcar cristal' },
{ name: 'Brigadeiro', price: 2.00, category: 'Doces', description: 'Brigadeiro tradicional' },
{ name: 'Coxinha', price: 3.50, category: 'Salgados', description: 'Coxinha de frango' },
{ name: 'Café Expresso', price: 2.50, category: 'Bebidas', description: 'Café expresso forte' }
];
for (const productData of sampleProducts) {
try {
await this.productController.createProduct(productData);
await this.logger.success(`Produto criado: ${productData.name}`);
} catch (error) {
await this.logger.error(`Erro ao criar produto ${productData.name}`, { error: error.message });
}
}
}
// Demonstrar funcionalidades
async demonstrateFeatures() {
console.log('\n🎯 Demonstrando funcionalidades...');
try {
// Listar todos os produtos
console.log('\n📋 Todos os produtos:');
const allProducts = await this.productController.getAllProducts();
allProducts.forEach(product => {
console.log(` • ${product.name} - R$ ${product.price.toFixed(2)} (${product.category})`);
});
// Listar todas as categorias
console.log('\n📂 Todas as categorias:');
const allCategories = await this.categoryController.getAllCategories();
allCategories.forEach(category => {
console.log(` • ${category.name}: ${category.description}`);
});
// Buscar produtos por categoria
console.log('\n🥖 Produtos da categoria "Pães":');
const paes = await this.productController.getProductsByCategory('Pães');
paes.forEach(product => {
console.log(` • ${product.name} - R$ ${product.price.toFixed(2)}`);
});
// Demonstrar atualização de produto
if (allProducts.length > 0) {
const firstProduct = allProducts[0];
console.log(`\n✏️ Atualizando produto "${firstProduct.name}"...`);
await this.productController.updateProduct(firstProduct.id, {
price: firstProduct.price + 0.10
});
}
await this.logger.success('Demonstração concluída com sucesso');
} catch (error) {
await this.logger.error('Erro durante demonstração', { error: error.message });
console.error('❌ Erro durante demonstração:', error.message);
}
}
// Exibir menu interativo
async showMenu() {
console.log('\n🍞 ===== MENU DO SISTEMA =====');
console.log('1. Listar todos os produtos');
console.log('2. Listar todas as categorias');
console.log('3. Buscar produtos por categoria');
console.log('4. Criar novo produto');
console.log('5. Criar nova categoria');
console.log('6. Ver logs do sistema');
console.log('0. Sair');
console.log('================================');
}
}
// Função principal
async function main() {
const sistema = new PadariaSystem();
await sistema.init();
// Exibir menu
await sistema.showMenu();
console.log('\n🎉 Obrigado por usar o Sistema da Padaria!');
console.log('💡 Para interação completa, implemente readline para menu interativo');
}
// Executar apenas se for o arquivo principal
if (require.main === module) {
main().catch(error => {
console.error('❌ Erro fatal:', error.message);
process.exit(1);
});
}
module.exports = PadariaSystem;
Vamos criar o arquivo de configuração do projeto:
{
"name": "sistema-padaria",
"version": "1.0.0",
"description": "Sistema completo para gerenciamento de padaria",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "node app.js",
"test": "node test.js"
},
"keywords": [
"padaria",
"nodejs",
"sistema",
"gerenciamento"
],
"author": "Aluno do Curso",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
}
}
cd sistema-padaria
node --version
Deve mostrar a versão do Node.js (ex: v18.17.0)
node app.js
ou
npm start
Vamos criar um arquivo de teste para verificar se tudo está funcionando:
const PadariaSystem = require('./app');
const ProductController = require('./controllers/productController');
const CategoryController = require('./controllers/categoryController');
const Logger = require('./utils/logger');
async function runTests() {
console.log('🧪 ===== EXECUTANDO TESTES =====');
try {
// Teste 1: Criar controllers
console.log('\n✅ Teste 1: Criando controllers...');
const productController = new ProductController();
const categoryController = new CategoryController();
const logger = new Logger();
console.log('✅ Controllers criados com sucesso!');
// Teste 2: Criar categoria
console.log('\n✅ Teste 2: Criando categoria de teste...');
const testCategory = await categoryController.createCategory({
name: 'Teste',
description: 'Categoria para testes'
});
console.log('✅ Categoria de teste criada!');
// Teste 3: Criar produto
console.log('\n✅ Teste 3: Criando produto de teste...');
const testProduct = await productController.createProduct({
name: 'Produto Teste',
price: 5.99,
category: 'Teste',
description: 'Produto para testes'
});
console.log('✅ Produto de teste criado!');
// Teste 4: Listar produtos
console.log('\n✅ Teste 4: Listando produtos...');
const products = await productController.getAllProducts();
console.log(`✅ ${products.length} produtos encontrados!`);
// Teste 5: Sistema completo
console.log('\n✅ Teste 5: Testando sistema completo...');
const sistema = new PadariaSystem();
await sistema.init();
console.log('✅ Sistema completo testado!');
console.log('\n🎉 ===== TODOS OS TESTES PASSARAM! =====');
console.log('✅ O sistema está funcionando perfeitamente!');
console.log('🚀 Você pode executar: node app.js');
} catch (error) {
console.error('❌ Erro durante os testes:', error.message);
console.error('🔧 Verifique se todos os arquivos foram criados corretamente');
}
}
// Executar testes
if (require.main === module) {
runTests();
}
module.exports = runTests;
🏆 Parabéns! Você criou um sistema completo de gerenciamento para padaria!
Aprenda a criar seu primeiro servidor web com Express.js
Ir para próxima aula