Huymada icon

Prefetch

Huymada | PRO | 03/13/26 03:31:59 PM UTC (Edited) | 0 ⭐ | 214 👁️ | Never ⏰ | []
JavaScript |

5.24 KB

|

None

|

0 👍

/

0 👎

document.addEventListener('DOMContentLoaded', function () {
 
    var DEBUG = false; // true = exibe logs no console
    var DEPTH = 2;     // profundidade do prefetch (1 = só links da página atual, 2 = links dos links, etc.)
    var DOMAIN = window.location.origin;
 
    var prefetched = new Set([window.location.href]);
 
    // Mapeamento de seletores para o valor correto do atributo 'as'
    // usado no <link rel="prefetch"> — informa ao browser o tipo do recurso
    var RESOURCE_SELECTORS = [
        { selector: 'link[rel="stylesheet"][href]', as: 'style'  },
        { selector: 'script[src]',                  as: 'script' },
        { selector: 'img[src]',                     as: 'image'  },
    ];
 
    // -------------------------------------------------------------------------
    // Injeta um <link rel="prefetch"> no <head> para páginas internas (same-origin)
    // O browser trata com prioridade Idle, não compete com recursos ativos,
    // e respeita corretamente os headers de cache HTTP.
    // -------------------------------------------------------------------------
    function prefetchOne(url) {
        if (prefetched.has(url)) return;
        prefetched.add(url);
 
        var link = document.createElement('link');
        link.rel  = 'prefetch';
        link.href = url;
        link.as   = 'document';
        document.head.appendChild(link);
 
        if (DEBUG) console.log('[prefetch:internal] ' + url);
    }
 
    // -------------------------------------------------------------------------
    // Injeta um <link rel="prefetch"> para recursos externos (CSS, fontes, scripts)
    // Sem o atributo 'as' para recursos cujo tipo o browser não consegue inferir
    // (ex: Google Fonts), ou com 'as' correto quando identificado.
    // -------------------------------------------------------------------------
    function prefetchResource(url, as) {
        if (prefetched.has(url)) return;
        prefetched.add(url);
 
        var link = document.createElement('link');
        link.rel  = 'prefetch';
        link.href = url;
        if (as) link.as = as;
        document.head.appendChild(link);
 
        if (DEBUG) console.log('[prefetch:resource] ' + url);
    }
 
    // -------------------------------------------------------------------------
    // Percorre o DOM de uma página já parseada e faz prefetch de todos os
    // recursos estáticos encontrados (CSS, scripts, imagens, fontes externas)
    // -------------------------------------------------------------------------
    function prefetchResources(doc, baseUrl) {
        RESOURCE_SELECTORS.forEach(function (def) {
            doc.querySelectorAll(def.selector).forEach(function (el) {
                try {
                    var attr    = el.href || el.src;
                    var resolved = new URL(attr, baseUrl).href;
                    prefetchResource(resolved, def.as);
                } catch (_) {}
            });
        });
    }
 
    // -------------------------------------------------------------------------
    // Busca o HTML de uma URL, extrai links internos (recursivo até DEPTH)
    // e faz prefetch de todos os recursos estáticos da página.
    // Usa DOMParser para evitar execução de scripts do HTML remoto.
    // -------------------------------------------------------------------------
    function prefetchDeep(url, depth) {
        if (depth === 0 || prefetched.has(url)) return;
 
        prefetchOne(url);
 
        if (depth <= 1) return;
 
        fetch(url)
            .then(function (response) {
                if (!response.ok) throw new Error('Status ' + response.status);
                return response.text();
            })
            .then(function (html) {
                var parser = new DOMParser();
                var doc    = parser.parseFromString(html, 'text/html');
 
                // Recursos estáticos da página (CSS, fontes, scripts, imagens)
                prefetchResources(doc, url);
 
                // Links internos — continua a recursão
                doc.querySelectorAll('a[href]').forEach(function (a) {
                    try {
                        var resolved = new URL(a.getAttribute('href'), url).href;
                        if (resolved.startsWith(DOMAIN)) {
                            prefetchDeep(resolved, depth - 1);
                        }
                    } catch (_) {
                        // href inválido (javascript:, mailto: etc.) — ignora
                    }
                });
            })
            .catch(function (error) {
                if (DEBUG) console.warn('[prefetch] falha em ' + url, error);
            });
    }
 
    // -------------------------------------------------------------------------
    // Ponto de entrada: percorre todos os links da página atual
    // -------------------------------------------------------------------------
    document.querySelectorAll('a[href]').forEach(function (a) {
        try {
            var resolved = new URL(a.getAttribute('href'), DOMAIN).href;
            if (resolved.startsWith(DOMAIN)) {
                prefetchDeep(resolved, DEPTH);
            }
        } catch (_) {
            // ignora hrefs inválidos
        }
    });
 
});

Comments