Conteúdo sobre Front-end por Matheus Pergoli.

Blog.

Setup para Desenvolvimento Backend com Node / TS / Vitest

Author image

Matheus Pergoli

Cover image

Guia de setup para um ambiente de desenvolvimento Backend
com Node / TS / Vitest

Neste setup vamos utilizar algumas tecnologias para nos ajudar a manter um código bem escrito e organizado seguindo as boas práticas


Lista das dependências que vamos utilizar no setup

  • prettier

  • typescript

  • @types/node

  • eslint eslint-plugin-promise eslint-plugin-import eslint-plugin-n @typescript-eslint/eslint-plugin eslint-config-standard-with-typescript

  • lint-staged

  • husky

  • commitlint

  • vitest @vitest/coverage-c8


Vamos começar a instalar um por um e explicando cada configuração

Antes de tudo vamos iniciar um projeto com npm

npm init -y

E vamos também criar um repositório git dentro do nosso projeto

git init

Precisamos também do arquivo .gitignore para excluirmos alguns arquivos a serem enviados para o GitHub
Crie um na raiz do projeto e adicione o seguinte conteudo:

node_modules
dist
coverage

A pasta node_modules é muito grande e não precisamos enviar para o GitHub
A pasta dist é onde ficará todo nosso código javascript compilado
E a pasta coverage é onde ficará o coverage dos nossos testes e também não precisamos enviar

Instalação das dependências

  • prettier

Para formatação e organização do nosso código

npm install -D prettier

Vamos também utilizar um arquivo de configuração para o prettier
Crie na raiz do seu projeto um arquivo chamado .prettierrc.json e adicione o seguinte conteúdo:

{
  "tabWidth": 2,
  "semi": false,
  "useTabs": false,
  "endOfLine": "lf",
  "printWidth": 90,
  "singleQuote": true,
  "jsxSingleQuote": true,
  "bracketSpacing": true,
  "bracketSameLine": true,
  "trailingComma": "none"
}

E também vamos criar um arquivo .prettierignore para que ele ignore algumas pastas/arquivos
Adicione o seguinte conteúdo:

node_modules
dist
coverage


  • typescript

Pacote nescessário para utilização do typescript em nosso projeto

npm install -D typescript

Precisamos de um arquivo de configuração para o typescript
Crie na raiz do projeto um arquivo chamado tsconfig.json e adicione o seguinte conteúdo:

{
  "compilerOptions": {
    "outDir": "./dist",
    "module": "CommonJS",
    "rootDir": ".",
    "target": "ES2020",
    "esModuleInterop": true,
    "allowJs": true,
    "strict": true,
    "strictNullChecks": true
  }
}

Explicação do arquivo:

outDir: Pasta que será criada para manter todo nosso código compilado
module: Para podermos utilizar import/export mas compilar o código para o formato require
rootDir: Onde ficara nosso projeto central
target: Versão para qual o typescript será compilado
esModuleInterop: Converte import/export para require em módulos que ainda usam esse formato
allowJs: Permite incluir arquivos JS na compilação para pasta Dist
strict: Para habilitar o modo estrito do typescript para melhor qualidade do código
strictNullChecks: Habilita uma verificação mais rigorosa para valores null & undefined

Também vamos criar um outro arquivo para utilizarmos na hora de fazer o build do TS
Crie um arquivo chamado tsconfig.build.json e adicione o seguinte conteúdo:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "rootDir": "./src"
  },
  "include": ["src"],
  "exclude": ["**/*.spec.ts", "**/*.test.ts"]
}

Como esse arquivo será utilizado na hora de fazer o build da aplicação, vamos utilizar o exclude para excluir arquivos que não queremos dentro do nosso build, e também vamos utilizar o include e pegar apenas os arquivos dentro da pasta src

  • @types/node

npm install -D @types/node

Pacote que adiciona tipagens para o Node que nos ajuda a evitar alguns erros bobos


  • eslint eslint-plugin-promise eslint-plugin-import eslint-plugin-n @typescript-eslint/eslint-plugin eslint-config-standard-with-typescript

