it-swarm.com.de

Verhindern, dass RequireJS erforderliche Skripts zwischenspeichert

RequireJS scheint intern etwas zu tun, dass Caches Javascript-Dateien erfordern. Wenn ich eine der erforderlichen Dateien ändere, muss ich die Datei umbenennen, damit die Änderungen übernommen werden. 

Der übliche Trick, eine Versionsnummer als Querzeichenfolge-Parameter an das Ende des Dateinamens anzuhängen, funktioniert nicht mit requiredjs <script src="jsfile.js?v2"></script> 

Was ich suche, ist eine Möglichkeit, dieses interne Zwischenspeichern von RequireJS-erforderlichen Skripts zu verhindern, ohne meine Skriptdateien bei jeder Aktualisierung umbenennen zu müssen.

Plattformübergreifende Lösung:

Ich verwende jetzt urlArgs: "bust=" + (new Date()).getTime() für das automatische Cache-Busting während der Entwicklung und urlArgs: "bust=v2" für die Produktion, bei der ich die hartcodierte Version num nach dem Ausrollen eines aktualisierten erforderlichen Skripts inkrementiere.

Hinweis:

@Dustin Getz hat kürzlich in einer Antwort erwähnt, dass die Chrome Developer Tools beim Debuggen Haltepunkte löschen, wenn Javascript-Dateien kontinuierlich aktualisiert werden. Eine Problemumgehung besteht darin, debugger; in den Code zu schreiben, um einen Haltepunkt in den meisten Javascript-Debuggern auszulösen.

Server-spezifische Lösungen:

Nachfolgend finden Sie einige Lösungen, die möglicherweise für Ihre Serverumgebung wie Node oder Apache besser geeignet sind.

291
BumbleB2na

RequireJS kann so konfiguriert werden, dass an jede Skript-URL ein Wert angehängt wird, um das Cache-Busting durchzuführen. 

