Node.js é um ambiente de execução JavaScript no lado do servidor, permitindo que você use JavaScript para construir aplicações que rodam fora do navegador. Baseado no motor V8 do Google Chrome, ele permite a execução rápida e eficiente de código JavaScript no servidor.
Node.js é popular por seu alto desempenho, graças ao modelo de E/S não-bloqueante e baseado em eventos, que permite a gestão eficiente de múltiplas conexões simultâneas. Ele também unifica a linguagem usada tanto no frontend quanto no backend, simplificando o desenvolvimento. Além disso, possui um vasto ecossistema de pacotes e uma comunidade ativa que facilita a adição de funcionalidades e suporte.
Node.js foi criado por Ryan Dahl em 2009 para superar as limitações dos servidores web tradicionais, que não gerenciavam bem grandes volumes de conexões simultâneas. A solução foi criar um ambiente de execução com E/S não-bloqueante, o que tornou o Node.js ideal para aplicações escaláveis.
Apesar de ambos utilizarem JavaScript, o Node.js e o ambiente do navegador têm diferenças fundamentais. O Node.js é usado para operações no servidor, como manipulação de arquivos e redes, enquanto o navegador se concentra na interação com o DOM. No Node.js, o JavaScript tem acesso completo ao sistema, exigindo cuidados adicionais com segurança, enquanto no navegador, o JavaScript é executado em um ambiente seguro.
Para executar código no Node.js, você precisa primeiro instalá-lo em seu sistema. Após a instalação, você pode criar um arquivo JavaScript, por exemplo
app.js
, e escrever o código que deseja executar:console.log("Hello, Node.js!");Depois, no terminal, você pode executar esse código usando o comando:
node app.jsIsso irá executar o código dentro do arquivo
app.js
e exibir "Hello, Node.js!" no terminal.Se você quiser criar um servidor web simples, poderia escrever algo assim:
const http = require('http'); const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello, World!\n'); }); server.listen(3000, () => { console.log('Server running at http://localhost:3000/'); });E ao rodar
node app.js
, você terá um servidor rodando localmente, que responde com "Hello, World!" para qualquer requisição.
O Node.js é uma plataforma popular para desenvolver aplicações no lado do servidor. Uma das suas principais características é o suporte a módulos, que permitem dividir o código em partes reutilizáveis, organizadas e de fácil manutenção. No Node.js, existem dois sistemas principais de módulos: **CommonJS** e **ESM (ECMAScript Modules)**. Além disso, você pode criar e importar módulos personalizados, bem como utilizar a palavra-chave `global` para definir variáveis globais.O sistema de módulos CommonJS foi o primeiro a ser implementado no Node.js. Ele é amplamente utilizado e tem uma sintaxe simples para exportar e importar módulos.
- Exportando Módulos: Usamos
module.exports
ouexports
para exportar funções, objetos, ou valores.- Importando Módulos: Usamos
require
para importar um módulo.// Nome do arquivo: math.js function somar(a, b) { return a + b; } function subtrair(a, b) { return a - b; } // Exportando as funções module.exports = { somar, subtrair };// Nome do arquivo: app.js // Aqui estamos puxando o arquivo 'math.js' para dentro do 'app.js' const math = require('./math'); console.log(math.somar(2, 3)); // Saída: 5 console.log(math.subtrair(5, 3)); // Saída: 2O ESM é o sistema de módulos padrão definido na especificação ECMAScript (ES6+). Ele é mais moderno e também é compatível com os navegadores, o que torna o código mais consistente entre o frontend e o backend.
- Exportando Módulos: Usamos
export
para exportar funções, objetos ou valores.- Importando Módulos: Usamos
import
para importar módulos.// math.mjs export function somar(a, b) { return a + b; } export function subtrair(a, b) { return a - b; }// app.mjs import { somar, subtrair } from './math.mjs'; console.log(somar(2, 3)); // Saída: 5 console.log(subtrair(5, 3)); // Saída: 2
- Sintaxe: CommonJS usa
require
emodule.exports
, enquanto ESM usaimport
eexport
.- Suporte Nativo: CommonJS é o sistema de módulos padrão no Node.js, enquanto o ESM foi adicionado em versões mais recentes e requer o uso da extensão
.mjs
ou a definição de"type": "module"
nopackage.json
.- Assincronismo: ESM suporta importações assíncronas, o que permite carregar módulos de maneira mais eficiente.
Os módulos personalizados são simplesmente arquivos JavaScript que exportam funções, objetos ou valores que podem ser reutilizados em outras partes do seu código.
// utils.js function apresentar(nome) { return `Olá, ${nome}!`; } module.exports = apresentar;Importando e Usando o Módulo Personalizado:
// app.js const apresentar = require('./utils'); console.log(apresentar('Henrique')); // Saída: Olá, Henrique!Criando um Módulo Personalizado (ESM):
// utils.mjs export function apresentar(nome) { return `Olá, ${nome}!`; }Importando e Usando o Módulo Personalizado:
// app.mjs import { apresentar } from './utils.mjs'; console.log(apresentar('Rick')); // Saída: Olá, Rick!No Node.js,
global
é um objeto especial que pode ser usado para definir variáveis ou funções que estão disponíveis globalmente em toda a aplicação, semelhante ao objetowindow
no navegador.// Definindo uma variável global global.minhaVarGlobal = 'Este é um valor global'; console.log(global.minhaVarGlobal); // Saída: Este é um valor global // Definindo uma função global global.apresentar = function(nome) { return `Olá, ${nome}!`; }; console.log(global.apresentar('Node.js')); // Saída: Olá, Node.js!
- Evitar Conflitos: Como as variáveis e funções no objeto
global
são acessíveis em toda a aplicação, isso pode causar conflitos de nome e tornar o código mais difícil de depurar.- Boa Prática: É uma boa prática evitar o uso de
global
e preferir passar variáveis e funções explicitamente como argumentos ou importá-las de módulos específicos.Você pode aprender mais sobre no artigo: MDN - Modules
O NPM (Node Package Manager) é a ferramenta padrão para gerenciar pacotes no ecossistema Node.js. Ele permite que você instale, compartilhe e gerencie dependências (bibliotecas e ferramentas) que seu projeto precisa. Além disso, o NPM facilita a criação de scripts para automatizar tarefas e suporta a criação e publicação de pacotes. Neste guia, exploraremos detalhadamente os conceitos de npx, Versionamento Semântico, instalações globais e locais, atualização de pacotes, execução de scripts, workspaces e a criação de pacotes.O
npx
é uma ferramenta que vem com o NPM e permite executar pacotes diretamente da linha de comando sem instalá-los globalmente no seu sistema. É útil para testar pacotes ou executar comandos únicos.# Usando npx para criar um novo projeto React npx create-react-app meu-projeto
npx
baixa e executa o pacotecreate-react-app
temporariamente.- O comando cria um novo diretório chamado
meu-projeto
com uma aplicação React configurada.- Sem necessidade de instalação global: O
create-react-app
não precisa ser instalado globalmente, economizando espaço e evitando conflitos com outras versões.
- Executa pacotes temporariamente: Ideal para usar ferramentas sem poluir o ambiente global.
- Versão mais recente: Sempre usa a versão mais atual do pacote.
O Versionamento Semântico (SemVer) é um sistema para versionar pacotes, composto por três números:
MAJOR.MINOR.PATCH
."dependencies": { "express": "^4.17.1" }Explicação:
4
(MAJOR): Mudanças que quebram a compatibilidade. Atualizações que podem exigir alterações no seu código.17
(MINOR): Novas funcionalidades que são compatíveis com versões anteriores. Adições que não quebram a compatibilidade.1
(PATCH): Correções de bugs que não afetam a compatibilidade. Atualizações que apenas resolvem problemas sem introduzir novas funcionalidades.
^4.17.1
permite atualizações para4.18.0
ou4.17.2
, mas não para5.0.0
.~4.17.1
permite atualizações para4.17.2
, mas não para4.18.0
.
- Controle de Compatibilidade: Garante que as atualizações de dependências não quebrem seu código.
- Gestão de Dependências: Ajuda a escolher quando adotar novas funcionalidades ou aplicar correções de bugs.
Você pode instalar pacotes no nível do projeto (local) ou no nível do sistema (global).
Instalação Local: O pacote é instalado no diretório
node_modules
do seu projeto. Usado para dependências específicas do projeto.# Instalando o pacote 'lodash' localmente npm install lodash
Explicação:
- O pacote
lodash
é instalado na pastanode_modules
do projeto.- Adicionado ao arquivo
package.json
como uma dependência local.Instalação Global: O pacote é instalado em uma localização global no seu sistema, acessível de qualquer lugar. Usado para ferramentas de linha de comando.
# Instalando o pacote 'nodemon' globalmente npm install -g nodemon
Explicação:
- O pacote
nodemon
é instalado globalmente, permitindo que você o execute de qualquer diretório.- É útil para ferramentas que você usa em múltiplos projetos ou diretamente na linha de comando.
Manter suas dependências atualizadas é crucial para segurança e funcionalidade.
# Atualizando o pacote 'lodash' para a versão mais recente permitida pela SemVer npm update lodash
Explicação:
- Atualiza o pacote
lodash
para a versão mais recente compatível com a especificada empackage.json
.# Atualizando todas as dependências do projeto npm update
Explicação:
- Atualiza todos os pacotes listados no
package.json
para a versão mais recente permitida pela SemVer.# Atualizando para a última versão disponível, mesmo que quebre a compatibilidade npm install lodash@latest
Explicação:
- Instala a versão mais recente do pacote
lodash
, ignorando a compatibilidade com a versão especificada anteriormente.No
package.json
, você pode definir scripts personalizados para automatizar tarefas."scripts": { "start": "node app.js", "test": "jest", "build": "webpack --config webpack.config.js" }Explicação:
start
: Executanode app.js
para iniciar o aplicativo.test
: Executajest
para rodar testes automatizados.build
: Executawebpack
para construir o projeto usando uma configuração específica.# Executando o script 'start' npm run start # Executando o script 'build' npm run buildExplicação:
npm run start
enpm run build
executam os scripts definidos nopackage.json
.- O script
start
pode ser executado apenas comnpm start
(semrun
).Os workspaces permitem gerenciar múltiplos pacotes em um único repositório (monorepo).
{ "name": "meu-monorepo", "private": true, "workspaces": [ "pacote-a", "pacote-b" ] }Explicação:
workspaces
: Lista os diretóriospacote-a
epacote-b
que contêm seus própriospackage.json
.private: true
: Garante que o repositório não será publicado no NPM.Benefícios:
- Gerenciamento Centralizado: Permite instalar e atualizar dependências para todos os pacotes de uma vez.
- Compartilhamento de Dependências: Facilita o compartilhamento de dependências entre pacotes.
Criar pacotes permite compartilhar código reutilizável com outros projetos ou com a comunidade.
- Inicialize o pacote:
npm init
- Gera um
package.json
onde você define o nome, versão, descrição e outras informações do pacote.
- Escreva o código:
- Crie os arquivos e implemente a funcionalidade do seu pacote.
- Teste o pacote:
- Teste seu código localmente para garantir que tudo funciona como esperado.
- Publique o pacote:
npm publish
- Publica seu pacote no repositório do NPM para que outros possam instalá-lo e usá-lo.
{ "name": "meu-pacote", "version": "1.0.0", "description": "Um pacote exemplo", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": ["exemplo", "npm", "pacote"], "author": "Seu Nome", "license": "ISC" }Explicação:
name
: Nome do pacote.version
: Versão inicial do pacote.description
: Descrição breve do que o pacote faz.main
: O ponto de entrada principal do pacote (arquivo principal).scripts
: Scripts relacionados ao desenvolvimento e teste.keywords
: Palavras-chave que ajudam na busca do pacote.author
elicense
: Informações sobre o autor e a licença do pacote.Você pode aprender mais sobre no artigo: NPM - docs
Erros de sistema em Node.js são aqueles que resultam de falhas no ambiente de execução, como problemas de I/O (entrada/saída), falhas de rede, ou falta de recursos do sistema. Esses erros geralmente ocorrem durante operações assíncronas, como ao tentar acessar arquivos, se conectar a bancos de dados, ou comunicar-se com APIs externas.
Imagine que você tem um servidor Node.js que precisa ler um arquivo de configuração no momento em que inicia. Se o arquivo não estiver disponível (por exemplo, foi excluído ou o caminho está errado), isso resultará em um erro de sistema.
const fs = require('fs'); // Tentativa de ler um arquivo que não existe no sistema fs.readFile('/path/to/config.json', 'utf8', (err, data) => { if (err) { // Código do erro 'ENOENT' significa 'Error NO ENTry', indicando que o arquivo não foi encontrado console.error('Erro ao ler o arquivo:', err.code, '-', err.message); process.exit(1); // Encerra o processo devido a um erro crítico } else { // O arquivo foi lido com sucesso console.log('Configurações carregadas:', data); } });
fs.readFile
tenta ler um arquivo de configuração.- Se o arquivo não for encontrado, um erro
ENOENT
será lançado, interrompendo o processo do servidor para evitar comportamento imprevisível.Erros especificados pelo usuário são aqueles que você, como desenvolvedor, define explicitamente no código para indicar que uma condição específica não foi atendida. Isso é útil para validar dados ou garantir que certas pré-condições sejam satisfeitas antes de prosseguir.
Considere que você tem uma função que deve dividir dois números, mas a divisão por zero é indefinida. Você pode lançar um erro especificado para evitar que isso aconteça.
function divide(a, b) { if (b === 0) { // Lança um erro se a tentativa for de dividir por zero throw new Error('Divisão por zero não é permitida!'); } return a / b; } try { // Tentativa de dividir 10 por 0, o que lançará um erro const result = divide(10, 0); console.log('Resultado:', result); } catch (err) { // Captura o erro e exibe uma mensagem amigável console.error('Erro ocorrido:', err.message); }
- A função
divide
verifica se o divisor é zero.- Se for zero, um erro é lançado com uma mensagem clara.
- O
try...catch
captura o erro e impede que o programa falhe sem controle.Asserções são condições que você espera que sejam verdadeiras durante a execução do código. No Node.js, você pode usar o módulo
assert
para garantir que essas condições sejam atendidas. Se uma asserção falhar, um erro de asserção é lançado, geralmente indicando que algo está muito errado no código.Vamos supor que você está desenvolvendo uma função para somar dois números. Você quer garantir que a função sempre retorne o resultado correto.
const assert = require('assert'); function add(a, b) { return a + b; } // Teste de asserção para garantir que a função 'add' está funcionando corretamente const result = add(2, 2); assert.strictEqual(result, 4, 'O resultado esperado é 4, mas obtivemos um valor diferente'); console.log('Todos os testes passaram!');
- A função
add
retorna a soma de dois números.assert.strictEqual
compara o resultado com o valor esperado.- Se o resultado não for 4, um erro de asserção é lançado com uma mensagem explicativa.
Erros de JavaScript são os erros padrão que ocorrem no código JavaScript, como
TypeError
,ReferenceError
,SyntaxError
, entre outros. Em Node.js, esses erros podem ocorrer por diversas razões, como chamar uma função inexistente, acessar variáveis indefinidas, ou escrever código com sintaxe incorreta.Imagine que você tenta chamar uma função que não foi definida.
try { // Tentativa de chamar uma função que não existe nonExistentFunction(); } catch (err) { // Captura o erro ReferenceError e exibe uma mensagem de erro console.error('Erro capturado:', err.name, '-', err.message); }
nonExistentFunction()
tenta chamar uma função que não foi declarada.- O
try...catch
captura oReferenceError
e exibe uma mensagem clara para o desenvolvedor.Exceções não capturadas ocorrem quando um erro é lançado e não é tratado dentro de um bloco
try...catch
. No Node.js, isso pode causar o término do processo, o que pode ser desastroso em um ambiente de produção. Para evitar isso, você pode usarprocess.on('uncaughtException')
, mas isso deve ser usado com cuidado.Suponha que você tenha um servidor que, por alguma razão, faz uma chamada a uma função que não existe, e esse erro não é capturado.
process.on('uncaughtException', (err) => { // Captura exceções não tratadas console.error('Exceção não capturada:', err.message); // Finaliza o processo para evitar inconsistências process.exit(1); }); // Função inexistente que causará um erro nonExistentFunction();
process.on('uncaughtException')
captura exceções que não foram tratadas.- É importante encerrar o processo para evitar que o servidor fique em um estado inconsistente.
Erros assíncronos ocorrem frequentemente em Node.js devido à natureza não bloqueante do ambiente. Ao trabalhar com callbacks, promessas, ou async/await, é crucial lidar corretamente com erros para evitar que o aplicativo falhe silenciosamente ou tenha comportamentos inesperados.
Suponha que você está lendo um arquivo que pode não existir.
const fs = require('fs'); // Tentativa de ler um arquivo que pode não existir fs.readFile('/path/to/file.txt', 'utf8', (err, data) => { if (err) { // Erro na leitura do arquivo console.error('Erro ao ler o arquivo:', err.message); return; } console.log('Conteúdo do arquivo:', data); });Agora, usando promessas para lidar com o mesmo caso.
const fs = require('fs').promises; async function readFile() { try { // Tentativa de ler um arquivo const data = await fs.readFile('/path/to/file.txt', 'utf8'); console.log('Conteúdo do arquivo:', data); } catch (err) { // Lida com o erro de forma assíncrona console.error('Erro ao ler o arquivo:', err.message); } } readFile();
fs.readFile
com callbacks e promessas demonstra duas abordagens para lidar com erros assíncronos.- Em ambos os casos, o erro é capturado e tratado para evitar falhas silenciosas.
A pilha de chamadas, ou stack trace, é um relatório que mostra a sequência de chamadas de função que levou a um erro. Em Node.js, a stack trace é extremamente útil para depuração, pois ajuda a identificar onde exatamente o erro ocorreu e como o fluxo do programa chegou a esse ponto.
Imagine que você tem várias funções aninhadas e uma delas lança um erro.
function functionOne() { functionTwo(); } function functionTwo() { functionThree(); } function functionThree() { // Lança um erro propositalmente throw new Error('Algo deu errado na função três!'); } try { functionOne(); } catch (err) { // Exibe a stack trace completa para ajudar na depuração console.error('Stack Trace:', err.stack); }
- As funções
functionOne
,functionTwo
, efunctionThree
são chamadas em sequência.- Quando
functionThree
lança um erro, a stack trace mostra todas as funções chamadas antes do erro ocorrer.Node.js inclui ferramentas de depuração que permitem aos desenvolvedores examinar o estado do programa durante a execução. O depurador pode ser usado para definir pontos de interrupção, inspecionar variáveis, e seguir o fluxo do código passo a passo. Isso é essencial para entender o comportamento do código e localizar erros.
Vamos ativar o depurador em um script Node.js.
function add(a, b) { debugger; // Define um ponto de interrupção return a + b; } const result = add(5, 3); console.log('Resultado:', result);
- O
debugger
é uma palavra-chave que, ao ser atingida, pausa a execução do código.- Ao rodar o código com
node inspect script.js
, o depurador é ativado, permitindo examinar o estado do programa no ponto de interrupção.Você pode aprender mais sobre no artigo: MDN - Error
Programação assíncrona é uma técnica que permite que um programa execute tarefas sem precisar esperar que uma tarefa seja concluída antes de iniciar a próxima. Em JavaScript, isso é fundamental para garantir que a aplicação continue responsiva, especialmente em ambientes de execução como navegadores e servidores.Um Event Emitter é um padrão que permite que objetos emitam eventos e outros objetos escutem e respondam a esses eventos. Esse padrão é amplamente utilizado em Node.js para a comunicação entre diferentes partes de uma aplicação.
// Importa o módulo EventEmitter const EventEmitter = require('events'); // Cria uma nova instância do EventEmitter const myEmitter = new EventEmitter(); // Define um ouvinte para o evento 'event' myEmitter.on('event', () => { console.log('Um evento ocorreu!'); }); // Emite o evento 'event' myEmitter.emit('event');
- Importamos o módulo
events
e criamos uma instância doEventEmitter
.- Usamos o método
on
para registrar um ouvinte para o evento chamado'event'
.- O ouvinte registrado executará uma função que imprime uma mensagem no console.
- Em seguida, usamos o método
emit
para emitir o evento'event'
, o que aciona o ouvinte registrado e imprime a mensagem.O Event Loop é um mecanismo que permite ao JavaScript executar código de forma assíncrona e gerenciar o tempo de execução de tarefas. Ele é responsável por garantir que o JavaScript continue a processar operações enquanto espera por operações assíncronas.
console.log('Início'); setTimeout(() => { console.log('Executando após 2 segundos'); }, 2000); console.log('Fim'); /* Saída: Início Fim Executando após 2 segundos */
- O
console.log('Início')
é executado imediatamente e imprime'Início'
.- O
setTimeout
agenda a execução de uma função após 2 segundos, mas não bloqueia o restante do código.- O
console.log('Fim')
é executado imediatamente após o início dosetTimeout
.- Após 2 segundos, a função dentro do
setTimeout
é executada, imprimindo'Executando após 2 segundos'
.
- O Event Loop garante que o código assíncrono seja executado após o código síncrono.
Escrever código assíncrono é essencial para garantir que operações demoradas não bloqueiem o restante do código. Existem várias maneiras de escrever código assíncrono em JavaScript: Promises,
async/await
, Callbacks, e métodos de temporização comosetTimeout
esetInterval
.Promises são objetos que representam a eventual conclusão (ou falha) de uma operação assíncrona e permitem encadear ações a serem realizadas após a conclusão da operação.
const minhaPromise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Operação concluída com sucesso!'); }, 2000); }); minhaPromise.then(result => { console.log(result); // Imprime: 'Operação concluída com sucesso!' }).catch(error => { console.log('Erro:', error); });
- Criamos uma nova Promise que resolve após 2 segundos com a mensagem
'Operação concluída com sucesso!'
.- Usamos o método
then
para definir o que fazer quando a Promise é resolvida.- Usamos o método
catch
para tratar possíveis erros.
async
eawait
são uma maneira de escrever código assíncrono que parece síncrono, tornando-o mais fácil de ler e entender.function espera(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function executar() { console.log('Início'); await espera(2000); // Espera 2 segundos console.log('2 segundos se passaram'); } executar();
- Definimos uma função
espera
que retorna uma Promise que resolve após um tempo especificado.- Usamos a palavra-chave
async
para criar uma função assíncronaexecutar
.- Dentro de
executar
, usamosawait
para esperar a resolução da Promise retornada porespera
.- O código parece síncrono, mas realmente está aguardando a Promise ser resolvida.
Callbacks são funções passadas como argumentos para outras funções e são executadas quando a operação assíncrona é concluída.
function executarDepoisDe(ms, callback) { setTimeout(callback, ms); } executarDepoisDe(2000, () => { console.log('2 segundos se passaram'); });
- Definimos a função
executarDepoisDe
, que recebe um tempo em milissegundos e uma funçãocallback
.- Usamos
setTimeout
para executar a funçãocallback
após o tempo especificado.- Passamos uma função de callback para
executarDepoisDe
que imprime uma mensagem após 2 segundos.
setTimeout
é usado para executar uma função após um atraso especificado em milissegundos.console.log('Início'); setTimeout(() => { console.log('Executado após 3 segundos'); }, 3000); console.log('Fim');
- O
console.log('Início')
é executado imediatamente.setTimeout
agenda a execução de uma função após 3 segundos.- O
console.log('Fim')
é executado imediatamente após osetTimeout
.- Após 3 segundos, a função do
setTimeout
é executada, imprimindo'Executado após 3 segundos'
.
setInterval
é usado para executar uma função repetidamente com um intervalo de tempo específico.let contador = 0; const intervalo = setInterval(() => { console.log('Executado a cada 2 segundos'); contador++; if (contador === 3) { clearInterval(intervalo); // Para o intervalo após 3 execuções } }, 2000);
- Definimos um contador para rastrear o número de execuções.
setInterval
executa a função a cada 2 segundos e incrementa o contador.- Quando o contador atinge 3, usamos
clearInterval
para parar o intervalo.
setImmediate
é usado para executar uma função imediatamente após o ciclo de eventos atual. Está disponível apenas em ambientes Node.js.console.log('Início'); setImmediate(() => { console.log('Executado imediatamente após o ciclo de eventos'); }); console.log('Fim');
- O
console.log('Início')
é executado imediatamente.setImmediate
agenda a execução de uma função assim que o ciclo de eventos atual termina.- O
console.log('Fim')
é executado imediatamente após osetImmediate
.- Após o ciclo de eventos, a função do
setImmediate
é executada, imprimindo'Executado imediatamente após o ciclo de eventos'
.
process.nextTick
é usado para executar uma função na próxima iteração do loop de eventos, antes que qualquer outro código assíncrono seja executado. Também disponível apenas em Node.js.console.log('Início'); process.nextTick(() => { console.log('Executado na próxima iteração do loop de eventos'); }); console.log('Fim');
- O
console.log('Início')
é executado imediatamente.process.nextTick
agenda a execução de uma função na próxima iteração do loop de eventos.- O
console.log('Fim')
é executado imediatamente após oprocess.nextTick
.- A função do
process.nextTick
é executada na próxima iteração do loop de eventos, imprimindo'Executado na próxima iteração do loop de eventos'
.Você pode aprender mais sobre no artigo: JavaScript info
No desenvolvimento com Node.js, a manipulação de arquivos é uma tarefa comum e essencial. Seja para ler dados de um arquivo, salvar informações ou monitorar mudanças em diretórios, o Node.js oferece diversas ferramentas e módulos que facilitam o trabalho com arquivos. Além dos recursos internos da própria linguagem, como
__dirname
e__filename
, o Node.js possui módulos comofs
epath
, que tornam as operações com o sistema de arquivos mais simples e eficientes. Além disso, a comunidade também contribuiu com pacotes de código aberto comofs-extra
echokidar
, que oferecem funcionalidades avançadas para manipulação de arquivos e diretórios.As constantes globais
__dirname
e__filename
são duas ferramentas fundamentais do Node.js, utilizadas para obter o caminho do diretório e o nome do arquivo atualmente em execução, respectivamente. Elas são especialmente úteis para trabalhar com sistemas de arquivos e para criar caminhos absolutos, independentemente de onde o script foi executado.A constante global
__dirname
retorna o caminho absoluto do diretório onde o script Node.js atualmente em execução está localizado. Ela é definida automaticamente pelo Node.js e está disponível em todos os módulos.
__dirname
é útil quando você precisa trabalhar com arquivos ou criar caminhos relativos ao diretório onde o seu script está localizado, em vez do diretório de onde o Node.js foi iniciado.// Exibe o caminho absoluto do diretório onde este script está localizado console.log('Diretório do script atual:', __dirname); // Exemplo: Criar um caminho absoluto para um arquivo localizado no mesmo diretório que o script const path = require('path'); const fullPathToFile = path.join(__dirname, 'meuArquivo.txt'); console.log('Caminho absoluto para o arquivo:', fullPathToFile);
- Independência de Plataforma:
__dirname
garante que o caminho do diretório seja obtido de forma consistente, independentemente do sistema operacional (Windows, macOS, Linux).- Confiabilidade: Como
__dirname
sempre aponta para o diretório onde o script reside, você pode usá-lo para construir caminhos de forma segura e confiável, evitando problemas com caminhos relativos que podem ocorrer dependendo de onde o Node.js é executado.A constante global
__filename
retorna o caminho absoluto do arquivo atualmente em execução. Ela inclui o nome do arquivo junto com o caminho completo.
__filename
é útil quando você precisa do caminho completo do script que está sendo executado, por exemplo, para registrar logs, ou para manipular o próprio script em tempo de execução.// Exibe o caminho absoluto do arquivo atualmente em execução console.log('Caminho completo do script atual:', __filename); // Exemplo: Separar o nome do arquivo e o caminho do diretório const path = require('path'); const fileName = path.basename(__filename); const directoryName = path.dirname(__filename); console.log('Nome do arquivo:', fileName); console.log('Diretório do arquivo:', directoryName);
- Extração de Informação: Usando
path.basename
epath.dirname
(do módulopath
), você pode facilmente extrair o nome do arquivo e o diretório do caminho completo obtido através de__filename
.- Contexto Completo:
__filename
é particularmente útil em cenários onde é necessário ter o contexto completo de onde o código está sendo executado, o que pode ser essencial para fins de depuração e análise.
- Descrição: Aponta para o diretório onde o arquivo JavaScript atual está localizado.
- Uso: Ideal para trabalhar com caminhos relativos ao próprio script.
- Descrição: Retorna o diretório de trabalho atual de onde o Node.js foi executado.
- Uso: Mais útil para caminhos relativos ao diretório de execução do comando Node.js.
console.log('__dirname:', __dirname); // Caminho do diretório onde este script está localizado console.log('process.cwd():', process.cwd()); // Diretório de onde o Node.js foi iniciado
- Contexto Diferente:
__dirname
é estático e se refere sempre ao diretório do script, enquantoprocess.cwd()
é dinâmico e depende de onde o Node.js foi executado. Saber quando usar um ou outro pode ajudar a evitar problemas com caminhos relativos.As constantes globais
__dirname
e__filename
são ferramentas poderosas no Node.js para trabalhar com caminhos de arquivos e diretórios. Elas garantem que você tenha acesso ao caminho absoluto do diretório e do arquivo em execução, o que é crucial para criar aplicações seguras e independentes de plataforma. Entender como e quando usá-las permite que você manipule caminhos de arquivos de forma eficaz e confiável, evitando erros comuns relacionados a caminhos relativos e execução em diferentes ambientes.O método
process.cwd()
é uma função do Node.js que retorna o diretório de trabalho atual da aplicação. Isso significa que ele fornece o caminho absoluto do diretório em que o Node.js foi executado. Esse método é particularmente útil quando você precisa trabalhar com arquivos e diretórios relativos ao diretório de execução da sua aplicação.O método
process.cwd()
retorna uma string que representa o caminho absoluto do diretório de trabalho atual da aplicação Node.js.cwd
significa "Current Working Directory" (Diretório de Trabalho Atual).Saber o diretório de trabalho atual é importante para garantir que você esteja acessando arquivos e diretórios no local correto, especialmente ao lidar com caminhos relativos.
// Importa o módulo 'fs' para trabalhar com o sistema de arquivos const fs = require('fs'); // Obtém o diretório de trabalho atual const currentWorkingDirectory = process.cwd(); // Exibe o diretório de trabalho atual console.log('Diretório de trabalho atual:', currentWorkingDirectory); // Exemplo de uso prático: Listar todos os arquivos e diretórios no diretório de trabalho atual fs.readdir(currentWorkingDirectory, (err, files) => { if (err) { return console.error('Erro ao ler o diretório:', err); } console.log('Conteúdo do diretório atual:', files); });
- Diretório de Trabalho: Quando você executa o comando
node script.js
em um terminal, oprocess.cwd()
retornará o diretório no qual você estava ao rodar esse comando.- Uso Prático: Como mostrado no exemplo, você pode usar o diretório de trabalho atual para realizar operações de leitura ou manipulação de arquivos, como listar o conteúdo do diretório.
- Descrição:
__dirname
é uma variável global que contém o caminho absoluto do diretório onde o script atualmente em execução está localizado.- Uso: Usado quando você quer saber onde o arquivo JavaScript atual está fisicamente localizado.
- Descrição:
process.cwd()
retorna o diretório de trabalho atual da aplicação, que é o diretório de onde o comando Node.js foi iniciado.- Uso: Usado quando você precisa trabalhar com caminhos relativos ao local de execução da aplicação.
console.log('__dirname:', __dirname); // Retorna o caminho do diretório onde este script está localizado console.log('process.cwd():', process.cwd()); // Retorna o diretório de trabalho atual de onde o script foi executado
- Contexto:
__dirname
é mais específico para o arquivo em execução, enquantoprocess.cwd()
é mais geral para a aplicação inteira. Dependendo do que você está fazendo, pode ser importante escolher entre um ou outro.Embora o
process.cwd()
retorne o diretório de trabalho atual, ele não permite alterá-lo diretamente. No entanto, você pode usar o métodoprocess.chdir()
para mudar o diretório de trabalho durante a execução de um programa Node.js.// Muda o diretório de trabalho para o diretório 'user/documents' process.chdir('/user/documents'); // Exibe o novo diretório de trabalho console.log('Novo diretório de trabalho:', process.cwd());
- Flexibilidade: Usar
process.chdir()
permite que seu programa mude seu contexto de trabalho, o que pode ser útil em scripts que precisam navegar por diferentes diretórios para executar tarefas.- Cuidado: Alterar o diretório de trabalho pode causar confusão, especialmente se outros módulos ou funções do seu código dependem do diretório original.
O método
process.cwd()
é uma ferramenta essencial para gerenciar o contexto de trabalho da sua aplicação Node.js. Ele permite que você saiba exatamente de onde a aplicação está sendo executada, o que é crucial ao lidar com caminhos relativos e manipulação de arquivos. Ao entender as diferenças entreprocess.cwd()
e__dirname
, e como usarprocess.chdir()
para alterar o diretório de trabalho, você pode escrever código mais robusto e flexível para lidar com diferentes cenários de execução.O módulo
path
do Node.js é utilizado para trabalhar com caminhos de arquivos e diretórios de forma segura e eficiente. Ele oferece uma variedade de métodos para manipular e resolver caminhos de arquivos, garantindo que você possa construir, normalizar e manipular caminhos de maneira consistente, independentemente do sistema operacional.
path.join
é utilizado para unir vários segmentos de caminho em um único caminho completo. Ele garante que os separadores corretos de diretório sejam usados, dependendo do sistema operacional.const path = require('path'); const directory = 'user'; const subdirectory = 'documents'; const filename = 'file.txt'; const fullPath = path.join(directory, subdirectory, filename); console.log('Caminho completo:', fullPath);
- Plataforma Cruzada:
path.join
garante que o caminho gerado seja válido em qualquer sistema operacional, seja Windows (que usa\
) ou Unix (que usa/
).- Facilidade de Uso: Ao invés de concatenar strings manualmente, o que pode gerar erros,
path.join
cuida dos detalhes para você.
path.resolve
resolve uma sequência de caminhos ou segmentos de caminho em um caminho absoluto. A resolução é feita da direita para a esquerda, então é possível "saltar" entre diretórios de forma eficiente.const path = require('path'); const fullPath = path.resolve('user', 'documents', 'file.txt'); console.log('Caminho absoluto:', fullPath);
- Caminho Absoluto:
path.resolve
começa a resolução a partir do diretório atual (ou de um caminho absoluto fornecido) e vai até a raiz do sistema, garantindo que o resultado seja sempre um caminho absoluto.- Controle Total: Você pode misturar caminhos relativos e absolutos para gerar um caminho final completamente resolvido.
path.basename
retorna a última parte de um caminho, que normalmente é o nome do arquivo. É possível também remover a extensão do arquivo no resultado.const path = require('path'); const fullPath = '/user/documents/file.txt'; const basename = path.basename(fullPath); console.log('Nome do arquivo:', basename); const basenameWithoutExtension = path.basename(fullPath, '.txt'); console.log('Nome do arquivo sem extensão:', basenameWithoutExtension);
- Nome do Arquivo: Este método é útil quando você precisa isolar o nome do arquivo de um caminho completo.
- Remover Extensão: Ao passar a extensão como segundo argumento, você pode obter apenas o nome do arquivo sem a extensão, o que é útil em muitas situações.
path.dirname
retorna o caminho do diretório pai de um caminho especificado, removendo o nome do arquivo.const path = require('path'); const fullPath = '/user/documents/file.txt'; const dirname = path.dirname(fullPath); console.log('Diretório pai:', dirname);
- Diretório Pai: Útil para obter o caminho do diretório que contém o arquivo, especialmente quando você precisa navegar pelo sistema de arquivos em relação ao local de um arquivo específico.
path.extname
retorna a extensão do arquivo de um caminho. A extensão é a parte do nome do arquivo a partir do último ponto até o final.const path = require('path'); const fullPath = '/user/documents/file.txt'; const extname = path.extname(fullPath); console.log('Extensão do arquivo:', extname);
- Identificação de Tipos de Arquivo: Saber a extensão de um arquivo pode ser crucial para determinar como ele deve ser tratado, por exemplo, ao decidir se deve ser lido como texto ou binário.
path.normalize
ajusta um caminho para um formato padrão, removendo segmentos redundantes como..
ou.
e corrigindo separadores de diretório.const path = require('path'); const messyPath = '/user/./documents/../documents/file.txt'; const normalizedPath = path.normalize(messyPath); console.log('Caminho normalizado:', normalizedPath);
- Simplificação:
path.normalize
é útil para garantir que o caminho seja o mais direto e simples possível, o que pode evitar erros em operações subsequentes.- Correção Automática: Ele corrige automaticamente quaisquer problemas comuns em caminhos, como múltiplos separadores consecutivos ou segmentos que não são necessários.
O módulo
path
do Node.js é uma ferramenta essencial para manipulação de caminhos de arquivos e diretórios de forma segura, consistente e independente de plataforma. Desde a construção e resolução de caminhos até a extração de partes específicas como nomes de arquivos ou extensões,path
oferece uma solução robusta para lidar com caminhos de maneira eficiente. Com a prática, essas operações se tornarão naturais, permitindo que você manipule caminhos de arquivos e diretórios com confiança em qualquer ambiente Node.js.O módulo
fs
(abreviação de "file system") do Node.js é um dos módulos centrais mais importantes, permitindo a interação com o sistema de arquivos de maneira direta e eficaz. Ele oferece uma ampla gama de funções para ler, escrever, abrir, fechar, renomear, excluir arquivos, entre outras operações. Abaixo, exploraremos as principais funcionalidades deste módulo, com exemplos completos e comentados para ajudar na compreensão.
fs.readFile
é usado para ler o conteúdo de um arquivo de forma assíncrona. Essa função carrega o conteúdo do arquivo completo na memória antes de disponibilizá-lo ao callback.const fs = require('fs'); fs.readFile('example.txt', 'utf8', (err, data) => { if (err) { console.error('Erro ao ler o arquivo:', err); return; } console.log('Conteúdo do arquivo:', data); });
- Codificação: No exemplo, a codificação
utf8
é especificada, garantindo que o conteúdo seja retornado como uma string legível. Se não for especificada, o conteúdo será retornado como um buffer.- Assíncrono: A função é assíncrona, então outras operações podem continuar sendo executadas enquanto o arquivo é lido.
fs.writeFile
permite escrever dados em um arquivo de forma assíncrona. Se o arquivo já existir, seu conteúdo será substituído; caso contrário, o arquivo será criado.const fs = require('fs'); const data = 'Este é o conteúdo a ser escrito no arquivo.'; fs.writeFile('output.txt', data, 'utf8', (err) => { if (err) { console.error('Erro ao escrever no arquivo:', err); return; } console.log('Arquivo escrito com sucesso!'); });
- Criação/Substituição:
fs.writeFile
cria um novo arquivo ou substitui o conteúdo de um arquivo existente.- Codificação: A codificação
utf8
garante que o conteúdo seja escrito como uma string. Se omitir essa codificação, os dados serão escritos como bytes brutos.
fs.appendFile
é usado para adicionar dados ao final de um arquivo existente, em vez de substituí-lo. Se o arquivo não existir, ele será criado.const fs = require('fs'); const additionalData = '\nEste texto será adicionado ao final do arquivo.'; fs.appendFile('output.txt', additionalData, 'utf8', (err) => { if (err) { console.error('Erro ao adicionar conteúdo ao arquivo:', err); return; } console.log('Conteúdo adicionado com sucesso!'); });
- Preservação de Dados: Ao contrário de
fs.writeFile
, que substitui o conteúdo,fs.appendFile
preserva o conteúdo existente, apenas adicionando novos dados ao final.
fs.rename
permite renomear um arquivo ou movê-lo para outro diretório. Se o novo nome incluir um caminho diferente, o arquivo será movido.const fs = require('fs'); fs.rename('output.txt', 'new_output.txt', (err) => { if (err) { console.error('Erro ao renomear o arquivo:', err); return; } console.log('Arquivo renomeado com sucesso!'); });
- Renomear e Mover:
fs.rename
pode ser usado tanto para renomear quanto para mover arquivos, dependendo do caminho fornecido.
fs.unlink
é usado para excluir um arquivo. Esta operação é permanente e remove o arquivo do sistema de arquivos.const fs = require('fs'); fs.unlink('new_output.txt', (err) => { if (err) { console.error('Erro ao excluir o arquivo:', err); return; } console.log('Arquivo excluído com sucesso!'); });
- Permanente: A exclusão é permanente, portanto, certifique-se de que o arquivo realmente precisa ser removido antes de usar essa função.
fs.readdir
permite ler o conteúdo de um diretório, retornando uma lista de nomes de arquivos e subdiretórios.const fs = require('fs'); fs.readdir('.', (err, files) => { if (err) { console.error('Erro ao ler o diretório:', err); return; } console.log('Conteúdo do diretório:', files); });
- Exploração de Diretórios: Essa função é útil para listar arquivos e pastas em um diretório, permitindo operações como iteração ou manipulação dos itens.
Embora métodos assíncronos sejam preferidos na maioria dos casos,
fs.existsSync
é uma função síncrona que verifica se um arquivo ou diretório existe.const fs = require('fs'); if (fs.existsSync('output.txt')) { console.log('O arquivo existe.'); } else { console.log('O arquivo não existe.'); }
- Síncrono: Como é uma função síncrona, ela bloqueia o processo até que a verificação seja concluída. Deve ser usada com cautela em ambientes de produção, onde o desempenho é crítico.
O módulo
fs
do Node.js é extremamente poderoso e versátil, oferecendo uma gama completa de operações para manipulação de arquivos e diretórios. A partir de funções básicas, como leitura e escrita, até operações mais avançadas, como renomear e excluir arquivos,fs
é uma ferramenta essencial para qualquer desenvolvedor Node.js. Com a prática, essas operações tornam-se ferramentas poderosas no seu arsenal de desenvolvimento, permitindo uma manipulação eficaz e eficiente do sistema de arquivos.Quando se trata de manipulação de arquivos no Node.js, além dos módulos nativos como
fs
epath
, a comunidade Node.js oferece pacotes de código aberto que expandem e simplificam muitas dessas operações. Esses pacotes adicionam funcionalidades adicionais, facilitam o trabalho com arquivos e diretórios, e permitem uma integração mais fluida com o sistema de arquivos. Abaixo estão alguns dos pacotes mais populares e suas funcionalidades detalhadas.O pacote
glob
permite buscar arquivos no sistema de arquivos que correspondam a padrões específicos (chamados de "globs"). Esses padrões são semelhantes à expansão de arquivos usada em shells Unix, permitindo, por exemplo, encontrar todos os arquivos com uma determinada extensão ou nome em uma estrutura de diretórios.const glob = require('glob'); // Encontra todos os arquivos .js no diretório atual glob('*.js', (err, files) => { if (err) { console.error('Erro ao buscar arquivos:', err); return; } console.log('Arquivos encontrados:', files); });
- Flexibilidade:
glob
permite usar padrões poderosos para buscar arquivos em diretórios complexos. Por exemplo, o padrão**/*.js
pode ser usado para encontrar todos os arquivos JavaScript em uma árvore de diretórios.- Praticidade: Este pacote é útil para tarefas como busca de arquivos para processamento em massa, linting ou compilação.
globby
é uma versão mais avançada e moderna doglob
. Ele suporta Promises, o que facilita a escrita de código assíncrono e oferece mais funcionalidades, como a capacidade de lidar com múltiplos padrões ao mesmo tempo e manipular diretórios com mais flexibilidade.const globby = require('globby'); // Encontra todos os arquivos .js e .txt no diretório atual usando Promises (async () => { const paths = await globby(['*.js', '*.txt']); console.log('Arquivos encontrados:', paths); })();
- Promessas e Async/Await:
globby
é completamente compatível com Promises, o que facilita a integração em fluxos de trabalho assíncronos. Isso torna o código mais limpo e gerenciável.- Várias Funções: Além de buscar arquivos,
globby
pode ser configurado para manipular links simbólicos, retornar diretórios ou até mesmo excluir arquivos após serem encontrados.
fs-extra
é uma extensão do módulo nativofs
do Node.js. Ele adiciona funções adicionais que são frequentemente necessárias, mas que não estão incluídas no módulofs
padrão. Isso inclui operações comuns, como copiar, mover e remover arquivos e diretórios, com suporte nativo a Promises.const fs = require('fs-extra'); // Copia um arquivo de 'source.txt' para 'destination.txt' fs.copy('source.txt', 'destination.txt') .then(() => { console.log('Arquivo copiado com sucesso!'); }) .catch(err => { console.error('Erro ao copiar o arquivo:', err); });
- Facilidade de Uso: Com
fs-extra
, você pode realizar operações complexas de arquivos com menos código e maior clareza.- Funcionalidades Adicionais:
fs-extra
inclui métodos comoensureDir()
para garantir que um diretório existe (criando-o se necessário),emptyDir()
para esvaziar um diretório, entre outros. Isso simplifica muitas tarefas comuns que exigiriam várias etapas comfs
.
chokidar
é um pacote poderoso para observar mudanças em arquivos e diretórios. Ele permite monitorar o sistema de arquivos em tempo real e executar ações quando certos eventos ocorrem, como a criação, modificação ou exclusão de arquivos.const chokidar = require('chokidar'); // Observa o diretório atual por mudanças const watcher = chokidar.watch('.', { ignored: /(^|[\/\\])\../, // Ignora arquivos ocultos (começando com .) persistent: true }); // Evento: arquivo adicionado watcher.on('add', path => console.log(`Arquivo ${path} foi adicionado.`)); // Evento: arquivo alterado watcher.on('change', path => console.log(`Arquivo ${path} foi modificado.`)); // Evento: arquivo removido watcher.on('unlink', path => console.log(`Arquivo ${path} foi removido.`));
- Monitoramento em Tempo Real:
chokidar
é ideal para aplicações que precisam reagir a mudanças no sistema de arquivos, como servidores de desenvolvimento que precisam reiniciar ou reconstruir arquivos ao detectar alterações.- Alto Desempenho:
chokidar
é otimizado para monitorar um grande número de arquivos sem sobrecarregar o sistema, utilizando internamente a APIfs.watch()
oufsevents
no macOS.Esses pacotes de código aberto fornecem ferramentas essenciais e funcionalidades avançadas para trabalhar com arquivos e diretórios no Node.js. Desde a busca de arquivos com
glob
eglobby
, até a manipulação aprimorada de arquivos comfs-extra
, e o monitoramento em tempo real comchokidar
, essas ferramentas expandem o poder do Node.js, tornando-o ainda mais versátil e eficiente para manipulação de arquivos.Você pode aprender mais sobre no artigo: MDN - Guia NodeJs
Para sair de uma aplicação Node.js, você pode usar a função
process.exit()
. Este método encerra o processo atual com um código de saída opcional.console.log("Aplicação iniciada."); // Encerra a aplicação com código de saída 0 (sucesso) process.exit(0);Os códigos de saída são números que o processo retorna ao sistema operacional quando ele termina. O código 0 geralmente indica sucesso, enquanto qualquer outro código indica um erro.
console.log("Aplicação com erro."); process.exit(1); // Código 1 indica um erro
process.env
é um objeto que contém todas as variáveis de ambiente do sistema onde a aplicação está sendo executada.// Acessa uma variável de ambiente chamada 'MY_VARIABLE' const myVariable = process.env.MY_VARIABLE || 'valor padrão'; console.log(`O valor da variável MY_VARIABLE é: ${myVariable}`);O pacote
dotenv
permite carregar variáveis de ambiente de um arquivo.env
paraprocess.env
.npm install dotenv
- Crie um arquivo
.env
:MY_VARIABLE=valor_importado
- Utilize o
dotenv
no seu código:require('dotenv').config(); const myVariable = process.env.MY_VARIABLE; console.log(`O valor da variável MY_VARIABLE é: ${myVariable}`);
process.stdin
é um fluxo de leitura que permite ler a entrada do usuário via terminal.process.stdin.setEncoding('utf8'); console.log('Digite algo e pressione Enter:'); process.stdin.on('data', (input) => { console.log(`Você digitou: ${input.trim()}`); process.exit(); });O pacote
inquirer
facilita a criação de prompts interativos.npm install inquirerconst inquirer = require('inquirer'); inquirer.prompt([ { type: 'input', name: 'name', message: 'Qual é o seu nome?' } ]).then(answers => { console.log(`Olá, ${answers.name}!`); });O pacote
prompts
também é utilizado para criar prompts interativos.####Instalação:
npm install promptsconst prompts = require('prompts'); (async () => { const response = await prompts({ type: 'text', name: 'name', message: 'Qual é o seu nome?' }); console.log(`Olá, ${response.name}!`); })();
stdout
estderr
são fluxos de saída padrão e de erro padrão, respectivamente.// Saída padrão process.stdout.write('Mensagem para stdout\n'); // Saída de erro process.stderr.write('Mensagem para stderr\n');O pacote
chalk
permite colorir o texto no terminal.npm install chalkconst chalk = require('chalk'); console.log(chalk.green('Texto em verde')); console.log(chalk.red.bold('Texto em vermelho e negrito'));O pacote
figlet
gera texto em estilo de arte ASCII.npm install figletconst figlet = require('figlet'); figlet('Olá Mundo!', (err, data) => { if (err) { console.log('Algo deu errado...'); console.dir(err); return; } console.log(data); });O pacote
cli-progress
é utilizado para criar barras de progresso no terminal.npm install cli-progressconst cliProgress = require('cli-progress'); // Cria uma nova barra de progresso const bar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic); // Inicia a barra de progresso bar.start(100, 0); // Atualiza a barra de progresso for (let i = 0; i <= 100; i++) { bar.update(i); // Simula um atraso require('deasync').sleep(50); } // Finaliza a barra de progresso bar.stop();
process.argv
é um array que contém os argumentos da linha de comando passados para o processo Node.js.// Acessa argumentos da linha de comando const args = process.argv.slice(2); console.log('Argumentos da linha de comando:'); args.forEach((arg, index) => { console.log(`Argumento ${index + 1}: ${arg}`); });O pacote
commander
facilita o gerenciamento de argumentos e opções da linha de comando.npm install commanderconst { program } = require('commander'); program .version('1.0.0') .description('Descrição da minha aplicação CLI') .option('-n, --name <type>', 'Nome do usuário') .parse(process.argv); const options = program.opts(); if (options.name) { console.log(`Olá, ${options.name}!`); } else { console.log('Olá, mundo!'); }Você pode aprender mais sobre nesse repositorio: awesome-nodejs
APIs (Application Programming Interfaces) são fundamentais no desenvolvimento moderno de software. Elas permitem a comunicação entre diferentes sistemas e aplicações, facilitando a troca de dados e funcionalidades. O desenvolvimento e consumo de APIs envolvem a criação de endpoints que outros serviços podem usar para acessar recursos ou funcionalidades específicas e a realização de requisições a essas APIs para consumir dados ou executar operações.
- Frameworks para Construção de APIs: Ferramentas que facilitam o desenvolvimento de APIs robustas e escaláveis.
- Realizando Chamadas de API: Métodos para interagir com APIs e consumir seus dados.
- Autenticação em APIs: Mecanismos para garantir a segurança e controle de acesso nas APIs.
O Express.js é um framework minimalista e flexível para Node.js que fornece um conjunto robusto de recursos para construir aplicativos web e APIs. Ele é amplamente utilizado devido à sua simplicidade e extensibilidade.
const express = require('express'); const app = express(); const port = 3000; // Endpoint básico app.get('/', (req, res) => { res.send('Hello World!'); }); // Iniciando o servidor app.listen(port, () => { console.log(`Servidor rodando em http://localhost:${port}`); });Este código cria um servidor básico com o Express.js que responde com "Hello World!" ao acessar a raiz (
/
). O métodoapp.get()
define uma rota para o endpoint/
, enquantoapp.listen()
inicia o servidor na porta especificada.Fastify é um framework web altamente focado em performance e baixo overhead. Ele oferece uma API similar ao Express.js, mas com um foco maior em velocidade e eficiência.
const fastify = require('fastify')({ logger: true }); const port = 3000; // Endpoint básico fastify.get('/', async (request, reply) => { return { message: 'Hello Fastify!' }; }); // Iniciando o servidor fastify.listen(port, (err, address) => { if (err) { fastify.log.error(err); process.exit(1); } fastify.log.info(`Servidor rodando em ${address}`); });Fastify cria um servidor com um endpoint que retorna uma resposta JSON com a mensagem "Hello Fastify!". O servidor é inicializado na porta especificada, e a logica para lidar com erros de inicialização também é implementada.
NestJS é um framework para construir aplicações Node.js escaláveis e eficientes. Ele utiliza TypeScript por padrão e é inspirado por arquiteturas como a do Angular, oferecendo um desenvolvimento estruturado e modular.
import { Module } from '@nestjs/common'; import { Controller, Get } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; @Controller() class AppController { @Get() getHello(): string { return 'Hello NestJS!'; } } @Module({ controllers: [AppController], }) class AppModule {} async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(3000); } bootstrap();Este exemplo configura uma aplicação básica em NestJS com um único controlador (
AppController
) que responde a requisições GET na raiz com a mensagem "Hello NestJS!". O métodobootstrap()
inicializa o aplicativo.Hono é um micro framework para construir aplicações web ultraleves e rápidas, com foco em simplicidade e desempenho.
import { Hono } from 'hono'; const app = new Hono(); // Endpoint básico app.get('/', (c) => c.text('Hello Hono!')); // Iniciando o servidor app.listen({ port: 3000 });Este código cria um servidor básico usando Hono que responde com "Hello Hono!" ao acessar a raiz. O método
app.listen()
inicia o servidor na porta especificada.O módulo
http
do Node.js é utilizado para criar servidores HTTP e realizar requisições HTTP. Ele é uma ferramenta fundamental e de baixo nível para manipulação de protocolos HTTP.const http = require('http'); // Realizando uma requisição GET http.get('http://example.com', (res) => { let data = ''; // A medida que os dados chegam, eles são acumulados res.on('data', (chunk) => { data += chunk; }); // Quando a resposta completa é recebida res.on('end', () => { console.log(data); }); }).on('error', (err) => { console.error(`Erro: ${err.message}`); });Este exemplo mostra como realizar uma requisição GET usando o módulo
http
. Os dados da resposta são recebidos em partes (chunks
) e acumulados até que a resposta completa seja processada.Axios é uma biblioteca popular para realizar requisições HTTP de forma simples e eficiente. Ela suporta promessas e permite uma fácil integração com APIs.
const axios = require('axios'); // Realizando uma requisição GET axios.get('http://example.com') .then(response => { console.log(response.data); }) .catch(error => { console.error('Erro:', error); });Neste exemplo, o Axios realiza uma requisição GET para o
http://example.com
e lida com a resposta e possíveis erros utilizando promessas (then
ecatch
).Ky é uma biblioteca para realizar requisições HTTP focada em simplicidade e leveza, baseada no
fetch
. Ela é otimizada para ser utilizada em aplicações frontend.import ky from 'ky'; (async () => { try { const json = await ky.get('http://example.com').json(); console.log(json); } catch (error) { console.error('Erro:', error); } })();Este exemplo utiliza o Ky para realizar uma requisição GET e automaticamente tratar a resposta como JSON. A função assíncrona (
async
) é usada para esperar a resposta e lidar com possíveis erros.A Fetch API é uma interface moderna para realizar requisições HTTP. Ela é nativa em navegadores modernos e também pode ser utilizada no Node.js com bibliotecas adicionais.
fetch('http://example.com') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Erro:', error));O exemplo utiliza a Fetch API para realizar uma requisição GET e processar a resposta como JSON. Promessas são utilizadas para lidar com a resposta e erros.
Got é uma biblioteca HTTP moderna e robusta para Node.js, que oferece suporte a recursos avançados como interceptadores de requisições, cancelamento e recuperação de erros.
const got = require('got'); (async () => { try { const response = await got('http://example.com'); console.log(response.body); } catch (error) { console.error('Erro:', error.response.body); } })();Got realiza uma requisição GET e a resposta é manipulada utilizando uma função assíncrona. O corpo da resposta é exibido, e erros são tratados de maneira específica.
JWT é uma maneira compacta e segura de transmitir informações entre as partes como um objeto JSON. É amplamente utilizado para autenticação em APIs.
const jwt = require('jsonwebtoken'); const token = jwt.sign({ userId: 123 }, 'secreto', { expiresIn: '1h' }); console.log(token); // Verificando o token try { const decoded = jwt.verify(token, 'secreto'); console.log(decoded); } catch (err) { console.error('Token inválido', err); }Este exemplo cria um token JWT assinado com uma chave secreta e com um tempo de expiração de uma hora. O token gerado é então verificado, e se for válido, seus dados são exibidos.
Passport.js é um middleware de autenticação para Node.js, que oferece suporte a diversos mecanismos de autenticação, como JWT, OAuth, e login tradicional.
const express = require('express'); const passport = require('passport'); const LocalStrategy = require('passport-local').Strategy; passport.use(new LocalStrategy( function(username, password, done) { // Aqui você realizaria a verificação do usuário if (username === 'user' && password === 'pass') { return done(null, { id: 1, name: 'user' }); } else { return done(null, false, { message: 'Credenciais incorretas' }); } } )); const app = express(); app.use(passport.initialize()); // Endpoint de login app.post('/login', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' }) ); app.listen(3000, () => console.log('Servidor rodando na porta 3000'));Neste exemplo, Passport.js é configurado para usar a estratégia
LocalStrategy
para autenticar usuários com um nome de usuário e senha. Se as credenciais estiverem corretas, o usuário é autenticado com sucesso.Compreender como construir e consumir APIs, junto com a implementação de autenticação, é essencial para o desenvolvimento de aplicações modernas. Ferramentas como Express.js, Fastify, NestJS, e Hono facilitam a construção de APIs, enquanto Axios, Fetch, e Got ajudam no consumo dessas APIs. Para segurança, JWT e Passport.js são poderosos aliados na implementação de autenticação em APIs.
Você pode aprender mais sobre nesse artigo: MDN - API's