Forcer le chargement de vos scripts après chaque changement avec Django

With keywords: Modification Production Recharchement Scripts Server

De plus en plus, le développement de site web se repose sur javascript et de moins en moins sur le serveur. Le serveur devenant un fournisseur de données plus ou moins formaté (notamment en utilisant JSON).  C'est le cas pour la version mobile de ce site.

Le chargement des scripts devient de plus en plus critique. Mais pour les scripts, vous avez un ennemi le cache. Que ce soit le cache serveur ou le cache du navigateur.

Bien sûr, vous avez fait comme moi et respecter à la lettre les recommendations Google ou Yahoo! en regroupant tous vos scripts en un seul (perso, j'ai deux fichiers, un qui s'appelle libs.js qui contient toutes les libs et un autre qui s'appelle appli.js pour mon appli).

Peut-être même chargez vous vos scripts de manière asynchrone à la main ou avec LAB.js mais reste et restera le problème du cache.

Ne me dites pas que c'est impossible, c'est vrai, je l'ai connu. Une des solutions consiste à ajouter la date à la fin du nom de fichier en utilisant ? pour indiquer une requête. Elle ne sera pas prise en compte, mais le serveur comprendra qu'il faut renvoyer le script.

<script type="text/javascript" src="/static/js/monscript.js?{% date_now %}"></script>

date_now est un tag qui renvoit la date au format numérique

import time

@register.filter
def date_now():
return str(int(time.time()))

Mais cela reste une mauvaise solution car votre utilisateur chargera à chaque fois le script.

J'étais là, je méditais tranquilement sur ce problème quand la solution m'est venu. Généralement, une modif ne vient jamais seule, il faut regarger le démon wsgi à chaque fois (méthode expliquée ici).

Il suffit de tenir à jour un fichier contenant le nombre de rechargement...

Donc, dans le fichier settings.py j'ajoute :

import os

PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))
NUMBER_OF_RELOAD = 1

filename = os.path.join(PROJECT_PATH, "number_of_reload.txt")

if os.path.exists(filename):
NUMBER_OF_RELOAD = int(open(filename, 'r').read()) + 1

Puis dans le fichier monitor.py qui permet de recharger le démon wsgi au tout début :

# Name for the reload counter
from settings import PROJECT_PATH
filename = os.path.join(PROJECT_PATH, "number_of_reload.txt")

def _restart(path):
# Debut de la routine
# ...
# Add the reload counter
 number_of_reload = int(open(filename, 'r').read()) + 1
open(filename, 'w').write(str(number_of_reload))

 

Nous avons donc un fichier qui tient le compte des reload puis je crée un processeur de gabarit :

def reloadcount(request):
return { 'NUMBER_OF_RELOAD' : settings.NUMBER_OF_RELOAD }

Il suffira alors dans le gabarit d'écrire :

<script type="text/javascript" src="/static/js/monfichier.js?{{ NUMBER_OF_RELOAD }}"></script>

À chaque modification, le compteur changera d'incrément et les fichiers critiques seront gentillement rechargé. En l'absence de modification, on laisse jouer les caches à différents endroits (serveur, navigateur, etc). Avec cette méthode, j'ai mis un temps d'expiration très long, ce qui permet d'alléger un peu la bande passante, sans absoluement aucun problème.

 

Commentaires

Gravatar de Circonflex
Circonflex
On Saturday 19 Jan 2013

Merci pour cet article fort intéressant, une petite chose pour l'appel au script sur la dernière ligne

ne faudrait-il pas utiliser {{RELOAD_COUNT}} au lieu de {{NUMER_OF_RELOAD}}


Gravatar de Regis
Regis
On Monday 21 Jan 2013

Ooops pas vu. J'ai corrigé. Cependant, ce type de méthode ne convient pas vraiment, je ne suis pas très satisfait du résultat, je pense faire une correction pour ce post.


Add your comment

HTML code is displayed as text and web addresses are automatically converted.