Interação entre dois projetos Front-end utilizando postMessage
17
0

Interação entre dois projetos Front-end utilizando postMessage

Há algum tempo precisei resolver a seguinte questão: Tenho um projeto React embutido com a tag em outro projeto Vue. Como fazer com que o clique de um botão no meu projeto FrontEnd A (React) executar uma ação no projeto FrontEnd B (Vue)?

Matheus Odilon
3 min
17
0
Email image

Há algum tempo precisei resolver a seguinte questão: Tenho um projeto React embutido com a tag <embed /> em outro projeto Vue. Como fazer com que o clique de um botão no meu projeto FrontEnd A (React) executar uma ação no projeto FrontEnd B (Vue)?

Para ser mais explicito o que estava rolando era o seguinte, o meu projeto FrontEnd B é uma web application com uma área logada, porém construímos uma landing page em React para mostrar aos usuários não logados, e essa é o FrontEnd A. 

  • FrontEnd A: Landing Page desenvolvida em React.
  • FrontEnd B: Aplicação desenvolvida em Vue.

Criamos um componente chamado SiteComponent no Front B, e utilizamos a tag embed para carregar o conteúdo do site. Basicamente este era o conteúdo html do component:

<template>
<v-layout>
<embed src="https://minha-react-page.com.br/" />
</v-layout>
</template>

Até aqui, tudo de boa. Porém, aqui é onde mora nosso problema. Em nosso projeto Front A, que é o site, temos um botão de LOGIN e quando o usuário clicar nesse botão o Front B deve mudar a rota e ir para o component Login. E nem o embed, iframe ou qualquer elemento do tipo consegue interceptar essa ação, seja manipulado o html ou qualquer outra coisa do tipo, pois as duas aplicações estão hospedadas em origens diferentes. Por isso, precisamos de um jeito de comunicar a ação do site (Front A) para o Front B, para que ele possa executar a ação de mudar de component.

Email image

E a solução que encontramos foi utilizar o postMessage que pertence ao window.

O postMessage foi criado exatamente para resolver esse problema. Ele é um método seguro de comunicação entre window objects. Quando executado, ele envia uma mensagem de determinada aplicação para um destinatário, e o melhor de tudo é que esse destinatário NÃO PRECISA pertencer ao mesmo domínio do remetente.

Então quando o usuário clicar no botão Login do Front A, ao invés de criar uma "ação fake" para interceptar no Front B, nós enviamos um postMessage com destino ao Front B.

O botão Login no site (Front A), executa está ação:

export default function Header() {
const goToLogin = () => {
window.parent.postMessage('goToLogin', 'https://meu-app-vue.com.br/');
}
return (
<>
<Action>
<a href="#" onClick={() => { goToLogin(); }}>
Entrar
</a>
</Action>
</>;
)
}

O que estamos fazendo no postMessage?

Estamos enviando dois parâmetros: a message ('goToLogin') e o targetOrigin ('https://app.exemplo.com.br/'). O targetOrigin deve ter o endereção da aplicação "destinatária". 

Pronto! O Front A já está enviando uma mensagem que pode ser escutada pelo Front B. E para escutar essa mensagem devemos utilizar o window.addEventListener no Front B:

private addLoginEventListener() {
window.addEventListener('message', (event) => {
const { origin, data } = event;
if (
origin === 'https://minha-react-page.com.br'
&& data === 'goToLogin'
) {
this.goToLogin();
}
}, false);
}

Pronto!

Agora o FrontEnd B recebe a mensagem enviada pelo FrontEnd A. Adicionamos as validões para garantir que essa mensagem veio de um lugar seguro e tem o mesmo valor que estamos esperando.

Quando o usuário clica no botão Login do Front A, o Front B recebe esse evento e executa a ação!

Email image

Assim ficou o código completo do meu FrontEnd B:

<template>
<v-layout>
<embed src="https://minha-react-page.com.br" />
</v-layout>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
@Component
export default class Site extends Vue {
private goToLogin() {
this.$router.push({
name: 'login',
});
}
private addLoginEventListener() {
window.addEventListener('message', (event) => {
const { origin, data } = event;
if (
origin === 'https://minha-react-page.com.br'
&& data === 'goToLogin'
) {
this.goToLogin();
}
}, false);
}
private created() {
this.addLoginEventListener();
}
}
</script>

Esse é um problema chato com uma resposta simples. Espero que esse artigo possa te ajudar!

Caso queira saber mais me chame no Instagram ou Linkedin e me segue lá no GitHub.

Até a próxima.