Aguarde...

15 de abril de 2019

Inline SVG… em cache

Inline SVG… em cache

Começando com SVG embutido

Como isso…

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Inline SVG</title>
  <link rel="stylesheet" href="/styles/style.css">
</head>

<body>

  ...
 
  <svg width="24" height="24" viewBox="0 0 24 24" class="icon icon-alarm" xmlns="http://www.w3.org/2000/svg">
    <path id="icon-alarm" d="M11.5,22C11.64,22 11.77,22 11.9,21.96C12.55,21.82 13.09,21.38 13.34,20.78C13.44,20.54 13.5,20.27 13.5,20H9.5A2,2 0 0,0 11.5,22M18,10.5C18,7.43 15.86,4.86 13,4.18V3.5A1.5,1.5 0 0,0 11.5,2A1.5,1.5 0 0,0 10,3.5V4.18C7.13,4.86 5,7.43 5,10.5V16L3,18V19H20V18L18,16M19.97,10H21.97C21.82,6.79 20.24,3.97 17.85,2.15L16.42,3.58C18.46,5 19.82,7.35 19.97,10M6.58,3.58L5.15,2.15C2.76,3.97 1.18,6.79 1,10H3C3.18,7.35 4.54,5 6.58,3.58Z"></path>
  </svg>

É muito fácil jogar texto no cache do navegador como um arquivo

No HTML acima, o seletor .icon-alarmnos buscará a parte inteira <svg>desse ícone.

const iconHTML = document.querySelector(".icon-alarm").outerHTML;

Então, podemos inserir no cache do navegador assim:

if ("caches" in window) {
  caches.open('static').then(function(cache) {
    cache.put("/icons/icon-wheelchair.svg", new Response(
      iconHTML,
      { headers: {'Content-Type': 'image/svg+xml'} }
    ));
  }
}

Veja o caminho do arquivo /icons/icon-wheelchair.svg? Isso é meio que apenas inventado. Mas realmente será colocado no cache naquele local.#Vamos nos certificar de que o navegador extraia esse arquivo do cache quando solicitado

Vamos registrar um Service Worker em nossas páginas:

if (navigator.serviceWorker) {   
  navigator.serviceWorker.register('/sw.js', {
    scope: '/'
  });
}

O próprio service worker será bem pequeno, apenas um correspondente de cache:

self.addEventListener("fetch", event => {
  let request = event.request;

  event.respondWith(
    caches.match(request).then(response => {
      return response || fetch(request);
    })
  );
});

#Mas … nós nunca pedimos esse arquivo, porque nossos ícones são inline.

Verdade. Mas e se outras páginas se beneficiassem desse cache? Por exemplo, um ícone SVG poderia ser colocado na página assim:

<svg class="icon">
  <use xlink:href="/icons/icon-alarm.svg#icon-alarm" /> 
</svg>

Uma vez que /icons/icon-alarm.svgestá pronto para ser colocado em cache, o navegador ficará feliz em removê-lo do cache e exibi-lo.

(Fiquei espantado com o fato de isso funcionar. O Edge não gosta de <use>elementos que se ligam a arquivos, mas isso acabará em breve.)

E mesmo que o arquivo não esteja no cache, presumindo que nós realmente jogamos esse arquivo no sistema de arquivos, provavelmente o resultado de algum tipo de “include” (usei o Nunjucks na demo).

Mas … <use>e SVG embutido não são exatamente os mesmos

Verdade. O que eu gosto sobre o acima é que ele está fazendo uso do cache e os ícones devem renderizar perto de imediatamente. E há algumas coisas que você pode estilizar dessa maneira – por exemplo, definir o preenchimento no ícone pai deve passar pelo DOM de sombra que <use>cria e colorir os elementos SVG dentro dele.

Ainda assim, não é o mesmo. A sombra DOM é uma grande barreira em comparação com o SVG embutido.

Então, aprimore-os! Poderíamos carregar de forma assíncrona um script que encontre cada ícone SVG, Ajaxs para o SVG necessário e substitua o <use>material …

const icons = document.querySelectorAll("svg.icon");

icons.forEach(icon => {
  const url = icon.querySelector("use").getAttribute("xlink:href"); // Might wanna look for href also
  fetch(url)
    .then(response => response.text())
    .then(data => {
      // This is probably a bit layout-thrashy. Someone smarter than me could probably fix that up.

      // Replace the <svg><use></svg> with inline SVG
      const newEl = document.createElement("span");
      newEl.innerHTML = data;
      icon.parentNode.replaceChild(newEl, icon);

      // Remove the <span>s
      const parent = newEl.parentNode;
      while (newEl.firstChild) parent.insertBefore(newEl.firstChild, newEl);
      parent.removeChild(newEl);
    });
});

Agora, supondo que esse JavaScript seja executado corretamente, essa página tem o SVG embutido disponível da mesma forma que a página original.

Postado em BlogTags:
Escreva um comentário