Configurando estrutura inicial de uma aplicação Node.js

Utilizando express, nodemon e sucrase para usar novas sintaxes javascript

Essa é a primeira parte de uma série de artigos configurando estrutura inicial de uma aplicação Node.js usando express.

Estrutura inicial de um projeto Node.js

Defina o nome do diretório/projeto, acesse-o via terminal e digite yarn init -y. Supondo que esteja usando yarn como gerenciador de pacotes e que o comando esteja configurado no path do sistema operacional (o processo é similar caso esteja usando npm).

Após rodar o comando, abra o diretório com o Visual Studio Code ou qualquer outro editor da sua preferência. Na raíz do projeto, crie um diretório src que é onde vamos colocar todos os códigos referentes ao projeto.

Dentro do diretório src adicione 3 arquivos: app.js, routes.js e server.js. Esse tipo de organização, além de separar responsabilidades e deixar o código mais legível, facilita no processo de teste (não chamar recursos que não serão utilizados).

Instalando e configurando o framework Express

Chegou a hora de instalar o nosso framework que vai prover os recursos necessários de rotas, middlewares e demais funções que facilitam a criação da nossa API. Nosso servidor Node.js.

No terminal digite: yarn add express. Após concluir a instalação já estamos prontos para criar nossa API.

Abra o arquivo src/app.js que criamos anteriormente e vamos iniciar o processo de configuração do nosso servidor. Tendo como base que já há um certo conhecimento sobre as tecnologias utilizadas aqui, sigamos para o código:

const express = require("express");
const routes = require("./routes");

class App {
  constructor() {
    this.server = express();

    this.middlewares();
    this.routes();
  }

  middlewares() {
    this.server.use(express.json());
  }

  routes() {
    this.server.use(routes);
  }
}

module.exports = new App().server;

No construtor (inicia automaticamente ao instanciar a classe), criamos a instância de server (nosso express), chamamos os middlewares que a aplicação terá (por enquanto apenas o express.json()) e iniciamos as nossas rotas (que importamos do arquivos que criamos e vamos definir no próximo passo). No final, exportamos apenas o que é necessário, no caso, nossa instância de server que já já veremos onde ela será chamada.

Agora vamos configurar o arquivo src/routes.js que criamos anteriormente.

const { Router } = require("express");
const routes = new Router();

routes.get("/", (req, res) => {
  return res.json({ message: "Hello World!" });
});

module.exports = routes;

Todas as nossas rotas serão definidas nesse arquivo. Simples, não? Assim, organizamos nosso código e deixamos ele mais legível.

Para vermos o servidor funcionando, vamos configurar o arquivo que irá iniciar nosso servidor. Abra o arquivo src/server.js que criamos anteriormente e adicione o seguinte trecho de código:

const app = require("./app");

app.listen(3333);

Veja que o arquivo src/server.js importa o arquivo app que instancia o express. Abra o terminal e rode: node src/server.js. Se você abrir o navegador e digitar http://localhost:3333 receberá o retorno do json que retornamos.

Retorno json após acessar localhost:3333

Configurando Nodemon e sucrase

O nodemon, como está decrito no próprio site, é um utilitário que monitora todas as alterações nos arquivos da aplicação e reinicia automaticamente o servidor quando for necessário.

Já o sucrase vai nos permitir trabalhar com novas sintaxes do javascript, mesmo quando o usuário não está usando versões mais recentes dos navegadores (o sucrase vai parsear sintaxe nova com sintaxe entendível por navegadores que ainda não suportam).

Instale-os: yarn add nodemon sucrase -D (-D é para dependências de desenvolvimento, apenas).

Próximo passo é substituir a sintaxe antiga (usando require para importar os módulos). Abra o arquivo src.app.js e compare com a sintaxe atual no código abaixo:

import express from "express";
import routes from "./routes";

class App {
  constructor() {
    this.server = express();

    this.middlewares();
    this.routes();
  }

  middlewares() {
    this.server.use(express.json());
  }

  routes() {
    this.server.use(routes);
  }
}

export default new App().server;

Perceba que, tanto a maneira de importar quanto a maneira de exportar estão, agora, usando a nova sintaxe do Node.js. Vamos fazer isso nos demais arquivos.

Arquivo src/routes.js:

import { Router } from "express";
const routes = new Router();

routes.get("/", (req, res) => {
  return res.json({ message: "Hello World!" });
});

export default routes;

Arquivo src/server.js:

import app from "./app";

app.listen(3333);

Mas ainda não vai funcionar! Se você tentar rodar a aplicação (node src/server.js), vai descobrir. Vamos adicionar um script no package.json que ao rodar, ele execute, tanto o nodemon quanto o sucrase.

Abra o arquivo package.json e adicione a instrução, logo após o license, "script". Abaixo o exemplo de todo o arquivo package.json:

{
  "name": "guia-comercial",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "nodemon src/server.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.1",
    "sucrase": "^3.10.1"
  }
}

Agora, um último passo antes de rodar o servidor novamente. Crie um arquivo nodemon.json na raíz do projeto (fora do diretório src) e adicione o seguinte objeto:

{
  "execMap": {
    "js": "node -r sucrase/register"
  }
}

O código acima garante que ao rodar o script yarn dev (como configuramos mais acima), além de rodar o nodemon, executará o sucrase antes. Dessa forma, o servidor inicia e reinicia sempre que necessário e, usa as sintaxes mais recentes do javascript.

Para saber mais dos porquês usarmos a nova sintaxe, quais os benefícios (além de manter um padrão com o frontend - feito com ReactJS, por exemplo) ou qualquer instrução nos arquivos de configuração, veja a documentação desses utilitários que usamos.

Para testar o que acabamos de fazer, inicie o servidor novamente usando o novo script: yarn dev. Basta abrir o http://localhost:3333 e ver que tudo continua funcionando. Se alterar a resposta json da rota que criamos, no momento que salvar, perceberá que o nodemon vai se encarregar de reiniciar o servidor de forma automática para nós.

Configurando debug com nodemon e sucrase

Como nem tudo na vida é console.log(), vou deixar como dica final, a configuração do debug no VS Code com nodemon e sucrase.

Abra o package.json e adicione mais uma instrução em "script":

{
  "name": "guia-comercial",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "dev": "nodemon src/server.js",
    "dev:debug": "nodemon --inspect src/server.js"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.1",
    "sucrase": "^3.10.1"
  }
}

Perceba que foi adicionado a instrução "dev:debug": "nodemon --inspect src/server.js" dentro do objeto "scripts: {}".

Ao clicar em Add Configuration e selecionar Node, vai ser criado o arquivo .vscode/launch.json na raíz do projeto. Basta seguir as instruções abaixo e a configuração está pronta:

Configurando debug no VS Code

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "attach",
      "name": "Launch Program",
      "restart": true,
      "skipFiles": ["<node_internals>/**"],
      "protocol": "inspector"
    }
  ]
}

Perceba que há algumas diferenças entre o arquivo gerado e o exemplo acima. Adicione o que falta e faça os ajustes necessários para que fique similar ao mostrado aqui.

Pronto! Agora basta iniciar a aplicação com yarn dev:debug (script que adicionamos no package.json) e fazer os debugs necessários.

Testando o debug do VS Code com Node.js, nodemon e sucrase

Para ler a segunda parte dessa série: Mantenha o mesmo padrão de escrita no código usando ESLint, Prettier e editorConfig.

Obrigado pela leitura.

Outras postagens interessantes:

Comentários