NodeJs - alandrade21/docsCompartilhados GitHub Wiki
Nesta página:
- Instalação
- NPM
- Criação de componentes em TS
- JS no Node
- Error: ENOSPC: System limit for number of file watchers reached
Dê preferência por utilizar o NVM, listado na próxima seção.
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt install nodejs
sudo apt install build-essentialTesta a instalação
node -v
npm -vInformações retiradas dessa página.
Vamos utilizar o NVM.
Pode haver versão de Angular e de Typescript instalada globalmente. Essa instalação global faz com que os comandos ng ou tsc sejam reconhecidos em todo o operacional.
Para verificar se esse é o caso, simplesmente digite ng ou tsc no terminal. Se o comando for reconhecido, então essas ferramentas estão instaladas no escopo global.
Angular e Typescript são pacotes NPM. Se eles estão em escopo global é porque eles foram instalados com npm i -g <nome do pacote>.
Para verificar todos os pacotes instalados em escopo global, rode o comando npm list -g.
No linux, utilizando uma instalação global de NodeJs, os pacotes instalados em escopo global ficam na pasta /usr/lib/node_modules.
Os pacotes de Angular e Typescript que estejam no escopo global devem ser removidos. Para isso utilize os comandos abaixo:
sudo npm un -g @angular/cli
sudo npm un -g typescriptOutra opção é simplesmente apagar as pastas destes pacotes de /usr/lib/node_modules.
Para verificar se o NodeJS está em escopo global, rode o comando node -v. Se o comando for reconhecido, ele responde qual é a versão instalada.
O comando which node vai responder onde o node está instalado. Você deve obter a resposta /usr/bin/node (ou qualquer outra pasta de sistema, fora do seu domínio de usuário).
sudo apt remove nodejsSó o pacote do node deve aparecer como candidato à remoção.
O NVM é um gerenciador/chaveador de versões do node, que utiliza a sua pasta de usuário ao invés da área do sistema.
Veja qual a versão mais recente no repositório github da ferramenta. Para instalar:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bashEsse comando baixa o script de instalação e instala o NVM em ~/.nvm/. As versões diferentes do node serão instaladas nesse diretório tb.
Essa instalação acrescenta as linhas abaixo no arquivo ~/.bashrc:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completionLogo após a instalação, pode ser necessário abrir um novo terminal para o NVM ser reconhecido.
- Versão do
nvminstalada:
nvm --version- Listar versões instaladas do node:
nvm ls- Listar versões disponíveis do node para instalação:
nvm ls-remote- Instalar uma versão do node:
nvm install vX.X.X- Instalar a versão mais recente do node:
nvm install node- Desinstalar uma versão do node:
nvm uninstall vX.X.X- Usar uma versão do node (vale para aquela seção de shell):
nvm use vX.X.X- Usar a versão mais recente do node:
nvm use node- Definir nome para uma versão do node:
nvm alias meunome vX.X.X
nvm use meunome- Remover um nome de versão do node:
nvm unalias meunome- Definir uma versão padrão do node:
nvm alias default vX.X.X- Definir a versão mais nova versão padrão:
nvm alias default node- Saber a versão atual:
nvm currentCada versão instalada pelo comando nvm install vX.X.X é colocada em um subdiretório da pasta ~/.nvm/versions/node/.
Assim, se instalamos nvm install v15.11.0, esta versão estará instalada em ~/.nvm/versions/node/v15.11.0/.
O escopo global desta versão estará em ~/.nvm/versions/node/v15.11.0/lib/node_modules/.
Informações retiradas da página How to run multiple Node and Angular versions simultaneously.
Versões específicas do angular tem dependências de versões específicas de node e de typescript. Esta é a tabela de versões compatíveis).
Crie um arquivo .nvmrc na raiz do projeto e coloque dentro dele a versão do node. Ex: 12.4.0.
Todos os comandos node agora tem que ser rodados com nvm:
- O que era rodado com
node [arguments], agora precisa ser rodado comnvm run [arguments]. - O que era rodado com
npm run [nome do script] [arguments], agora precisa ser rodado comnvm exec npm run [nome do script] [arguments].
Roda os comandos abaixo depois de instalar o npm.
npm set init.author.name 'André Andrade'
npm set init.author.email '[email protected]'
npm set init.author.url 'https://github.com/alandrade21'
npm adduserEsse último comando vai pedir seu usuário e sua senha no repositório npm, e será utilizado na hora de publicar pacotes.
Verifica as configurações feitas com o comando
npm config lsNode Package Manager.
O repositório de pacotes é o NPM registry.
Na pasta raiz do projeto, no terminal, roda npm init. Ele vai pedir vários dados, vai criar o arquivo de entry point e o package.json.
Dependências de desenvolvimento
npm i <pacote> -Dou
npm install @types/node --save-devDependências de RunTime
npm i <pacote> -SInstalar pacote em escopo global:
npm i <pacote> -gInstalar todas as dependências do projeto:
npm installAtualizar as dependências de um projeto:
npm updateNúmero de versão composto por Major.Minor.Patch.
Incrementa a patch quando algum bug for corrigido. Não tem quebra de funcionalidade para os clientes.
Incrementa a minor quando novas funcionalidades forem acrescentadas. Não tem quebra de funcionalidade para os clientes.
Incrementa a major quando grandes mudanças forem feitas e o código do cliente pode quebrar.
Essas regras podem ser encontradas no site da Semantic Versioning.
No package.json o número de versão de dependências começa com um caractere:
-
~: Atualiza para versões mais novas que tenham trocado apenas o patch number. -
^: Atualiza para versões mais novas que tenham trocado ou o patch number ou minor number.
- moment: facilita o trabalho e a formatação de datetime.
- nodemon: monitor para o node verificando se algum dos arquivos do seu projeto mudou. Se mudou, ele reinicia o node. Então, ao invés de rodar o projeto com
node app.js, roda comnodemon app.js. Pra isso instala esse cara no escopo global. Isso foi implementado no próprio node com o comandonode --watch app.js.
Crie um novo diretório de projeto para escrever o código do componente.
Entre nesse diretório e inicialize o projeto com
npm init -yGera o arquivo tsconfig.json com o comando tsc --init.
No tsconfig.json coloca a propriedade "declaration" : true. Isso vai gerar o arquivo de tipos .d.ts.
Escreve o componente, de preferência no arquivo index.ts.
Transpila o componente com tsc. O resultado vai aparecer na pasta ./dist.
Completa o arquivo package.json com as entradas:
"main": "dist/index.js",
"types" : "dist/index.d.ts"Coloque seu namespace no nome do componente: @alandrade21/<nome-do-componente>.
Para evitar publicar um componente antes do término do seu desenvolvimento e ainda assim permitir seu uso em outros projetos, vamos linkar a pasta do componente no projeto.
Vai para a pasta do componente e roda o comando:
sudo npm linkIsso cria um link global para o componente em /usr/lib/node_modules/@alandrade21/<nome-do-componente>. Por isso a permissão de sudo.
Vai para a pasta do projeto que usará o componente e roda o comando:
npm link <nome-do-componente>Coloca a entrada files no package.json, da seguinte forma:
“files”: [“dist/**/*”]Isso garante que apenas os arquivos necessários serão utilizados no empacotamento.
Loga no repositório npm com o comando:
npm loginDentro do diretório do componente a ser publicado, publica o pacote com o comando:
npm publishDesfaça o link no projeto que consome o compenente.
npm uninstall --no-save <nome-do-componente>Instale o pacote a partir do npm:
npm installO componente já está no package.json, é só rodar o comando acima para usar a versão publicada.
Para apagar o link global, vai para o diretório do componente e roda:
npm uninstallPodem ser consultadas na página de documentação do node, na seção API DOCS.
É a capacidade do javascript de passar funções como parâmetros, de colocá-las em arrays, etc. São usadas como vc usa qualquer outro tipo.
Isso é possível pq em JS funções são tipos especiais de objetos.
Function expression é quando vc atribui a definição de uma função a uma variável:
var greetMe = function(){
console.log('Hi');
}Pode ser rodada como greetMe().
Function expressions tb podem ser criadas assim:
(function() {
...
}());Function expressions são executadas imediatamente (IIFE - Immediately Invoked Function Expressions). Isso garante que o que é criado no escopo desse tipo de função permanece nesse escopo.
Objetos em js são containers de pares nome:valor separados por vírgla.
var person = {
firstName: 'John',
lastname: 'Doe',
greet: function() {
console.log('Hello, ' + this.firstName + ' ' + this.lastName);
}
};A sintaxe acima é uma das formas de se definir um objeto.
Acesso aos componentes do objeto podem ser feitos de diversas maneiras:
person.greet();
console.log(person['firstName']);É uma função que quando chamada com new retorna um objeto vazio. Todos os objetos criados a partir de uma mesma costructor function compartilham o mesmo objeto prototype.
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
var john = new Person('John', 'Doe');Alterações no prototype da constructor function são compartilhados por todos os objetos criados a partir dela:
Person.prototype.greet = function() {
console.log('Hello, ' + this.firstName + ' ' + this.lastName);
}De forma que john.greet() vai funcionar.
O prototype de um objeto pode ser acessado na propriedade __proto__.
var person = {
firstName: '',
lastName: '',
greet: function() {
return this.firstName + ' ' + this.lastName;
}
}
var john = Object.create(person);
john.firstName = 'John';
john.lastName = 'Doe';No exemplo acime, o objeto person é o prototype do objeto john.
É um encadeamento de prototypes.
var util = require('util');
function Person() {
this.firstName = '';
this.lastName = '';
}
Person.prototype.greet = function() {
console.log('Hello, ' + this.firstName + ' ' + this.lastName);
}
function Policeman() {
Person.call(this);
this.badgeNumber = '';
}
util.inherits(Policeman, Person);
var officer = new Policeman();
officer.firstName = 'John';
officer.lastName = 'Doe';
officer.badgeNumber = '1234';
officer.greet();A função util.inherits é provida pela API do Node e fa o cascateamento de prototypes.
No entanto, elementos definidos fora dos prototypes, como os atributos de Pessoa, não ficam visíveis a partir do Policeman. Para que isso aconteça é preciso rodar Person.call(this); na primeira linha da constructor function da "subclasse". Isso é similar a chamar super() em outras linguagens.
Na seção de constructor functions fizemos algo assim:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.greet = function() {
console.log('Hello, ' + this.firstName + ' ' + this.lastName);
}
var john = new Person('John', 'Doe');Agora em ES6 podemos escrever:
'use strict';
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
greet() {
console.log('Hello, ' + this.firstName + ' ' + this.lastName);
}
}
var john = new Person('John', 'Doe');Ouso de 'use strict' é mandatário ao utilizar ES6.
Mas isso é só syntax suggar. Por baixo dos panos a classe é só uma constructor function, e os métodos da classe então sendo criados no prototype do objeto, e o encadeamento de prototypes para fazer herança continua existindo do mesmo jeito de antes.
Para mostrar como fazer herança usando constructor functions fizemos:
var util = require('util');
function Person() {
this.firstName = '';
this.lastName = '';
}
Person.prototype.greet = function() {
console.log('Hello, ' + this.firstName + ' ' + this.lastName);
}
function Policeman() {
Person.call(this);
this.badgeNumber = '';
}
util.inherits(Policeman, Person);
var officer = new Policeman();
officer.firstName = 'John';
officer.lastName = 'Doe';
officer.badgeNumber = '1234';
officer.greet();Em ES6 fica:
'use strict';
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
greet() {
console.log('Hello, ' + this.firstName + ' ' + this.lastName);
}
}
class Policeman extends Person {
constructor(firstName, lastName, badgeNumber) {
super(firstName, lastName)
this.badgeNumber = badgeNumber;
}
var officer = new Policeman('John', 'Doe', '1234');
}O super é obrigatório para que o encadeamento de prototypes pegue os elementos definidos nos construtores das super classes.
Module é um bloco de código reutilizável cuja existência não impacta, acidentalmente, outros códigos.
Só javascript ES6 tem isso.
CommonsJS Modules é o padrão sobre como módulos devem ser estruturados no node.
Um módulo precisa expor aquilo que vai ser público.
greet.js:
var greet = function() {
console.log('Hi!');
};
module.exports = greet;app.js:
var greet = require('./greet'); // Se os arquivos estiverem no mesmo dir.
greet();Qdo require roda, ele encapsula todo o arquivo em uma function expression e retorna a propriedade module.exports.
Se require não achar um arquivo .js ele procura por uma pasta com o mesmo nome, e dentro dela por um arquivo index.js.
Esse index.js terá requires e exports, como no exemplo abaixo:
var english = require('./english');
var spanish = require('./spanish');
module.exports = {
english: english,
spanish: spanish
};No exemplo acima, existem dois arquivos english.js e spanish.js no mesmo diretório do index.js mostrado acima.
Se esses arquivos estiverem dentro de uma pasta greet, no mesmo nível do arquivo js que quiser consumir esse módulo, o require fica:
var greet = require('./greet');
greet.english();
greet.spanish();Requires tb pode apontar para um json. Nesse caso um novo objeto é criado com base no json.
Outras formas de trabalhar com módulos:
greet.js:
module.exports.greet = function() {...};app.js:
var greet = require('./greet');
greet.greet();ou
var greet = require('./greet').greet;
greet();Vários requires apontando para um mesmo arquivo retornam o mesmo objeto (qdo um objeto é retornado). Como se fosse um singleton.
Funções nativas podem ser requeridas sem um caminho, usando apenas o nome do arquivo que contém a api desejada, por exemplo var util = require('util');.
No package.json essa opção é identificada pelo "type": "commonsjs" ou usa a extensão .cjs. Não misturar estilos.
É o padrão de módulos criado pelo js.
Os conceitos são os mesmos, muda a sintaxe.
greet.js:
export function greet() {
console.log('Hello!');
}app.js:
import * as greetr from './greet';
greetr.greet();No package.json essa opção é identificada pelo "type": "module" ou usa a extensão .mjs. Não misturar estilos.
É um padrão para lidar com eventos assíncronos e callbacks.
Promise é um valor futuro que não está disponível agora.
Sugar syntax para Promises.
async function fazAlgumaCoisaAssincrona() {
try {
let retorno = await servicoAssincrono(...);
console.log(retorno);
} catch (err) {
console.error('Error: ', err);
}
}async informa que essa função será pausada esperando por um retorno assíncrono. O ponto exato de pausa é identificado por await. Durante a pausa o fluxo de execução do js continua. Após o retorno assíncrono, a função pausada é retomada.
No caso de precisar esperar por várias funções assíncronas serem concluídas:
await Promise.all([
fun1(),
func2(),
...
funcn()
]);Aumentar o limite de user watches no sistema operacional.
Verificar o limite atual:
cat /proc/sys/fs/inotify/max_user_watchesAjustar o novo limite no arquivo /etc/sysctl.conf:
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -pO comando acima acrescenta a linha fs.inotify.max_user_watches=524288 ao arquivo /etc/sysctl.conf e em seguida pede ao kernel para recarregar as novas configurações.
Verificar o novo limite:
cat /proc/sys/fs/inotify/max_user_watches