Desenvolvendo um Widget Web em larga escala para seus clientes

Compartilhe

Compartilhar no facebook
Compartilhar no google
Compartilhar no twitter
Compartilhar no linkedin

Muitos serviços atuais oferecem diversos produtos que podem ser integrados como um widget no website do cliente. Dentre esse produtos, muitos envolvem recursos de atendimento e FAQ (Intercom, Zendesk), que são plugados na página do cliente, e geralmente são desenvolvidos por um time da empresa que está oferecendo esse serviço como um Software as a Service. Abordaremos aqui alguns problemas e soluções comumente encontrados no desenvolvimento de web widgets que precisam ser plugados em uma página, – e que geralmente, é uma página do cliente -, e também apresentarei um case real e comentários relativos ao desenvolvimento de tais componentes.

Enquanto trabalhava como front-end na Calamar, uma startup inteiramente focada em chatbots, tivemos a demanda de criar um app de mensagens que o cliente pudesse inserir em sua página, e seus usuários, ao acessarem a página, poderiam interagir com um robô que respondia perguntas baseadas em FAQ.

Neste artigo abordaremos problemas envolvidos na criação de um widget web, – com foco na parte front-end da solução -, propor soluções e apresentar comentários sobre escolhas que foram bem-ou-não-sucedidas.

No nosso escopo, o sucesso da solução envolve:

  • Reatividade, utilizando frameworks front-end modernas;
  • Facilidade, fácil instalação na página do cliente (self-checkout) com um simples copiar & colar de um script javascript;
  • Isolamento, do código (javascript e css) client-side da página do cliente, para o código (também client-side) do widget;
  • Escalabilidade, para que milhares de clientes possam usar o mesmo script de carregamento, modificando apenas um ID do cliente;

Isolando o seu código do código do cliente

As páginas dos seus clientes, geralmente, são caóticas. Não há como prever que tipo de ferramentas seu cliente está usando, e essas ferramentas quase sempre afetam todo os componentes da página, seja em estilo (CSS), ou até mesmo javascript, que pode modificar o DOM livremente de acordo com regras definidas pelo próprio cliente. Como separar o código do seu widget (que deve se manter consistente entre todos os seus clientes) do código do seu cliente, que você não conhece (e nem deveria), e que potencialmente pode afetar o widget com experiências indesejadas?

A resposta curta é: IFRAMES. Dentre todas as possibilidades de se implementar de um elemento embed na página, iframes foi a escolha que me deixou, surpreendentemente, mais otimista. Apesar tag da <iframe> parecer uma tecnologia remanescente da época dos dinossauros, há algumas vantagens em utilizá-lo:

  1. Iframes são mais seguros, principalmente porque o JavaScript dentro do iframe está sendo executado no contexto de outra página. É claro que há riscos, mas estamos falando de front-end, vocês já sabem que no mundo front-end nada é realmente seguro :p
  2. Não bloqueia a renderização da página, pois a página pode ser carregada enquanto o conteúdo externo (nosso widget) está sendo carregado.
  3. É a prova de falhas de Javascript na página do cliente. Ao usar um iframe, baseamos a injeção apenas na renderização de HTML, não na execução de JavaScript, logo, os erros do cliente não afetarão o iframe.
  4. Estilização fica isolada. É a nossa própria página, por isso, os únicos estilos aplicáveis ​​são provenientes da nossa própria folha de estilo :) (vamos deixar o assunto de customização para daqui a pouco ;))
  5. Testes descomplicados. Para testar se o widget funciona, criamos uma página fictícia e simplesmente colocamos o iframe lá. Como o conteúdo está em um sandbox, não precisamos nos importar com o que tem nessa página fictícia.

Arquitetando as paradas

Vivemos em um mundo onde sua framework preferida, que você aprendeu a usar mês passado, poderá ficar obsoleta no mês que vem, e isso se dá pela alta rotatividade e constante reinvenção das frameworks JavaScript modernas (tudo bem, não chore, é normal). Mas (felizmente) hoje em dia todas elas seguem tecnologias semelhantes, e como podemos usar nossa a framework preferida com iframes? COMUNIDADES! Seja React, Vue.js, Angular ou Whatever.js que você esteja usando, alguém já disponibilizou um componente que permite encapsular todo o seu aplicativo ou ‘por componente’ em um iFrame. Veja esse essa lib do React como exemplo (que a propósito, foi criada por uns caras do Zendesk, um serviço que também disponibiliza um widget para ser instalado na página do cliente), ou esse fiddle em Vue.js.

