Node.js e Express: Utilizando React como sua view engine

Compartilhando seus componentes no lado do servidor!

Poderosa combinação para sua template engine! — Créditos da Imagem para Avanthika Meenakshi

Para tudo. E preste atenção na afirmação seguinte: Esse artigo NÃO É sobre React isomórfico, universal, <nova-buzz-word-aqui>, para isso, existem soluções mais robustas como Next.js, Razzle ou GatsbyJS.

O meu caso hoje é o bom e velho template engine da linguagem de servidor que você trabalha. Para minha sorte (ou não), o projeto está em Node.js.

Nosso cenário atual

O projeto gera relatórios estáticos e tem a seguinte estrutura:

  • Está conectado com 4 serviços diferentes
  • Em torno de 8 telas

Estamos satisfeitos com a estruturação e implementação na parte do servidor.

Percebemos algumas inconsistências na parta da interface, que está utilizando EJS, com isso, resolvemos que era um momento adequado para repensar essa parte da aplicação.

Problemas comuns, independente da tecnologia

Ano vai, ano vem, framework vai, framework vem e os problemas de engenharia de interface do usuário são praticamente idênticos. Para citar alguns:

  • HTML diferente, para um mesmo tipo de componente
  • CSS diferente, para um mesmo tipo de componente
  • Modificações para "esse caso especial"
  • Cores, tamanhos de fonte, peso de texto etc
  • Múltiplas implementações de comportamento/interação semelhantes

Eu presenciei isso com CSS e MooTools, e preciso dizer que também vejo isso com CSS-in-JS e React. Isso não é um problema relacionado a tecnologia, é um problema de planejamento e execução.

Sendo sincero, com as duas últimas tecnologias citadas acima, a frequência é bem menor. Desenvolvedores estão mais familiarizados com conceitos como encapsulamento, responsabilidade única etc. Tudo é um reflexo de um material de maior qualidade para educar o uso desses novos frameworks.

Achando uma solução para nosso o contexto

A um tempo atrás, nós investimos em uma estrutura de componentes em React. Está em produção em várias partes da empresa, com boilerplates e scaffolding automatizados para novas equipes/projetos, uma estrutura de SPA/PWA bem robusta.

Mas nós não queríamos reescrever essa aplicação, ela estava funcionando muito bem obrigado. Queríamos reutilizar todo esse investimento em componentes React, apenas na camada da view dessa aplicação.

A primeira idéia que venho em mente foi:

  • É só carregar o React na view do ejs e colocar um container para renderizar a aplicação.

Bem, isso funciona. Mas alguns problemas com isso:

  • Iríamos precisar manter os fragmentos de ejs e React (view, partials, etc)
  • Precisaríamos injetar os dados no HTML da view, para podermos ler no JS
  • Propenso a futuras confusões/erros por causa dessa fragmentação

Colocando React no Express

Ao procurar melhores soluções, acabamos encontrando:

A idéia da biblioteca é resumida em uma frase:

  • Essa é uma view engine para Express que renderiza componentes React no servidor. É retornado marcação estática e não suporta a montagem dessas views-components como componentes no navegador. — express-react-views

Fantástico! Era exatamente isso que estávamos procurando. Toda a lógica e dados corretos, já estavam sendo passados para a view, queríamos mudar a sua sintaxe e reutilizar nossos componentes, de algo como:

<%- include('header'); -%>
<h1>Title</h1>
<p>My page</p>
<%- include('footer'); -%>

Para:

const { Header, Footer, Text } = require('@nosso-styleguide');
<Header />
<Text.Heading1>Title</Text.Heading1>
<Text.Base>My page</Text.Base>
<Footer />

A configuração é bem simples, ao iniciar seu servidor Express:

const express = require('express');
const path = require('path');
const { createEngine } = require('express-react-views');
const server = express();

server.set('views', path.resolve('./views'); // [A]
server.set('view engine', 'js'); // [B]
server.engine('js', createEngine()); // [C]
  • // [A]: Aqui estamos definindo o caminho que ''views" serão definidas. Isso irá refletir na utilização das suas rotas.

Por exemplo:

app.get(‘/’, (res, req) => res.render(‘home’, { name: ‘Eduardo’ }));

Em res.render('home', ...você precisa ter um arquivo ./views/home.js para ser enviado como uma view nessa requisição e { name: 'Eduardo' } será passado como props para o seu componente.

  • // [B]: Estamos dizendo ao Express qual será o tipo de view engine vamos usar.
  • // [C]: Essa é a extensão dos arquivos que serão transformados pelo express-react-views, você pode definir qualquer outra extensão, .jsx por exemplo, para diferenciar esses arquivos no seu servidor.

Finalizando

Com essa abordagem, conseguimos:

  • Eliminar ejs completamente da nossa base código
  • Reutilizar nossos componentes já criados em uma aplicação 100% renderizada no servidor
  • Unificar a linguagem e mentalidade sobre criação de views e componentes (no final, tudo é um componente)
  • Remover "mais uma coisa para aprender" no processo de integração de novos desenvolvedores ou pessoas de outra equipe

Ah! Uma coisa importante que vale mencionar:

É isso aí galera, valeu! 👋 🙏