Frontend Web

Tecnologias Utilizadas

O frontend web tem como base os seguintes frameworks JavaScript:

  • React, como alicerce da arquitetura

  • Next.js, para estrutura geral da aplicação SPA (Single Page Application)

  • PrimeReact, como suite de componentes de UI

  • PrimeFlex, para tema, layouts e estilos padronizados

  • PrimeIcons, complemento de ícones do PrimeReact

  • FontAwesome free, catálogo de ícones amplamente usado

  • Normalize, reset de CSS

  • Cloudsupport for React, que oferece componentes estruturais

Os apps de frontend web utilizam como dependência a biblioteca Node react-cloudsupport, que inclui módulos e componentes para aumentar produtividade dos desenvolvedores bem como auxiliar o cumprimento dos padrões e convenções de código definidos ao longo deste manual. Dessa forma o código-fonte dos projetos fica enxuto e o desenvolvedor poderá focar naquilo que lhe é útil: construir as páginas.

Considere o exemplo cloudsupport-archetype-frontweb como ponto de partida para novos projetos bem como para acompanhar a leitura deste manual e melhor assimilar os conceitos.

Observação: O Cloudsupport não é restrito ao Next.js e PrimeReact. Conforme a necessidade do projeto, outros frameworks podem ser utilizados, como por exemplo a suite de componentes de UI Mantine ou PatternFly. O Next.js e PrimeReact são indicados para aplicações de uso geral e serão considerados nas seções seguintes.

Funcionalidades da Arquitetura

São funcionalidades oferecidas pela biblioteca Cloudsupport for React:

  • Módulo que oferece uma solução de profile configurável em runtime, em que as propriedades por ambiente podem ser definidas após o build da aplicação, como, por exemplo, no momento da execução do container Docker.

  • Hook useProfile para acesso ao profile.

  • Componente que exibe aviso de que a aplicação tem atualização pendente, quando há mudanças no profile.

  • Integração OIDC, com suporte a todos os tokens (JWT, Refresh Token, ID Token e User Info), através de extensões e pré-configuração do framework React OIDC Context.

  • Componente AuthRequired para proteger páginas que requerem autenticação via SSO OIDC.

  • Injeção automática do Access Token (JWT) nos requests webservice, o que permite autenticar de maneira transparente as requisições para o backend.

  • Injeção automática de parâmetro nas requisições webservice que permite ao backend identificar a origem das requisições (nome e versão da aplicação de frontend).

  • Rotina automática de refresh do Access Token (JWT), de forma a desonerar o desenvolvedor do esforço de manter a autenticação OIDC viva.

  • Fluxo de redirect de pós login, que faz retorno para a página onde o usuário estava antes da autenticação, preservando-se os parâmetros iniciais de URL.

  • Fluxo de redirect de pós logout, em que o OIDC redireciona o usuário para uma página de “sessão encerrada” da aplicação.

  • Módulo para propagação de logout para todas as abas do browser.

  • Componente React integrado ao OIDC que exibe aviso de sessão expirada.

  • Hook useAuth para simplificar o acesso aos dados do usuário autenticado em qualquer página/componente.

  • Suporte a execução em “Modo Desenvolvedor”, que permite login fake do OIDC (mock do useAuth) com base em propriedades locais do profile, evitando necessidade de um servidor OIDC IdP local.

  • Hook useToast que fornece Toast global para que qualquer página/componente possa emitir mensagens.

  • Hook useProcessing que fornece API para exibição de indicador de processamento (notifyStart() e notifyStop()), acessível em qualquer página/componente, com suporte a tratamento de requisições concorrentes.

  • Suporte a timeout de request webservice via Networking.fetch(), que estende o fetch do JavaScript.

  • Componentes de UI complementares ao PrimeReact (ErrorMessage, Field, LoadingBar, RefreshingIcon, RowExpansionBox, etc).

    • Para aplicações móveis, o Cloudsupport for React Native fornece uma suite ampla de componentes de interface gráfica, que inclui tipografia, formulários, validações, mídia, popups, menus, efeitos, etc.

Estrutura de Camadas

Os apps de frontend web possuem as seguintes camadas:

  • Camada de Apresentação (Pages), engloba os componentes que representam as páginas web.

  • Camada de Integração (Remotes), módulos que fazem a comunicação com serviços externos, i.e., que consome os webservices dos microsserviços de backend.

  • Camada de Negócio (Services), composta por funcionalidades de negócio providas no próprio frontend web.

