Acessando o "compartilhar" nativo, vulgo Web-Share, em VanillaJS e Vue
Tags: webdev, javascript, vue, braziliandevs
Published: 2022-08-11 19:09:09

Nessa semana estive trabalhando em uma demanda simples de um cliente Freela.

O projeto consiste em um daqueles formulários interativos que você responde X perguntas e tem um resultado no final, vulgo, um Quiz.

A ideia é que o resultado fosse compartilhado no Insta com a hashtag de uma campanha para que o usuário pudesse participar de uma promoção.

Meu desafio em si foi descobrir como fazer um botão "compartilhar" desses. O Facebook tem um "widget" que é só copiar, colar e pronto. Não encontrei nada similar para o Insta...

Foi então que me veio na cabeça a ideia de tentar utilizar a UI nativa do smartphone do usuário. Afinal, cada usuário já está acostumado a utilizar essa interface em inúmeras operações de compartilhar que são feitas todos os dias.

📖 Parti para a pesquisa e encontrei a tal da API do Web Share.

Segundo a [documentação do MDN](https://developer.mozilla.org/pt-BR/docs/Web/API/Navigator/share), até o presente momento, o suporte ainda é parcial, mas nos pareceu uma solução bastante viável dado o nosso público-alvo.

Existem ainda algumas restrições adicionais como:

- O site precisa ser acessado via HTTPS
- O recurso precisa ser invocado por uma ação direta do usuário

HTTPs é super fácil com o [Let's Encrypt](https://letsencrypt.org/) 🙌 e, de fato, queríamos que o usuário clicasse em "compartilhar" para poder enviar nossa imagem, então, até aqui, tudo certo!

Antes de seguir, criei uma funçãozinha para não ter que ficar copiando e colando toda hora (Let's keep it DRY 😜):

{% codepen https://codepen.io/jonyhayama/pen/NWYKmjL default-tab=js %}

Com a função no jeito, vamos começar a brincadeira compartilhando um **link** só para esquentar os motores:

{% codepen https://codepen.io/jonyhayama/pen/NWYKmbB default-tab=js,result %}

Naturalmente que, no Insta, faz mais sentido compartilhar uma imagem. Portanto precisamos passar a utilizar a propriedade `files` que espera um `array` de `File`.

O primeiro exemplo que encontrei para gerar esse `array`, foi o de simplesmente ler o resultado de um determinado input:

{% codepen https://codepen.io/jonyhayama/pen/KKoPYqE default-tab=js,result %}

> ⚠️ **OBS:** Inicialmente tentei ativar o WebShare no evento `change` do `input`, mas nem sempre isso foi considerado um "user gesture", por isso precisei adicionar o botão. Se tiver interesse em validações bem detalhadas e outros possíveis cenários, da uma conferida [nesse exemplo](https://w3c.github.io/web-share/demos/share-files.html) da W3C.

Funciona até que legal, mas a minha imagem estava em um servidor e não no dispositivo do usuário...

De certa forma, eu precisava converter uma URL em um `File`, o que (para a minha surpresa) pode ser feito facilmente utilizando o `fetch`:

{% codepen https://codepen.io/jonyhayama/pen/xxWxXPP default-tab=js,result %}

Depois que consegui organizar minha lógica foi hora de levar isso para o Vue, que é o framework utilizado no projeto.

Para isso, optei por utilizar uma biblioteca chamada [VueUse](https://vueuse.org/core/useShare/) que, dentre outras coisas, leva a reatividade para o `shareObj` de uma forma bem interessante.

{% stackblitz https://stackblitz.com/edit/vitejs-vite-twz2xk?file=src%2Fcomponents%2FWebShare.vue %}

Daí para frente foi só `git commit`, `git push` e `npm run build` 🥳