Módulos Internos (Core Modules) - Parte 1

Módulos Internos (Core Modules) - Parte 1

Na lição anterior, você viu sobre o funcionamento dos módulos em NodeJS, aprendendo como eles são criados e usados por outros arquivos.

O conhecimento adquirido alí foi primordial para que pudéssemos estar aqui agora aprendendo sobre os Módulos Internos (Core Modules).

O funcionamento dos módulos internos é o mesmo, a diferença é que não precisamos criar o módulo e a sua lógica, uma vez que isso já foi feito pelos próprios desenvolvedores do NodeJS rs

Sendo assim, precisamos só importá-los para dentro da nossa aplicação, e entender como fazer o uso de seus métodos e propriedades 😅

Arquivos da lição

Os arquivos que veremos durante o decorrer desta lição, podem ser encontrados nos links abaixo:

O que são módulos internos?

Módulos Internos, ou também conhecidos como Core Modules, nada mais são do que módulos que foram criados e disponibilizados gratuitamente pelos próprios desenvolvedores do NodeJS.

De forma a adicionar funcionalidades que até então não existiam no Javascript (Client Side).

Para mais informações detalhadas do que são os módulos internos, não deixe de acessar a lição que fala sobre eles.

Os módulos internos tem por objetivo principal, adicionar e ampliar as capacidades do NodeJS em diversas áreas, desde a manipulação de arquivos até comunicação segura e controle de execução assíncrona.

Exemplos de módulos internos

Vou deixar com vocês, uma grande lista de apenas alguns módulos internos disponíveis para uso com o NodeJS.

Nesse primeiro momento, peço para que você dê somente uma passada de olho na lista abaixo, não é para implementar tudo isso agora, ok? 

http: Fornece funcionalidades para criar um servidor HTTP e fazer solicitações HTTP.

const http = require('http');

fs (file system): Permite interagir com o sistema de arquivos do sistema operacional.

const fs = require('fs');

path: Fornece utilitários para trabalhar com caminhos de arquivo e diretório.

const path = require('path');

events: Implementa um mecanismo de eventos que permite a comunicação entre objetos em seu aplicativo.

const events = require('events');

util: Fornece utilitários comuns, como formatação de strings e manipulação de objetos.

const util = require('util');

os: Oferece métodos para interagir com o sistema operacional, como obter informações sobre a CPU e a memória.

const os = require('os');

querystring: Facilita a manipulação de strings de consulta em URLs.

const querystring = require('querystring');

crypto: Fornece funcionalidades de criptografia, como hash e criptografia.

const crypto = require('crypto');

url: Ajuda a analisar e formatar URLs.

const url = require('url');

util: Fornece funções utilitárias comumente usadas.

const util = require('util');

stream: Fornece uma implementação base para trabalhar com fluxos de dados. É especialmente útil ao lidar com grandes volumes de dados.

const stream = require('stream');

zlib: Permite a compressão e descompressão de dados usando a biblioteca zlib.

const zlib = require('zlib');

net: Oferece funcionalidades para criar servidores TCP (Transmission Control Protocol).

const net = require('net');

dgram: Permite a criação de servidores UDP (User Datagram Protocol) e sockets.

const dgram = require('dgram');

child_process: Facilita a execução de processos externos a partir de um aplicativo NodeJS.

const child_process = require('child_process');

cluster: Permite a criação de processos filhos para distribuição de carga em ambientes multi-core.

const cluster = require('cluster');

readline: Fornece uma interface para ler dados de um fluxo (como um arquivo ou a entrada do console) linha por linha.

const readline = require('readline');

https: Similar ao módulo http, mas fornece funcionalidades para criar servidores HTTP seguros usando o protocolo HTTPS.

const https = require('https');

tty: Oferece funcionalidades relacionadas a terminais (TTY), úteis ao trabalhar com a entrada e saída do console.

const tty = require('tty');

dns: Fornece funcionalidades para realizar operações DNS, como resolução de nomes de domínio.

const dns = require('dns');

url: Oferece utilitários para trabalhar com URLs.

const url = require('url');

