DraftCode Logo

DraftCode

HomeDesafiosSoluçõesRecursosBlog
Login
DraftCode Logo

DraftCode

DesafiosFAQ'sDiscord Icon
Criado por: Matheus Pergoli
ContatoNewsletter
    Voltar para o blog

    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 😄