No nosso caso, o app consistia em um pequeno overengineering. A arquitetura com iframes foi definida assim:

  1. Um bloco de script para que o cliente insira na página dele (aqui podemos setar algumas variáveis da window, além de termos um link para carregar scripts muito mais complexos que virão a seguir)
  2. Um script para carregar todo o bundle JS em um iFrame dentro da página do cliente (lembra de ser a prova de falhas do javascript do cliente?)
  3. Esse iFrame, que possui só o bundle JS da aplicação, fica encarregado por montar a aplicação no <body> da página do cliente (precisamos de uma <div> encapsulando seus componentes iFrame do app por questões de responsividade e uma ou outra estilização)
  4. Nosso componente iFrame, agora dentro da aplicação utilizando uma dessas libs que comentei acima, que será a área isolada com o chat, botões, e todo o resto da lógica divertida da aplicação

Complicado né? Fazendo um esboço da nossa UI, temos algo como esse wireframe assim:

Nesse widget, temos um botão que controla a abertura e fechamento da janela de chat, e uma janela de chat animada e responsiva.

Você pode ter se perguntado: por que dois iFrames? IFrames conseguem ser bem chatos com mouse events (sério), isto é, a experiência padrão em um iFrame é bloquear os cliques sem passar o evento para elementos do DOM abaixo. Após alguns dias de testes e tentativas, e também por questões de arquitetura por componentes, decidimos utilizar dois iframes para ganhar também esse espacinho clicável na página no cliente.

Para o ponto de entrada de conexão com nosso back-end, utilizamos uma tecnologia de socket chamada Phoenix Channels. Phoenix é um framework de desenvolvimento web escrito em Elixir que implementa padrões MVC. Além disso, ele possui uma feature poderosa chamada Channels, que nos permite adicionar facilmente recursos soft-realtime aos nossos aplicativos, e são baseados em uma ideia simples – enviar e receber mensagens. O Phoenix disponibiliza uma biblioteca JavaScript para fácil implantação do lado do cliente, ou, para nós, implementar uma conexão socket no nosso widget desenvolvido em React. Elixir tem a grande vantagem de ser distribuído, tolerante a falhas e escala muito bem em aplicações que demandam alta conectividade e troca de mensagens, por isso, quando estamos dizendo de uma demanda de milhões de clientes conectados ao mesmo tempo, Elixir destaca-se como um ótimo candidato.

Como tínhamos uma aplicação bem complexa, com cores e nomes customizáveis, imagens de branding, logo do cliente, etc, tudo precisa ser recebido do back-end antes de ser renderizado na página do cliente. Então como persistir essas informações de forma confiável em uma única fonte de verdade no lado do cliente? A resposta é (pasmem): STORES. Redux é incrível. Sua arquitetura one-way dataflow com actions, reducers e store é excelente para guardar o estado de uma aplicação de mensageria como a nossa. E com a ajuda do redux-thunk, podemos passar todas as mensagens recebidas do back-end por reducers, e de acordo com o tipo e payload da mensagem, podemos alterar o estado da nossa aplicação de acordo e de forma consistente na representação da interface.

Conclusões

Fazer um web widget é um desafio de engenharia complexo, envolvendo muitos tópicos de arquitetura tanto de front-end quanto back-end. Segurança, performance e consistência são fatores essenciais em qualquer solução front-end, ainda mais se tratando de uma solução escalável para milhares de clientes e milhões de usuários. No próximo artigo, construiremos um widget chat funcional utilizando ferramentas modernas do mercado, e com isso, poderemos desbravar mais profundamente os problemas e sucessos envolvidos no desenvolvimento de um widget web.

Gabriel Cencic

Gabriel Cencic

Gabriel Cencic, formado em Física Computacional na USP, trabalha atualmente como Engenheiro Front-End na Wavy Global. Entusiasta em jogos, fã de Adventure Time, robôs e dank memes.

Deixe um comentário

%d blogueiros gostam disto: