Huymada

Prefetch

Oct 18th, 2024 (edited)
274
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. document.addEventListener('DOMContentLoaded', function () {
  2.  
  3.     var DEBUG = false; // true = exibe logs no console
  4.     var DEPTH = 2;     // profundidade do prefetch (1 = só links da página atual, 2 = links dos links, etc.)
  5.     var DOMAIN = window.location.origin;
  6.  
  7.     var prefetched = new Set([window.location.href]);
  8.  
  9.     // Mapeamento de seletores para o valor correto do atributo 'as'
  10.     // usado no <link rel="prefetch"> — informa ao browser o tipo do recurso
  11.     var RESOURCE_SELECTORS = [
  12.         { selector: 'link[rel="stylesheet"][href]', as: 'style'  },
  13.         { selector: 'script[src]',                  as: 'script' },
  14.         { selector: 'img[src]',                     as: 'image'  },
  15.     ];
  16.  
  17.     // -------------------------------------------------------------------------
  18.     // Injeta um <link rel="prefetch"> no <head> para páginas internas (same-origin)
  19.     // O browser trata com prioridade Idle, não compete com recursos ativos,
  20.     // e respeita corretamente os headers de cache HTTP.
  21.     // -------------------------------------------------------------------------
  22.     function prefetchOne(url) {
  23.         if (prefetched.has(url)) return;
  24.         prefetched.add(url);
  25.  
  26.         var link = document.createElement('link');
  27.         link.rel  = 'prefetch';
  28.         link.href = url;
  29.         link.as   = 'document';
  30.         document.head.appendChild(link);
  31.  
  32.         if (DEBUG) console.log('[prefetch:internal] ' + url);
  33.     }
  34.  
  35.     // -------------------------------------------------------------------------
  36.     // Injeta um <link rel="prefetch"> para recursos externos (CSS, fontes, scripts)
  37.     // Sem o atributo 'as' para recursos cujo tipo o browser não consegue inferir
  38.     // (ex: Google Fonts), ou com 'as' correto quando identificado.
  39.     // -------------------------------------------------------------------------
  40.     function prefetchResource(url, as) {
  41.         if (prefetched.has(url)) return;
  42.         prefetched.add(url);
  43.  
  44.         var link = document.createElement('link');
  45.         link.rel  = 'prefetch';
  46.         link.href = url;
  47.         if (as) link.as = as;
  48.         document.head.appendChild(link);
  49.  
  50.         if (DEBUG) console.log('[prefetch:resource] ' + url);
  51.     }
  52.  
  53.     // -------------------------------------------------------------------------
  54.     // Percorre o DOM de uma página já parseada e faz prefetch de todos os
  55.     // recursos estáticos encontrados (CSS, scripts, imagens, fontes externas)
  56.     // -------------------------------------------------------------------------
  57.     function prefetchResources(doc, baseUrl) {
  58.         RESOURCE_SELECTORS.forEach(function (def) {
  59.             doc.querySelectorAll(def.selector).forEach(function (el) {
  60.                 try {
  61.                     var attr    = el.href || el.src;
  62.                     var resolved = new URL(attr, baseUrl).href;
  63.                     prefetchResource(resolved, def.as);
  64.                 } catch (_) {}
  65.             });
  66.         });
  67.     }
  68.  
  69.     // -------------------------------------------------------------------------
  70.     // Busca o HTML de uma URL, extrai links internos (recursivo até DEPTH)
  71.     // e faz prefetch de todos os recursos estáticos da página.
  72.     // Usa DOMParser para evitar execução de scripts do HTML remoto.
  73.     // -------------------------------------------------------------------------
  74.     function prefetchDeep(url, depth) {
  75.         if (depth === 0 || prefetched.has(url)) return;
  76.  
  77.         prefetchOne(url);
  78.  
  79.         if (depth <= 1) return;
  80.  
  81.         fetch(url)
  82.             .then(function (response) {
  83.                 if (!response.ok) throw new Error('Status ' + response.status);
  84.                 return response.text();
  85.             })
  86.             .then(function (html) {
  87.                 var parser = new DOMParser();
  88.                 var doc    = parser.parseFromString(html, 'text/html');
  89.  
  90.                 // Recursos estáticos da página (CSS, fontes, scripts, imagens)
  91.                 prefetchResources(doc, url);
  92.  
  93.                 // Links internos — continua a recursão
  94.                 doc.querySelectorAll('a[href]').forEach(function (a) {
  95.                     try {
  96.                         var resolved = new URL(a.getAttribute('href'), url).href;
  97.                         if (resolved.startsWith(DOMAIN)) {
  98.                             prefetchDeep(resolved, depth - 1);
  99.                         }
  100.                     } catch (_) {
  101.                         // href inválido (javascript:, mailto: etc.) — ignora
  102.                     }
  103.                 });
  104.             })
  105.             .catch(function (error) {
  106.                 if (DEBUG) console.warn('[prefetch] falha em ' + url, error);
  107.             });
  108.     }
  109.  
  110.     // -------------------------------------------------------------------------
  111.     // Ponto de entrada: percorre todos os links da página atual
  112.     // -------------------------------------------------------------------------
  113.     document.querySelectorAll('a[href]').forEach(function (a) {
  114.         try {
  115.             var resolved = new URL(a.getAttribute('href'), DOMAIN).href;
  116.             if (resolved.startsWith(DOMAIN)) {
  117.                 prefetchDeep(resolved, DEPTH);
  118.             }
  119.         } catch (_) {
  120.             // ignora hrefs inválidos
  121.         }
  122.     });
  123.  
  124. });
Advertisement
Add Comment
Please, Sign In to add comment