Aus der RequireJS-Dokumentation ( http://requirejs.org/docs/api.html#config ):

urlArgs: Zusätzliche Abfragezeichenfolge-Argumente, die an URLs angehängt werden, die RequireJS ruft Ressourcen ab. Am nützlichsten für die Zwischenspeicherung, wenn der Browser oder Server ist nicht richtig konfiguriert. 

Beispiel: Anhängen von "v2" an alle Skripte:

require.config({
    urlArgs: "bust=v2"
});

Zu Entwicklungszwecken können Sie erzwingen, dass RequireJS den Cache umgeht, indem Sie einen Zeitstempel anfügen:

require.config({
    urlArgs: "bust=" + (new Date()).getTime()
});
444
phil mccullick

Verwenden Sie hierfür keine urlArgs!

Erfordert das Laden von Skripts in Bezug auf http-Caching-Header. (Skripts werden mit einem dynamisch eingefügten <script> geladen. Dies bedeutet, dass die Anforderung genau wie jedes alte Objekt angezeigt wird, das geladen wird.)

Stellen Sie Ihre Javascript-Assets mit den richtigen HTTP-Headern bereit, um die Zwischenspeicherung während der Entwicklung zu deaktivieren. 

Die Verwendung von urlArgs von Requests bedeutet, dass von Ihnen festgelegte Haltepunkte nicht bei Aktualisierungen erhalten bleiben. Sie müssen am Ende debugger-Anweisungen überall in Ihrem Code einfügen. Schlecht. Ich verwende urlArgs für Cache-Busting-Assets während Produktions-Upgrades mit dem git sha; Dann kann ich festlegen, dass meine Assets für immer zwischengespeichert werden und garantiert wird, dass sie niemals veraltete Assets haben. 

In der Entwicklung spreche ich über alle ajax-Anforderungen mit einer komplexen mockjax -Konfiguration, dann kann ich meine App im Nur-Javascript-Modus mit einem 10-Zeilen-Python-HTTP-Server mit deaktiviertem Caching bedienen . Dies hat sich für mich zu einer ziemlich großen "Enterprisey" -Anwendung mit hunderten restful Webservice-Endpunkten entwickelt. Wir haben sogar einen vertraglich vereinbarten Designer, der mit unserer echten Produktions-Codebase arbeiten kann, ohne ihm Zugriff auf unseren Backend-Code zu gewähren.

54
Dustin Getz

Die urlArgs-Lösung hat Probleme. Leider können Sie nicht alle Proxy-Server steuern, die sich möglicherweise zwischen Ihnen und dem Webbrowser Ihres Benutzers befinden. Einige dieser Proxyserver können leider so konfiguriert werden, dass beim Zwischenspeichern von Dateien URL-Parameter ignoriert werden. In diesem Fall wird die falsche Version Ihrer JS-Datei an Ihren Benutzer gesendet.

Ich gab schließlich auf und implementierte meinen eigenen Fix direkt in requir.js. Wenn Sie bereit sind, Ihre Version der Bibliothek "requiredjs" zu ändern, funktioniert diese Lösung möglicherweise für Sie.

Sie können den Patch hier sehen:

https://github.com/jbcpollak/requirejs/commit/589ee0cdfe6f719cd761eee631ce68eee09a5a67

Einmal hinzugefügt, können Sie in Ihrer erforderlichen Konfiguration Folgendes tun:

var require = {
    baseUrl: "/scripts/",
    cacheSuffix: ".buildNumber"
}

Verwenden Sie Ihre Buildsystem- oder Serverumgebung, um buildNumber durch eine Versions-ID/Softwareversion/Lieblingsfarbe zu ersetzen.

Verwenden erfordern wie folgt:

require(["myModule"], function() {
    // no-op;
});

Erfordert, dass diese Datei angefordert wird:

http://yourserver.com/scripts/myModule.buildNumber.js

In unserer Serverumgebung verwenden wir Regeln zum Umbenennen von URLs, um die buildNumber zu entfernen und die richtige JS-Datei bereitzustellen. Auf diese Weise müssen wir uns nicht wirklich darum kümmern, alle unsere JS-Dateien umzubenennen.

Der Patch ignoriert jedes Skript, das ein Protokoll angibt, und wirkt sich nicht auf Nicht-JS-Dateien aus.

Dies funktioniert gut für meine Umgebung, aber ich weiß, dass einige Benutzer ein Präfix statt ein Suffix bevorzugen würden. Es sollte leicht sein, mein Commit an Ihre Bedürfnisse anzupassen.

Update:

In der Pullanforderungsdiskussion schlägt der Autor von requirjs vor, dass dies als Lösung zum Voranstellen der Revisionsnummer dienen kann:

var require = {
    baseUrl: "/scripts/buildNumber."
};

Ich habe dies nicht versucht, aber das impliziert, dass dies die folgende URL anfordern würde:

http://yourserver.com/scripts/buildNumber.myModule.js

Was für viele Menschen sehr gut funktionieren könnte, die ein Präfix verwenden können.

Hier sind einige mögliche doppelte Fragen:

RequireJS und Proxy-Caching

requir.js - Wie kann ich eine Version der erforderlichen Module als Teil der URL festlegen?

22
JBCP

Inspiriert von Cache auf required.js data-main auslaufen Wir haben unser Implementierungsskript mit der folgenden Ant-Task aktualisiert:

<target name="deployWebsite">
    <untar src="${temp.dir}/website.tar.gz" dest="${website.dir}" compression="gzip" />       
    <!-- fetch latest buildNumber from build agent -->
    <replace file="${website.dir}/js/main.js" token="@[email protected]" value="${buildNumber}" />
</target>

Wo der Anfang von main.js aussieht:

require.config({
    baseUrl: '/js',
    urlArgs: '[email protected]@',
    ...
});
19
dvtoever

In Produktion

urlArgs kann zu Problemen führen!

Der Hauptautor von requirjs bevorzugt urlArgs nicht:

Für bereitgestellte Assets lege ich es vor, die Version oder den Hashwert für das gesamte Erstellen Sie ein Build-Verzeichnis und ändern Sie einfach die verwendete baseUrl config Damit das Projekt dieses versionierte Verzeichnis als baseUrl verwenden kann. Dann keine anderen Dateien ändern sich und es hilft, einige Proxy-Probleme zu vermeiden, wenn sie kann eine URL mit einer Abfragezeichenfolge nicht zwischenspeichern.

Mein Styling.

Ich folge diesem Rat.

In Entwicklung

Ich ziehe es vor, einen Server zu verwenden, der Dateien, die häufig geändert werden, intelligent zwischenspeichert: Ein Server, der Last-Modified ausgibt und auf If-Modified-Since mit 304 antwortet, wenn dies angebracht ist. Sogar ein Server, der auf Node express set basiert, um statische Dateien zu liefern, macht dies sofort. Es ist nicht erforderlich, etwas an meinem Browser zu tun und Verwirrungen zu vermeiden.

11
Louis

Ich habe dieses Snippet von AskApache genommen und es in eine separate .conf-Datei meines lokalen Apache-Webservers gelegt (in meinem Fall /etc/Apache2/others/preventcaching.conf):

<FilesMatch "\.(html|htm|js|css)$">
FileETag None
<ifModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</ifModule>
</FilesMatch>

Für die Entwicklung funktioniert dies gut, ohne dass der Code geändert werden muss. Für die Produktion kann ich den Ansatz von @dvtoever verwenden.

6
myrho

Quick Fix für Entwicklung

Für die Entwicklung können Sie einfach den Cache in Chrome Dev Tools deaktivieren} ( Deaktivieren des Chrome-Caches für die Websiteentwicklung ). Die Deaktivierung des Cache geschieht nur, wenn das Dialogfeld für die Entwicklertools geöffnet ist. Sie müssen also nicht jedes Mal diese Option aktivieren, wenn Sie regelmäßig surfen.