string_decoder: Fornece utilitários para decodificar buffers em strings, especialmente útil ao trabalhar com dados binários.

const StringDecoder = require('string_decoder').StringDecoder;

punycode: Fornece funcionalidades para lidar com codificação e decodificação de strings de domínio internacionalizados (IDNs).

const punycode = require('punycode');

v8: Fornece acesso às funcionalidades da engine V8 do Google Chrome, como estatísticas de uso de memória.

const v8 = require('v8');

timers: Fornece funcionalidades para agendar a execução de código em intervalos regulares ou após um atraso.

const { setTimeout, setInterval, clearTimeout, clearInterval } = require('timers');

assert: Fornece funções de assertivas que podem ser usadas para testar as condições e gerar erros se as assertivas não forem atendidas.

const assert = require('assert');

buffer: Fornece funcionalidades para manipulação de dados binários em buffers.

const buffer = require('buffer');

tls (Transport Layer Security): Fornece funcionalidades para criar servidores seguros usando o protocolo TLS/SSL.

const tls = require('tls');

async_hooks: Permite rastrear a execução de operações assíncronas ao longo do tempo.

const async_hooks = require('async_hooks');

module: Fornece funcionalidades relacionadas ao sistema de módulos do NodeJS, permitindo manipular o carregamento de módulos.

const module = require('module');

Ufa... se você pensou que esses são todos os módulos internos do NodeJS, você está ligeiramente enganado rs

Existem muitos outros módulos internos que podem ser encontrados na documentação do NodeJS.

Conhecendo a variável PROCESS

Antes de continuarmos, é de vital importância que você tenha um mínimo de entendimento sobre a variável global do NodeJS, chamada de process.

Mas o que é essa variável, e para que ela serve?

De acordo com a documentação do NodeJS, essa variável fornece informações de controle sobre os processos em execução da própria aplicação.

Essa variável é criada diretamente pelo NodeJS por de baixo dos panos, de modo que não precisamos importa-la dentro de cada um de nossos sistemas.

Uma das utilizadades dessa variável, é que podemos ler argumentos que são passando no início da execução do programa.

Se lembra que para executar um programa em NodeJS nós usamos o comando node app.js dentro do nosso terminal?

Então, você sabia que é possível adicionar argumentos junto a instrução de execução? Não sabia? Então veja como isso é feito:

node app.js nome=micilini

No comando acima, estou dizendo para o NodeJS abrir a aplicação app.js, onde estou passando um argumento chamado nome que armazena a string micilini.

Legal, mas como eu faço para recuperar esses argumentos dentro da aplicação?

É ai que entra a variável process 😄

Dentro do app.js, você pode fazer o uso do comando process.argv, que retorna todos os argumentos da aplicação atual:

/* Aplicação de Testes (app.js) */

//Observação: Quando rodar esta applicação faça isso passando um argumento: [node app.js nome=micilini]

console.log('Todos os Argumentos da Aplicação');
console.log(process.argv);//Retorna todos os argumentos da aplicação

Como você pôde observar, muitos argumentos além do nome (que definimos) foram retornados pela aplicação.

Caso queiramos retornar somente os argumentos que passamos, podemos fazer o uso do método slice do próprio Javascript, de modo a resgatar apenas o segundo argumento:

const argsPassed = process.argv.slice(2);//Retorna os argumentos que nós passamos
console.log(argsPassed);//o retorno será: 'nome=william'

Para transformar esses argumentos em um objeto, podemos fazer o uso do método split do Javascript, observe:

/* Aplicação de Testes (app.js) */

//Observação: Quando rodar esta applicação faça isso passando um argumento: [node app.js nome=micilini]

console.log('Todos os Argumentos da Aplicação');
console.log(process.argv);//Retorna todos os argumentos da aplicação

const argsPassed = process.argv.slice(2);//Retorna os argumentos que nós passamos
console.log(argsPassed);

const nome = argsPassed[0].split("=")[1];
console.log('Olá ' + nome);//o retorno será 'Olá Micilini'

E como eu faço para passar mais de um único argumento? Simples, basta dar espaço e seguir a mesma lógica 😋