npm install -D eslint eslint-plugin-promise eslint-plugin-import eslint-plugin-n @typescript-eslint/eslint-plugin eslint-config-standard-with-typescript

Como vamos utilizar o padrão Standard Javascript precisamos incluir todos esses pacotes para que o eslint consiga configurar esse padrão para o typescript

Precisamos também de mais dois arquivos de configuração para o ESLINT
Crie na raiz do projeto o arquivo chamado .eslintrc.json e adicione o seguinte conteúdo:

{
  "extends": "standard-with-typescript",
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "rules": {
    "@typescript-eslint/strict-boolean-expressions": "off",
    "@typescript-eslint/space-before-function-paren": "off"
  }
}

Explicação do arquivo:

extends: Extensão das regras padrões do ESLINT para adicionar mais regras para o typescript
parserOptions: Opções que podemos passar para análise do parser do ESLINT
project: Para usar as configurações definidas no arquivo tsconfig.json do nosso projeto
rules: Onde podemos habilitar ou desabilitar regras do ESLINT

Também precisamos de outro arquivo chamado .eslintignore que vai sinalizar ao ESLINT quais pastas/arquivos ele deve ignorar na análise de código, crie um e adicione o seguinte conteúdo:

node_modules
dist
coverage


  • lint-staged

Pacote que vamos utilizar para rodar scripts apenas em arquivos modificados na área staged do Git

npm install -D lint-staged

Precisamos de um arquivo de configuração para o lint-staged
Crie na raiz do projeto um arquivo chamado .lintstagedrc.json e adicione o seguinte conteúdo:

{
  "*.ts": ["eslint 'src/**/*' --fix"]
}

Fazendo isso estamos dizendo para o lint-staged rodar o comando em qualquer arquivo dentro de qualquer pasta dentro de src que tenha a extensão .ts

  • husky

Pacote para podermos adicionar hooks ao git fazendo com que ele rode scripts durante alguns estágios que escolhermos

npm install -D husky

Para habilitar os hooks rode o seguinte comando:

npx husky install

Vamos adicionar um hook que vai rodar um script sempre que fizermos um commit

npx husky add .husky/pre-commit "npx lint-staged"

Esse comando cria na raiz do seu projeto uma pasta chamada .husky onde ficará todos os seus hooks e os scripts que vão ser rodados sempre que alguma ação definida acontecer

Vamos utilizar o lint-staged para rodar scripts nos arquivos modificados do git
O lint-staged será o responsável por rodar os scripts que definimos dentro do arquivo .lintstagedrc.json

  • commitlint

Para padronizar os commits seguindo o Conventional commits

De baixo dos panos é criado um hook que verifica cada commit e valida se estamos seguindo o padrão Conventional commits

npm install -D @commitlint/config-conventional @commitlint/cli

Vamos precisar criar mais um arquivo de configuração para o commitlint
Crie um arquivo chamado .commitlintrc.json e adicione o seguinte conteúdo:

{ "extends": ["@commitlint/config-conventional"] }

Após instalar o husky e o commitlint e criado o arquivo de configuração use o seguinte comando:

npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'

Feito isso seu linter de commits deve funcionar normalmente

  • vitest @vitest/coverage-c8

Pacotes nescessários para utilização do Vitest

npm install -D vitest @vitest/coverage-c8

Após terminar a instalação dos pacotes vamos criar o seguinte arquivo: vitest.config.ts
E dentro desse arquivo adicione o seguinte conteúdo:

import { defineConfig } from 'vitest/config'

export default defineConfig({
  test: {
    globals: true,
    watch: true,
    coverage: {
      enabled: true,
      include: ['src/**/*.ts'],
      exclude: ['src/**/index.ts', 'src/**/*.spec.ts', 'src/**/test/**']
    }
  }
})

Explicação do arquivo:

Precisamos importar o defineConfig do Vitest para criarmos uma configuração que será utilizada nos testes do Vitest