Hinweis: Die Verwendung von 'urlArgs' ist die richtige Lösung in der Produktion, sodass Benutzer den neuesten Code erhalten. Das Debugging ist jedoch schwierig, da Chrome bei jeder Aktualisierung Haltepunkte ungültig macht (weil es sich um eine 'neue' Datei handelt, die jedes Mal geliefert wird).

5
Deepak Joy

Ich empfehle nicht die Verwendung von ' urlArgs ' für das Cache-Bursting mit RequireJS. Da dies das Problem nicht vollständig löst. Beim Aktualisieren einer Version no werden alle Ressourcen heruntergeladen, auch wenn Sie nur eine einzelne Ressource geändert haben.

Um dieses Problem zu lösen, empfehle ich die Verwendung von Grunt-Modulen wie 'filerev' zum Erstellen der Revisionsnummer. Darüber hinaus habe ich in Gruntfile eine benutzerdefinierte Aufgabe geschrieben, um die Revision zu aktualisieren, wo immer dies erforderlich ist.

Bei Bedarf kann ich das Code-Snippet für diese Aufgabe freigeben.

3
Amit Sagar

So mache ich es in Django/Flask (kann leicht an andere Sprachen/VCS-Systeme angepasst werden):

In Ihrem config.py (ich verwende dies in python3, daher müssen Sie möglicherweise die Kodierung in python2 anpassen)

import subprocess
GIT_HASH = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8')

Dann in deiner Vorlage:

{% if config.DEBUG %}
     require.config({urlArgs: "bust=" + (new Date().getTime())});
{% else %}
    require.config({urlArgs: "bust=" + {{ config.GIT_HASH|tojson }}});
{% endif %}
  • Erfordert keinen manuellen Build-Prozess
  • Führt git rev-parse HEAD nur einmal beim Start der App aus und speichert sie im config-Objekt
2
Stephen Fuhry

Dynamische Lösung (ohne URLs)

Es gibt eine einfache Lösung für dieses Problem, sodass Sie für jedes Modul eine eindeutige Versionsnummer laden können.

Sie können die ursprüngliche RequiredJs.load-Funktion speichern, mit Ihrer eigenen Funktion überschreiben und Ihre geänderte URL erneut in die ursprüngliche RequiredJs.load-Datei einlesen:

var load = requirejs.load;
requirejs.load = function (context, moduleId, url) {
    url += "?v=" + oRevision[moduleId];
    load(context, moduleId, url);
};

In unserem Aufbauprozess habe ich "gulp-rev" verwendet, um eine Manifestdatei mit allen Überarbeitungen aller Module zu erstellen, die verwendet werden. Vereinfachte Version meiner Schluckaufgabe:

gulp.task('gulp-revision', function() {
    var sManifestFileName = 'revision.js';

    return gulp.src(aGulpPaths)
        .pipe(rev())
        .pipe(rev.manifest(sManifestFileName, {
        transformer: {
            stringify: function(a) {
                var oAssetHashes = {};

                for(var k in a) {
                    var key = (k.substr(0, k.length - 3));

                    var sHash = a[k].substr(a[k].indexOf(".") - 10, 10);
                    oAssetHashes[key] = sHash;
                }

                return "define([], function() { return " + JSON.stringify(oAssetHashes) + "; });"
            }
        }
    }))
    .pipe(gulp.dest('./'));
});

dadurch wird ein AMD-Modul mit Revisionsnummern für moduleNames generiert, das als 'oRevision' in der Datei main.js enthalten ist. In diesem Fall überschreiben Sie die Funktion requiredjs.load wie zuvor gezeigt.

0
mat