node app.js nome=micilini site=https://micilini.com/

Para selecionar o segundo argumento basta executar a lógica do slice e split🙂

Mas a variável process só serve para recuperar argumentos? Não, existem uma gama de possibilidades que você pode fazer com ela, vejamos algumas.

Métodos e Propriedades

process.env: retorna o arquivo .env que contém as variáveis do sistema. Como ainda não chegamos nessa lição de variáveis do ambiente em NodeJS, o retorno será undefined.

console.log(process.env.NODE_ENV); // Exemplo de acesso à variável de ambiente NODE_ENV

process.cwd(): método que retorna o diretorio de trabalho atual da aplicação que está sendo executada.

console.log(process.cwd());// Retorna o diretório da aplicação atual

process.pid: método que retorna o ID do processo NodeJS que está em execução.

console.log(process.pid);// Retorna o ID do NodeJS em execução

process.exit([code]): método que finaliza o processo de execução informando um código de saída (int).

process.exit(0); // Finaliza o processo com código de saída 0

process.on(event, callback): método que permite escutar certos eventos da aplicação (exit, uncaughtException e entre outros).

process.on('exit', (code) => {
 console.log(`Processo encerrado com código de saída: ${code}`);
});

process.stdin: método que permite escutar as entradas do usuário no console.

process.stdin.setEncoding('utf8');//Configura o charset do texto

console.log('Digite algo e pressione Enter:');//Diz ao usuário digitar algo no console

process.stdin.on('data', (dados) => {//Espera o usuário digitar, e assim que receber o input executa o bloco abaixo
 console.log(`Você digitou: ${dados.trim()}`);
 process.stdin.pause();//Pausa a entrada dos dados digitados pelo usuário
});

process.stdout: método usado para imprimir no console uma mensagem de saída.

process.stdout.write('Isso é uma mensagem na saída padrão.\n');

process.stderr: método usado para imprimir uma mensagem de erro padrão no console.

process.stderr.write('Isso é uma mensagem de erro na saída padrão de erro.\n');

Para entender mais sobre o funcionamento da variável global process, não deixe de acessar a documentação.

O que acontece se eu criar uma variável com nome de process?

Quando você cria uma variável usando o mesmo nome da variável global, sua nova variável irá sobreescrever a referência ao objeto global process, o que pode acarretar comportamentos indesejados, observe:

const process = "Micilini";

console.log(process);//"Micilini"

process.exit(0);//Erro na aplicação, pois process é uma constante agora.

Portanto, nunca crie uma variável com o nome de process 😆

Trabalhando com Core Modules

Para colocar a mão na massa e brincar um pouco com os módulos internos, vamos começar aprendendo a utilizar o módulo 'path', um dos módulos mais simples de se utilizar.

Módulo: path

O NodeJS, conta com um módulo interno capaz de trabalhar com caminhos de arquivos e diretórios, cujo nome é path.

Com ele você é capaz de resolver um caminho, retornar a extenção de um arquivo, retornar o diretório de um caminho, e entre outras coisas a mais.

É importante ressaltar que este módulo não lida com lida diretamente com a criação de pastas, e muito menos de arquivos, ok?

Para se trabalhar com o módulo path, comece criando o seu arquivo de testes (app.js) na pasta do seu projeto. Em seguida você vai precisar importar o módulo em si:

const path = require('path');

Este módulo conta com diversos métodos e propriedades, veremos cada um deles a seguir.

Métodos e Propriedades do módulo path

path.extname(path): método usado para retornar a extensão do arquivo de um caminho.

/* Aplicação de Testes (app.js) */

const path = require('path');

//extname
const ext = path.extname('meu-arquivo.xtr');
console.log('A extensão é: ' + ext);//o retorno será 'A extensão é: .xtr'

path.dirname(path): método usado para retornar o diretório de um caminho:

/* Aplicação de Testes (app.js) */

const path = require('path');

//dirname
const directory = path.dirname('/meu/caminho/eu.txt');
console.log('O caminho é: ' + directory);//o retorno será 'O caminho é: /meu/caminho/'