A camada de negócio em aplicações de frontend web tende a ser pequena ou mesmo inexistir, pois as regras de negócio são providas tipicamente pelo backend. Ela existe, por exemplo, em aplicações web que precisam oferecer funcionalidades de maneira offline utilizando o banco de dados local do browser. Ressalta-se que as regras de negócio implementadas no frontend web são passíveis, sem muito esforço, de violação, pois o código pode ser alterado pelo usuário final. É importante que todas as regras sejam sempre validadas quando enviadas para o backend. A camada de negócio em frontend web não será escopo deste manual, em razão de sua relevância reduzida, conforme mencionado.

Estrutura de Arquivos

Os apps de frontend web possuem a seguinte estrutura de pastas e arquivos:

package.json
public/
app/

O arquivo package.json é o descritor Node do projeto. Nele é configurado o uso da biblioteca react-cloudsupport e frameworks associados, como o Next.js e PrimeReact.

A pasta public é definida pelo Next.js. Seu conteúdo sugerido é:

Item Descrição
favicon/ Pasta com os arquivos de favicon para Android, iOS e web.
resources/ Pasta com os resources que forem necessários (imagens, scripts, CSS).
profile.json Arquivo definido pelo Cloudsupport que contém as propriedades da aplicação para o ambiente local.

O profile.json será ajustado em tempo de execução conforme as configurações de cada ambiente, como o de teste, homologação ou produção.

A pasta app contém o código-fonte de aplicação em aderência aos padrões do App Router do Next.js. A estrutura sugerida para esta pasta é:

Item Descrição
(pages) Camada de apresentanção; Contém os componentes de página web.
remotes Camada de funcionalidades remotas; Contém os módulos para comunicação com os microsserviços de backend.
services Camada de negócio; Contém os componentes que implementam regras de negócio, se for o caso.
components Contém componentes compartilhados para uso em páginas web.
util Contém módulos com funções estáticas utilitárias.
favicon.ico Arquivo principal de favicon.

Neste manual, o termo “componente” usualmente faz referência a componente React. O termo “módulo” faz referência a qualquer módulo JavaScript, que pode exportar constantes, objetos, funções e componentes. Cabe destacar que um componente React é também uma função, porém destinada a uso na interface gráfica, conforme ciclo de vida do React.

Diretrizes Gerais

  • Utilizar preferencialmente JavaScript puro, em conformidade com ECMAScript 6 (ES6), podendo, se for necessidade do projeto, considerar TypeScript. Este manual incluirá diretrizes e exemplos sempre baseados em JavaScript.

  • Utilizar a solução App Router do framework Next.js para organização dos componentes de página e tratamento de roteamento (navegação).

  • Preferir que funções e códigos assíncronos sejam implementados por meio de Promises em lugar da sintaxe async/await.

  • Declarar componentes React na forma de componentes funcionais por meio da construção de funções JavaScript e uso dos Hooks. O React não recomenda a utilização de classes e orientação a objetos.

  • Evitar os operadores padrões de (des)igualdade == e != devido à complexidade da semântica IsLooselyEqual do JavaScript/TypeScript. Considerar os operadores estritos === ou !== e verificar explicitamente pelo undefined e pelo null sempre que for o caso.

    Os operadores padrões são desencorajados devido às suas “ambiguidades” lógicas, como esta exemplificada a seguir:

      a = ""
      b = null
    
      a == true  // retorna false
      b == true  // retorna false
      b == a     // retorna false
    

    Sobre loose equality: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#loose_equality_using

  • Evitar usar o operador || para efeito de “coalesce” ou valor padrão. Considerar ??, que é o verdadeiro Nullish coalescing operator.

    Exemplos:

      // retorna "default" se var1 for qualquer valor Falsy (exemplo: a="" ou a=0)
      var1 || "default" 
    
      // retorna "default" se e somente se var1 for null ou undefined
      var1 ?? "default" 
    
  • Evitar implicit coercion.

    Em vez de:

      if (a) {
          // ...
      }
    

    fazer:

      if (a !== null && a !== undefined) {
          // ...
      }
    
  • Atenção aos valores Falsy no JavaScript (convertidos para false em contextos Boolean): false, 0, -0, 0n, "", null, undefine e NaN.

    Evitar implicit coercion e os operadores ==, != e || (para fins de valor padrão) mitiga substancialmente os problemas causados pelos valores Falsy no JavaScript.

  • Não utilizar a sintaxe antiga de módulos do Node.js, o sistema CommonJS, a citar o comando require() e a variável global module.exports. Considere o padrão atual, com as diretivas import e export.

  • Identar o código preferencialmente com 4 espaços e evitar o caractere de tabulação \t.