test:
Onde ficará as configurações voltadas para os testes
globals: Por padrão o Vitest não expõe sua API para ser utilizada sem importações assim como Jest faz, então para conseguirmos ter o mesmo comportamento do Jest e não precisar ficar importando describre, test, it etc... podemos colocar essa opção como true
watch: Para ativar o modo watch nos testes
coverage: Onde ficará as configurações do coverage para os testes
enabled: Para ativar a captura de coverage dos arquivos
include: Para incluir todos os arquivos dentro de src que tenham a extensão .ts no coverage
exclude: Para excluir alguns arquivos que não queremos no coverage

Agora vamos criar dois arquivos, um para utilizarmos com testes unitários e testes de integração

Vamos criar primeiro o arquivo para testes unitários
Crie o seguinte arquivo: vitest-unit.config.ts e adicione o seguinte conteúdo:

import { mergeConfig } from 'vite'
import { defineConfig } from 'vitest/config'
import viteConfig from './vitest.config'

export default mergeConfig(
  viteConfig,
  defineConfig({
    test: {
      include: ['src/**/*.spec.ts'],
      watch: true
    }
  })
)

Explicação do arquivo:

Aqui precisamos importar o mergeConfig, defineConfig e nossa exportação do arquivo vitest.config.ts

Vamos utilizar o mergeConfig para fazer a junção de uma configuração prévia e mudar algumas coisas, nesse arquivo vamos utilizar o include para pegar apenas os arquivos .spec.ts que será nossa nomenclatura para utilizar em testes unitários

Agora a criação do arquivo de configuração para testes de integração
Crie um arquivo chamado vitest-integration.config.ts
E adicione o seguinte conteúdo:

import { mergeConfig } from 'vite'
import { defineConfig } from 'vitest/config'
import viteConfig from './vitest.config'

export default mergeConfig(
  viteConfig,
  defineConfig({
    test: {
      include: ['src/**/*.test.ts'],
      watch: true
    }
  })
)

Explicação do arquivo:

Aqui a única mudança é que vamos pegar os arquivos com a extensão .test.ts
Essa será a nossa nomenclatura para testes de integração

Agora vamos criar nossos scripts no package.json

"build": "npx tsc -p ./tsconfig.build.json",
"lint:fix": "npx eslint src/**/* --fix",
"test": "npx vitest",
"test:unit": "npm test -- --config ./vitest-unit.config.ts",
"test:integration": "npm test -- --config ./vitest-integration.config.ts"

Explicação dos scripts:

build: Script para fazer o build do typescript utilizando a flag -p para utilizarmos o arquivo que criamos para build do typescript
lint:fix: Script para rodar o eslint na aplicação
test: Para utilizar o Vitest para rodar todos os testes
test:unit:
Para utilizar o script test e adicionamos uma flag --config para utilizar o arquivo que criamos para rodar apenas em testes unitários
test:integration:
Para utilizar o script test e também adicionamos uma flag --config para utilizar o arquivo de configuração para testes unitários

Agora vamos testar se todo nosso setup está rodando corretamente

Crie na raiz do projeto uma pasta chamada src e dentro dela crie um arquivo controller.spec.ts e adicione o seguinte conteúdo:

describe('Controller Test', () => {
  test('Should pass the test', () => {
    expect(1).toBe(1)
  })
})

Após isso rode o comando:

npm run test:unit

Se o setup foi feito corretamente você deverá ver o resultado do seu primeiro teste

Vamos também testar se nossos commits estão padronizados
Rode os seguintes comandos:

git add .
git commit -m "Testando os commits"

E de novo, se o setup foi feito corretamente você deverá ver uma mensagem de erro dizendo que seu commit deve seguir o padrão definido no projeto.

Finalizamos nosso setup, agora temos tudo configurado para codar 😄

Mais Artigos

Post image

Core Javascript Principles

Aprenda sobre os princípios mais importantes do Javascript

Author image

Matheus Pergoli

Post image

Aprenda a criar uma Árvore Binária de Busca com Javascript

Aprenda como criar uma estrutura de dados de Árvore com Javascript

Author image

Matheus Pergoli