path.normalize(path): método usado para normalizar um caminho, resolvendo ".." e "." segmentos.

/* Aplicação de Testes (app.js) */

const path = require('path');

//normalize
const normalizedPath = path.normalize('/meu/caminho/../eu.txt');
console.log('O caminho normalizado: ' + normalizedPath);//o retorno será 'O caminho é: \meu\eu.txt'

path.isAbsolute(path): método usado para verificar se o caminho é absoluto.

/* Aplicação de Testes (app.js) */

const path = require('path');

//isAbsolute
const isAbsolute = path.isAbsolute('/meu/caminho/eu.txt');
console.log('O caminho absoluto? ' + isAbsolute);//o retorno será 'true'

path.relative(from, to): método usado para retornar o caminho relativo de from para to.

/* Aplicação de Testes (app.js) */

const path = require('path');

//relative
const relativePath = path.relative('/caminho/para', '/caminho/para/arquivo.txt');
console.log('O caminho relativo: ' + relativePath);//o retorno será 'arquivo.txt'

path.sep: propriedade que retorna o separador (string) de caminho específico do sistema ('/' no Unix, '\' no Windows). Bem útil quando estamos criando ou buscando por diretórios.

/* Aplicação de Testes (app.js) */

const path = require('path');

//sep
console.log('Separador do Sistema: ' + path.sep);//o retorno será de acordo com o sistema em uso

path.delimiter: propriedade que retorna o delimitador de caminho específico do sistema (':' no Unix, ';' no Windows).

/* Aplicação de Testes (app.js) */

const path = require('path');

//delimiter
console.log('Delimitador do Sistema: ' + path.delimiter);//o retorno será de acordo com o sistema em uso

path.basename(path[, ext]): método que retorna o nome do arquivo presente em um caminho.

A variável ext é opcional e e, se fornecido, remove a extensão especificada do nome do arquivo.

/* Aplicação de Testes (app.js) */

const path = require('path');

//basename (sem ext)
const fileName = path.basename('/minha/pasta/file.txt');
console.log('Nome do Arquivo é: ' + fileName);//o retorno será 'file.txt'

//basename (com ext)
const fileNameExt = path.basename('/minha/pasta/file.txt', '.txt');
console.log('Nome do Arquivo é: ' + fileNameExt);//o retorno será 'file'

path.resolve([...paths]): método usado para resolver uma sequência de caminhos ou segmentos de caminho dado em um caminho absoluto.

/* Aplicação de Testes (app.js) */

const path = require('path');

//resolve
const absolutePath = path.resolve('meu', 'caminho', 'arquivo.txt');
console.log('Caminho é: ' + absolutePath);//o retorno será '..../meu/caminho/arquivo.txt'

path.join([...paths]): método usado para combinar diversos segmentos de um caminho, em um caminho absoluto.

/* Aplicação de Testes (app.js) */

const path = require('path');

//join
const fullPath = path.join('/meu', 'caminho', 'eu.txt');
console.log('Caminho é: ' + fullPath);//o retorno será '\meu\caminho\eu.txt

Existem muitos outros métodos e propriedades referentes ao path, para saber mais consulte a documentação.

Módulo: readline

O readline é um dos módulos internos bastante utilizados por aplicações que fazem o uso da linha de comando.

Como o nome já diz, este módulo permitindo a leitura de entrada do console (prompt) de forma assíncrona. Fazendo com que tudo o que você digitar no console (prompt), seja lido pela sua aplicação por meio desse módulo.

Para se trabalhar com o módulo readline, comece criando o seu arquivo de testes (app.js) na pasta do seu projeto. Em seguida você vai precisar importar o módulo em si:  

const readline = require('readline');

Após isso, você vai precisar configurar a interface de leitura do readline, para isso você pode fazer o uso do método createInterface, para criar uma instância de interface de leitura:

/* Aplicação de Testes (app.js) */

const readline = require('readline');

const rl = readline.createInterface({
 input: process.stdin,
 output: process.stdout
});

Como você pode perceber, estamos passando dois parâmetros para dentro do método createInterface, chamados de:

input: que recebe a variável process, mais especificamente o método stdin, passando a responsabilidade de leitura para o módulo readline.

output: que recebe também a variavel process passando a responsabilidade do stdout para o readline.

Feito isso, o módulo readline já esta pronto para trabalhar com os inputs e outputs do console 😄

Métodos e Propriedades do módulo readline

O módulo readline possui alguns métodos e propriedades principais, vejamos alguns deles.

question(prompt, callback): método que exibe o prompt para que o usuário possa digitar alguma entrada no console.

/* Aplicação de Testes (app.js) */

const readline = require('readline');

const readline = readline.createInterface({
 input: process.stdin,
 output: process.stdout
});

readline.question('Me diga o seu nome ', (answer) => {
 console.log(`Olá, ${answer}!`);
 readline.close();//Fecha a interface de leitura/gravação
});

Observe no comando acima que o método question faz uma pergunta no console e aguarda o usuário informar algum dado.

Assim que esse dado é enviado, a resposta será armazenada dentro da variável answer para que possa seguir o fluxo, e por fim fechar a interface de leitura/gravação usando o close().

close(): Como dito anteriormente, é um método que serve para ser usado dentro do bloco do realine para fechar a interface.

 readline.close();//Fecha a interface de leitura/gravação

on(eventName, callback): é um método capaz de escutar qualquer tipo de interação que acontece no prompt. Por exemplo, podemos aciona-lo sempre quando o prompt fecha, ou quando o usuário digita alguma coisa.

Com relação ao eventName, ele é o nome do evento que podemos escutar, e neste caso possuímos 6 tipos principais.

'line': Acionado quando o usuário pressiona ENTER para enviar uma linha de entrada.

readline.on('line', (input) => {//O resultado digitado pelo usuário estará salvo dentro do input
 console.log(`Você digitou: ${input}`);
});

'close': Acionado quando a interface de leitura é fechada.

readline.on('close', () => {
 console.log('Interface fechada.');
});

'pause': Acionado quando a entrada é pausada.

readline.on('pause', () => {
 console.log('Leitura pausada.');
});

'resume': Acionado quando a entrada é retomada após ter sido pausada.

readline.on('resume', () => {
 console.log('Leitura retomada.');
});

'SIGCONT': Acionado quando a entrada está disponível novamente após ter sido pausada.

readline.on('SIGCONT', () => {
 console.log('Sinal SIGCONT recebido.');
});

'SIGINT': Acionado quando o usuário pressiona Ctrl+C.

readline.on('SIGINT', () => {
 console.log('Ctrl+C pressionado.');
 readline.close();
});

setPrompt(prompt): método usado para definir um prompt personalizado. Observe como isso pode ser feito.

readline.setPrompt('Digite um número de 1 a 10... ');// Define um prompt personalizado

readline.prompt();// Exibe o prompt, dando espaço para que o usuário digite o número no console

readline.on('line', (input) => {//'line' aguarda que o usuário digite algum valor e aperte ENTER para enviar

 const number = parseFloat(input);//Faz o parse do valor digitado pelo usuário para um valor númerico de ponto flutuante

 if (isNaN(number) || number < 1 || number > 10) {//Verifica se o número é válido, e se ele esta entre 1 a 10
 console.log('Isso não é um número válido. Tente novamente.');
 readline.prompt();//Exibe novamente o prompt até que o usuário digite um número válido
 }else{
 console.log(`Você digitou o número: ${number}`);
 readline.close();//Fecha o prompt
 }

});

readline.on('close', () => {// Evento 'close' é emitido quando a interface é fechada
 console.log('Encerrando a leitura.');
});

Para mais informações sobre os métodos e propriedades do módulo readline, não deixe de consultar a documentação.

Conclusão

Pois bem, chegamos ao final da primeira parte que fala sobre os módulos internos.

Aqui, tivemos uma lição cheia de aprendizado, onde você viu um pouco mais sobre o funcionamento dos módulos internos (core modules), além de uma enorme lista de módulos disponíveis para uso.

Você também aprendeu sobre os módulos path, readline e a variável global process.

Te aguardo na segunda parte desse incrível conteúdo 😄