Problématique du jour : Intercepter l’appel à des liens via Javascript.
Mon cas d’usage : J’ai des contenus (images, vidéos, audio, polices de caractères) stockés côté client (indexedDB, webSQL ou DOMStorage) que je souhaite insérer dans mes pages.
(billet mis à jour au fur et à mesure des réponses)
Quelques solutions :
Data:URI
Je récupère ma donnée, je la transforme en base64, et je remplace le lien standard par un lien en data:uri.
Deux défauts : Je stocke N fois la donnée dans le DOM où N est le nombre d’apparition de l’image ou de la ressource dans mes pages HTML/CSS. Pour ne rien gâcher, on stocke en base64 donc avec 30% de poids en plus. De plus, même si je n’ai pas de test à montrer, on s’est déjà pris les pieds dans le tapis à cause de très mauvaises performances de pages avec beaucoup de data:uri, spécialement sur Firefox (probablement sur les polices de caractères)
Blob + createObjectURL
Je récupère ma donnée, je créé un Blob à partir de cette donnée, je passe par URL.createObjectURL pour créer une URL dédiée et j’utilise cette dernière quand je référence ma ressource.
On résout les problèmes du data:uri mais on se coupe de IE 9, IE mobile et iOS 5. Pas gravissime mais j’aurai préféré éviter.
Par contre la solution ne fonctionnera de toutes façons pas pour les images ou polices de caractères référencées depuis les CSS (sauf à construire les CSS via Javascript mais là on entre dans des usines à gaz).
Cas spécifique des vidéo et audio
Les deux solutions me posent de toutes façons un sérieux problème pour les vidéo et les audio, qui peuvent être de gros volume. Je me vois mal sortir d’indexedDB des dizaines de mégaoctets (au mieux) pour construire un blob juste et avoir une URL dans ma balise HTML sans même savoir si l’utilisateur tentera effectivement de lire la vidéo ou le fichier audio.
Pour les vidéos et les audio (mais uniquement ces deux types de contenu) je peux réfléchir à mettre un lien vers une vidéo de taille quasi nulle et le changer dès que la vidéo est activée. J’ai toutefois un peu peur des effets de bords. Il va falloir aussi bosser en amont pour que la première image s’affiche bien dans le lecteur vidéo malgré l’absence de la vidéo complète.
Bidouille
Pour l’instant ma solution serait :
- Pour les images et polices de caractères dans les CSS : data:uri. En espérant que la CSS ne contient pas trop de ressources inutiles ou trop de liens vers la même ressource.
- Au pire : Générer la CSS en Javascript avec des liens obtenus par createObjectUrl, l’insérer dans le DOM manuellement
- Pour les images dans le code HTML : createObjectURL si possible.
- Vérifier tout de même si le data:uri n’est pas plus simple. La différence entre les deux sera assez faible si les images ne sont pas répétées plusieurs fois.
- Pour les audio et vidéo : Désactiver le preload, renseigner le lien via createObjectURL qu’au lancement de la vidéo. Pour les vidéo, penser à créer une image d’attente avec l’attribut poster.
Ça reste franchement du bricolage je trouve, et ça va nécessiter plein de javascript pour générer tout ça.
Dans mon monde idéal
Dans l’idéal j’aurai bien aimé avoir une sorte de faux serveur web en javascript depuis le navigateur. Genre toute url en « local-js://xxxxx » fait appel à un objet Javascript qui répond ensuite ce qu’il veut.
À défaut, un URL.createObjectURL( 'text/html', function() { return bindata; } )
serait bien pratique : Le navigateur n’appelant la fonction pour récupérer le contenu que quand il cherche à accéder au dit contenu, au lieu de lui donner tout le contenu par avance au cas où il en aurait besoin.
Quelqu’un a des pistes pour moi ?
Laisser un commentaire