Comment gérer les pages obsolètes d'une PWA ?

Discussion dans 'Développement d'un site Web ou d'une appli mobile' créé par ortolojf, 13 Janvier 2021.

  1. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Bonjour

    C'est pour une PWA.

    Je me met à l'étude de chargements de préférence up to date, avec l'api fetch.

    Comment savoir si une page a été modifiée sur le serveur ?

    C'est-à-dire, si cache valide, à partir du cache, sinon fetch + put dans le cache.

    J'ai imaginé l'enreg d'un hash code sha256 des pages.

    Mais le fichier contenant le hash code devrait être écrit sur le serveur à chaque modif. d'une page.

    La lecture de ce hash code ( fetch + response ), serait plus rapide que celle du fichier.

    Et, le hash code du cache serait lu à partir du contenu cache.

    Ensuite, comparaison, et si différent, fetch + put.

    Celà vous semble-t-il viable ?

    Merci beaucoup.
     
  2. nicodak
    nicodak WRInaute discret
    Inscrit:
    21 Octobre 2020
    Messages:
    77
    J'aime reçus:
    25
  3. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Rebonjour

    Je suis en train de coder.

    Qu'est-ce qui se passe :

    quand dans un self.addEventListener('fetch', function(evt) :

    on appelle plusieurs fetch, en modes et GET et PUT ?

    Plus général : Comment se fait-il qu'il soit possible d'appeler un fetch à l'intérieur du Listener fetch , sans que celà ne déclenche un autre event fetch ?

    Merci beaucoup de vos réponses.

    Je suis un newbie en Javascript.

    Amicalement.
     
  4. rick38
    rick38 WRInaute passionné
    Inscrit:
    23 Février 2013
    Messages:
    1 777
    J'aime reçus:
    269
    Dans l'esprit d'une PWA, je ne dirais pas qu'il faut voir si la "page" a été modifiée ou pas, parce qu'on n'est pas sensé charger une page, mais des données (le contenu dynamique, en JSON par exemple), et ensuite la page est remplie en JS.

    En dehors du 1er chargement du template (une page HTML vide, en gros, les fichiers JS/CSS...), le reste ce sont des flux JSON, on interroge le serveur pour savoir si tel truc ou tel truc est à jour (par exemple une liste de produits : on compare si le dernier stocké en base locale correspond au dernier du serveur, ou bien s'il y en a des nouveaux à charger).

    Ton histoire de hashcode peut fonctionner bien sûr, mais alors on se retape le chargement de la page au complet au lieu de ne charger que les données qui ont changé, ça n'est pas optimal.
     
  5. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Bonjour rick38

    Effectivement, le hash-code ne devrait mesurer que les data ( json ou text ).

    J'ai du mal à faire des fetch PUT pour uploader les hash-codes sur le serveur.

    A chaque fichier "fichier.json", son hash-code "hashcode_fichier.json".

    Dans mon esprit, à chaque lecture de fichier , les hash-codes sont systématiquement lus avec fetch, et comparés à celui du fichier en cache.

    Si les deux sont identiques, return response du cache, sinon fetch fichier et put du hash-code.

    Mais je n'arrive pas à faire des PUT avec des fetch.

    Voici le code :

    Code:
    
    // Make an HTTP PUT Request
    async function put(url, someData) {
            console.log('Handling PUT fetch for : ' + url + ' , hash_code : '. someData);
            // Awaiting fetch which contains method,
            // headers and content-type and body
            await fetch(url, {
                    method: 'PUT',
                    headers: {
                            'Content-type': 'application/json; charset=UTF-8' // Indicates the content
                    },
                    body: JSON.stringify(someData) // We send data in JSON format
            }).then(function(reponse) {
                    return reponse.json();
            }, function(error) {
                    console.log('Error while putting file : ' + url + '  , with hash code : ' + someData + '  , with error : ' + error);
                    return false;
            })
    }
    
    

    Merci beaucoup de ton aide.
     
  6. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Rebonjour rick38

    Voilà une fonction à utiliser pour translater du html en json :

    Code:
    
    // Test with an element.
    var initElement = document.getElementsByTagName("html")[0];
    var json = mapDOM(initElement, true);
    console.log(json);
    
    // Test with a string.
    initElement = "<div><span>text</span>Text2</div>";
    json = mapDOM(initElement, true);
    console.log(json);
    
    function mapDOM(element, json) {
        var treeObject = {};
                // If string convert to document Node
        if (typeof element === "string") {
            if (window.DOMParser) {
                  parser = new DOMParser();
                  docNode = parser.parseFromString(element,"text/xml");
            } else { // Microsoft strikes again
                  docNode = new ActiveXObject("Microsoft.XMLDOM");
                  docNode.async = false;
                  docNode.loadXML(element); 
            }
            element = docNode.firstChild;
        }
                //Recursively loop through DOM elements and assign properties to object
        function treeHTML(element, object) {
            object["type"] = element.nodeName;
            var nodeList = element.childNodes;
            if (nodeList != null) {
                if (nodeList.length) {
                    object["content"] = [];
                    for (var i = 0; i < nodeList.length; i++) {
                        if (nodeList[i].nodeType == 3) {
                            object["content"].push(nodeList[i].nodeValue);
                        } else {
                            object["content"].push({});
                            treeHTML(nodeList[i], object["content"][object["content"].length -1]);
                        }
                    }
                }
            }
            if (element.attributes != null) {
                if (element.attributes.length) {
                    object["attributes"] = {};
                    for (var i = 0; i < element.attributes.length; i++) {
                        object["attributes"][element.attributes[i].nodeName] = element.attributes[i].nodeValue;
                    }
                }
            }
        }
        treeHTML(element, treeObject);
                return (json) ? JSON.stringify(treeObject) : treeObject;
    }
    
    
     
  7. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Ah

    Voilà une fonction sympathique :

    Code:
    
    // Small library to improve on fetch() usage
    const api = function(method, url, data, headers = {}){
      return fetch(url, {
        method: method.toUpperCase(),
        body: JSON.stringify(data),  // send it as stringified json
        credentials: api.credentials,  // to keep the session on the request
        headers: Object.assign({}, api.headers, headers)  // extend the headers
      }).then(res => res.ok ? res.json() : Promise.reject(res));
    };
    // Defaults that can be globally overwritten
    api.credentials = 'include';
    api.headers = {
      'csrf-token': window.csrf || '',    // only if globally set, otherwise ignored
      'Accept': 'application/json',       // receive json
      'Content-Type': 'application/json'  // send json
    };
    // Convenient methods
    ['get', 'post', 'put', 'delete'].forEach(method => {
      api[method] = api.bind(null, method);
    });
    
    

    Pour appeler en mode put je fais :

    api['put'](url, data) ?

    ou bien :

    api.put(url, data ) ?

    Je m'emberlificote dans les objets en javascript.

    Merci beaucoup.
     
  8. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Bonjour rick38

    Tout fonctionne peu près, si ce n'est l'envoi par PUT des hashcodes.

    La fonction échoue lors des put.

    Voilà le code de la fonction :

    Merci beaucoup.


    Code:
    
    // Small library to improve on fetch() usage
    const api_put = function(method, url, data, headers = {}){
            return fetch(url, {
                    method: method.toUpperCase(),
                    body: data,                                                // send it as stringified json
                    credentials: api_put.credentials,                        // to keep the session on the request
                    headers: Object.assign({}, api_put.headers, headers)    // extend the headers
            }).then(res => res.ok ? res.text() : Promise.reject(res));
    };
    // Defaults that can be globally overwritten
    api_put.credentials = 'include';
    api_put.headers = {
            //        'csrf-token': window.csrf || '',     // only if globally set, otherwise ignored
            'Accept': 'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8',    // receive text/html
            'Content-Type': 'text/html; charset=utf-8'    // send text/html
    };
    // Convenient methods
    ['post', 'put', 'delete'].forEach(method => {
            api_put[method] = api_put.bind(null, method);
    });
    
    
     
  9. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Cà marche.

    Pour que le serveur web ( Nginx ) accepte les PUT, il suffit de mettre celà dans la config. :

    Code:
    
        location /pwa {
                root     /var/www/html;
                dav_methods  PUT;
    
    #          dav_methods PUT DELETE MKCOL COPY MOVE;
    
                dav_access user:rw group:rw all:r;
        }
    
    
    Cà marche, mais je dois peaufiner la loqique de ma fonction FETCH qui est censée prendre en charge les FetchEvent.

    Merci beaucoup.
     
  10. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Voilà la fonction FETCH(tmp_file) :

    Code:
    
    function hashCode(str) {
            var hash = 0;
            if(typeof str == 'undefined') {
                    return hash;
            }
            var len = str.length;
            var tmp_char = null;
            for (var i = 0; i < len; i++) {
                    tmp_char = str.charCodeAt(i);
                    hash = ((hash<<5)-hash)+tmp_char;
                    hash = hash & hash; // Convert to 32bit integer
            }
            return hash;
    }
    
    // Small library to improve on fetch() usage
    const api_fetch = function(method, url, data, headers = {}){
            return fetch(url, {
                    method: method.toUpperCase(),
                    body: data,                                                // send it as stringified json
                    credentials: api_fetch.credentials,                        // to keep the session on the request
                    headers: Object.assign({}, api_fetch.headers, headers)    // extend the headers
            }).then(res => res.ok ? res : Promise.reject(res));
    };
    // Defaults that can be globally overwritten
    api_fetch.credentials = 'include';
    api_fetch.headers = {
            'cache': 'no-store',
            'Accept': 'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8',    // receive text/html
            'Content-Type': 'text/html; charset=utf-8'    // send text/html
    };
    // method Fetch
    api_fetch['fetch'] = api_fetch.bind(null, 'fetch');
    
    // Small library to improve on fetch() usage
    const api_put = function(method, url, data, headers = {}){
            return fetch(url, {
                    method: method.toUpperCase(),
                    body: data,                                                // send it as stringified json
                    credentials: api_put.credentials,                        // to keep the session on the request
                    headers: Object.assign({}, api_put.headers, headers)    // extend the headers
            }).then(res => res.ok ? res.text() : Promise.reject(res));
    };
    // Defaults that can be globally overwritten
    api_put.credentials = 'include';
    api_put.headers = {
            'Accept': 'text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8',    // receive text/html
            'Content-Type': 'text/html; charset=utf-8'    // send text/html
    };
    // Convenient methods
    ['post', 'put', 'delete'].forEach(method => {
            api_put[method] = api_put.bind(null, method);
    });
    
    const CACHE = 'pwa-conf-v1';
    var staticAssets = [
            './',
            './index.html',
            './app.js',
            './styles.css'
    ];
    
    function from_filename(str, sep) {
            return new Array(str.substring(0, str.lastIndexOf(sep)), str.substring(str.lastIndexOf(sep) + 1));
    }
    
    function FETCH(tmp_file) {
            var chemin                = null;
            var avant_file_ndd        = null;
            var file_ndd            = null;
            var file                 = tmp_file;
            var hash_code_file        = null;
            var HashCodeResponse    = null;
            var Response            = null;
            var text                = null;
            var hash_code_cache        = null;
            var hash_code            = null;
            console.log('Handling FETCH function for : ' + file);
            str = from_filename(file, '/');
            chemin = str[0];
            avant_file_ndd = from_filename(from_filename(file, '/')[1], '.')[0];
            file_ndd = from_filename(file, '.')[1];
            hash_code_file = chemin + '/hash_code_' + avant_file_ndd + '.txt';
            file = new URL(file, location.href);
            hash_code_file = new URL(hash_code_file, location.href);
            console.log('request for : ' + file + ' and : ' + hash_code_file);
            return caches.open(CACHE).then(function (cache) {
                    /*****************************/
                    /**    LE FICHIER DE HASH CODE    **/
                    /** CONTIENT LE HASH CODE    **/
                    /**    DU FICHIER CHARGE.        **/
                    /*****************************/
                    /***********************/
                    /**    VALEUR IMPOSSIBLE **/
                    /***********************/
                    HashCodeResponse = -10;
                    api_fetch['get'](hash_code_file).then(function(response) {
                            if(!response) {
                                    return false;
                            }
                            return  response.text();
                    }, function(error) {
                            console.log('Error while fetching1 hash_code_file : ' + hash_code_file + '  , with error : ' + error.message);
                    }).then(function(text) {
                            HashCodeResponse = text;
                            console.log('Succeded while fetching hash_code_file : ' + hash_code_file + ' with text : ' + text);
                    }, function(error) {
                            console.log('Error while fetching2 hash_code_file : ' + hash_code_file + '  , with error : ' + error.message);
                    })
                    console.log('HashCodeResponse = ' + HashCodeResponse);
                    /*****************************************************/
                    /**    ON CHARGE LE HASH CODE DU FICHIER EN CACHE        **/
                    /*****************************************************/
                    /**        CE HASH CODE DOIT AVOIR ETE UPDATE LORS        **/
                    /**            DU DERNIER CHARGEMENT DU FICHIER.        **/
                    /*****************************************************/
                    cache.match(file).then(function(response) {
                            if(!response) {
                                    return false;
                            }
                            Response = response.clone();
                            return response.text();
                    }).then(function(text) {
                            hash_code_cache = hashCode(text);
                            console.log('Succeded while reading file from the cache : ' + file + ' with text : ' + text);
                            if(HashCodeResponse == hash_code_cache) {
                                    /**********************/
                                    /**    REPONSE DU CACHE **/
                                    /**********************/
                                    return Response;
                            }
                    }, function(error) {
                            console.log('Error while reading file from cache : ' + file + '  , with error : ' + error.message);
                    })
                    /*****************************/
                    /**       HASH CODE INVALIDE    **/
                    /**       ON LIT LE FICHIER    **/
                    /**        ET ON UPDATE        **/
                    /**        LE HASH CODE        **/
                    /*****************************/
                    api_fetch['get'](file).then(function(response) {
                            if(!response) {
                                    return false;
                            }
                            Response = response.clone();
                            return response.text();
                    }).then(function(text) {
                            console.log('Succeded while fetching file : ' + file + ' with response : ' + text);
                            hash_code = hashCode(text);
                            console.log('hash code = ' + hash_code);
                            /*************************/
                            /**      ON MET EN CACHE    **/
                            /**        LE FICHIER        **/
                            /*************************/
                            cache.put(file, Response);
                            /*************************/
                            /**        ON UPDATE        **/
                            /**        LE HASH CODE    **/
                            /*************************/
                            api_put['put'](hash_code_file, hash_code).then(function(text) {
                                    console.log('Succeded while putting file : ' + hash_code_file + ' with hash code : ' + hash_code + ' with response : ' + text);
                            }, function(error) {
                                    console.log('Error while putting file : ' + hash_code_file + ' with hash code : ' + hash_code + '  , with error : ' + error.message);
                            })
                            /************************/
                            /**    REPONSE DU FICHIER **/
                            /************************/
                            return Response;
                    }, function(error) {
                            console.log('Error while fetching file : ' + file + '  , with error : ' + error.message);
                            return false;
                    })
            }, function(error) {
                    console.log('Error while opening cache : ' + CACHE + '  , with error : ' + error.message);
                    return false;
            })
    }
    
    
     
  11. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Bonjour

    J'ai une question :

    J'ai une fonction FETCH(tmp_file) qui rend une Promise de type Response.

    Cette fonction utilise des fetch().

    Est-il possible, de déclarer le FetchEvent de cette manière :

    Code:
    
    self.addEventListener('fetch', function(event) {
            return FETCH(event.request.url);
    });
    
    
    sachant que fetch et FETCH retournent une Promise ?

    A part çà, les FetchEvent sont déclenchés par l'interface utilisateur ?

    C'est-à-dire : Les clics sur les href ?

    Merci beaucoup.
     
  12. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    Pardon

    Problème résolu.

    Le FETCH rend une Promise, il faut la résoudre.

    Code:
    
    self.addEventListener('fetch', function(event) {
           return FETCH(event.request.url).then(function(response) {
                return response;
          }, { function(error ){
               // traitement d'erreur.
         })
    });
    
    
    Là, çà marche, mais j'ai encore des erreurs, je vais charger moins de fichiers, vérifier FETCH() et investiguer.

    Et puis FETCH(event) au lieu de FETCH(event.request.url), correct ?

    Merci beaucoup.
     
  13. ortolojf
    ortolojf WRInaute accro
    Inscrit:
    14 Août 2002
    Messages:
    3 457
    J'aime reçus:
    27
    J'ai une question :

    Dans le service worker, je déclare les FetchEvent avec une fonction FETCH(file) qui rend la promise de type response, ou false.

    Il y a également, la fonction LECT(file), utilisant FETCH(file), et qui rend directement le contenu de file, lu soit dans le cache, soit le fichier file.

    Ces deux fonctions, doivent retourner toujours une version à jour de file.

    Voici le code :

    Code:
    
    self.addEventListener('fetch', function(evt) {
            // In a real app, you'd use a more sophisticated URL check.
            //        if (event.request.url.match(/.*/)) {
            //        event.respondWith(FETCH(event.request.url));
            var file = evt.request.url;
            evt.waitUntil(
                    FETCH(file).then(function(response) {
                            if(response === false) {
                                    console.log('Failed while FETCHING file, with response : ' + response);
                            }
                            return response;
                    }, function(error) {
                            console.log('Error while FETCHING file, with error : ' + error.message);
                            return false;
                    })
            );
            return false;
    });
    
    function LECT(file) {
            FETCH(file).then(function(response) {
                    if(response === false) {
                            console.log('Failed while reading file, with response : ' + response);
                    }
                    response.text().then(function(text) {
                            if(text) {
                                    console.log('Ok while reading file, with response : ' + text);
                                    return text;
                            } else {
                                    console.log('Bad while reading file, with response : ' + text);
                                    return false;
                            }
                    }, function(error) {
                            console.log('Error while  file, with error : ' + error.message);
                            return false;
                    })
            }, function(error) {
                    console.log('Error while  file, with error : ' + error.message);
                    return false;
            })
    }
    
    
    Ma question : Dois-je utiliser waitUntil ?

    Mon code est-il correct ?

    Je débute avec L'API fetch.

    Merci beaucoup.
     
Chargement...
Similar Threads - gérer obsolètes PWA Forum Date
Comment gérer une page zombie fiche produit ecommerce Techniques avancées de référencement 10 Août 2021
Aide utilisation twitter : gérer les commentaires Twitter 3 Mars 2021
HTML fait par Javascript <=>gérer les Events ? Développement d'un site Web ou d'une appli mobile 5 Juillet 2020
Site EN sur le .com et FR sur le .FR, comment gérer Référencement international (langues, pays) 25 Mars 2020
Comment gérer le duplicate content sur les pages magasins Demandes d'avis et de conseils sur vos sites 19 Mars 2020
Page évènement (salon) reporté : comment gérer l'URL ? Débuter en référencement 4 Mars 2020
Comment gérer le ALT d'une image en CSS background-image YouTube, Google Images et Google Maps 17 Décembre 2019
Indexation, pagination : comment gérer les URL de tri des colonnes ? Crawl et indexation Google, sitemaps 24 Septembre 2019
Gérer le duplicate content sur des sites différents Débuter en référencement 28 Mars 2019
WordPress Gros changement de pagination, comment gérer au mieux Crawl et indexation Google, sitemaps 13 Mars 2019