Convenções de Nomes

São convenções de nomes recomendadas:

Elemento Regra
Pasta CamelCase iniciando em minúsculo.
Arquivo CamelCase iniciando em minúsculo.
Variáveis JavaScript CamelCase iniciando em minúsculo.
Constantes JavaScript Em maiúsculo, com termos separados por _.
Componentes React CamelCase iniciando em maiúsculo.
Funções JavaScript (excetuando Componentes React) CamelCase iniciando em minúsculo.

Propriedades por Ambiente

A arquitetura fornece uma solução de profile, que permite definir as propriedades da aplicação por ambiente, como, por exemplo, ambiente local, teste / homologação ou produção. O profile é carregado em tempo de execução, ou seja, seria possível utilizar a mesma imagem Docker em qualquer ambiente.

As propriedades são definidas no arquivo public/profile.json e podem ser complementadas por JSON definido na variável de ambiente CLOUDSUPPORT_PROFILE do sistema operacional.

O profile pode ser utilizado livremente pelo desenvolvedor para definir variáveis que devem ser ajustadas conforme o ambiente de execução.

Exemplo de profile:

{
    "endpointPagamento": "https://gateway.dominio.com/api",
    "chaveAcessoIntegrador": "1A938BC02F19DCCD029D94"
}

Recomenda-se evitar a parametrização da aplicação em tempo de compilação (por scripts de build-time), pois nesse caso haverá necessidade de gerar imagens Docker distintas para cada ambiente.

As propriedades são acessíveis pelo Hook useProfile():

const profile = useProfile();

profile.endpointPagamento; // Retorna "https://gateway.dominio.com/api"

O carregamento das propriedades de profile ocorre a partir do endpoint /.well-known/profile.json. Esse endpoint pode ser mapeado no arquivo next.config.js do Next.js. O projeto do arquétipo exemplifica a configuração.

Aviso de Atualização

O Cloudsupport for React inclui uma funcionalidade que permite emitir aviso para o usuário de que há atualização pendente. O aviso por padrão é um banner do topo da página, que inclui opção para o usuário aplicar a atualização.

Exemplo:

Aviso de Atualização

Cabe recordar que aplicações em React são SPA (Single Page Application), tal que uma vez carregadas no browser, o usuário fará a navegação entre todas as páginas de maneira virtual, ou seja, o browser não fará a aquisição das páginas junto ao servidor web durante a navegação. Isso ocorre porque o código-fonte React (JavaScript) já foi carregado.

Se não houver um tratamento em nível de arquitetura para detecção de que o servidor web possui uma nova versão do frontend, o usuário poderá permanecer muito tempo navegando nas páginas de uma aplicação defasada, até que ocorra um refresh real ou abertura de nova janela/aba do navegador.

O Cloudsupport for React possui um componente interno que monitora o profile, verificando periodicamente se há mudança no retorno do endpoint /.well-known/profile.json, como, por exemplo, mudança na propriedade appVersion do profile. Ocorrendo mudança, o componente emite sinal de que a aplicação precisa ser atualizada.

Note que o processo de implantação de nova versão do frontend no ambiente de produção deve garantir que algum campo do profile seja atualizado. Sugere-se o campo appVersion. O projeto de arquétipo possui um exemplo de Deployment para Kubernetes com script que injeta automaticamente o appVersion no profile de acordo com a tag da imagem Docker no momento da subida do Pod/container.

Próximos Passos

As seções Apresentação e Integração explanam sobre como desenvolver páginas web e como realizar a comunicação com o backend. A seção Configuração mostra como habilitar e configurar a arquitetura. Por sim, a seção Documentação da API contém a referência completa de todos os módulos e componentes da arquitetura.