必要なスクリプトをキャッシュすることを要求することを防ぎます
-
25-10-2019 - |
質問
要求は、キャッシュがJavaScriptファイルを必要とすることを内部的に行うようです。必要なファイルのいずれかに変更を加えると、変更を適用するためにファイルの名前を変更する必要があります。
ファイル名の最後までQueryStringパラメーションとしてバージョン番号を追加するという一般的なトリックは、requirejsで動作しません <script src="jsfile.js?v2"></script>
私が探しているのは、更新されるたびにスクリプトファイルを変更することなく、必要なスクリプトのこの内部キャッシュを防ぐ方法です。
クロスプラットフォームソリューション:
私は今使っています urlArgs: "bust=" + (new Date()).getTime()
開発中の自動キャッシュバスト用 urlArgs: "bust=v2"
更新された必要なスクリプトをロールアウトした後、ハードコーディングバージョンNUMを増やすプロダクションの場合。
ノート:
@Dustin Getzは、JavaScriptファイルがこのように継続的に更新されているときに、Chrome開発者ツールがデバッグ中にブレークポイントをドロップすることを最近の回答で述べました。 1つの回避策は書くことです debugger;
コードでは、ほとんどのJavaScriptデバッガーでブレークポイントをトリガーします。
サーバー固有のソリューション:
ノードやApacheなどのサーバー環境に適した特定のソリューションについては、以下の回答の一部を参照してください。
解決
要求は、キャッシュバスト用の各スクリプトURLに値を追加するように構成できます。
requirejsドキュメントから(http://requirejs.org/docs/api.html#config):
urlargs: :JSを必要とするURLに追加された追加クエリ文字列引数は、リソースを取得するために使用します。ブラウザまたはサーバーが正しく構成されていない場合、バストをキャッシュするのに最も便利です。
たとえば、すべてのスクリプトに「V2」を追加します。
require.config({
urlArgs: "bust=v2"
});
開発目的では、タイムスタンプを追加して、キャッシュをバイパスする必要がある必要があります。
require.config({
urlArgs: "bust=" + (new Date()).getTime()
});
他のヒント
これにはurlargsを使用しないでください!
スクリプトのロードを必要とします。 (スクリプトには動的に挿入されています <script>
, 、これは、リクエストがロードされている古い資産のように見えることを意味します。)
開発中にキャッシュを無効にするために、適切なHTTPヘッダーを使用してJavaScriptアセットを提供します。
requireのurlargsを使用すると、設定したブレークポイントは、リフレッシュ全体で保存されません。あなたは置く必要があることになります debugger
あなたのコードのどこでもステートメント。悪い。私が使う urlArgs
Git Shaでの生産アップグレード中のキャッシュバスト資産の場合。その後、私は自分の資産を永遠にキャッシュするように設定し、古い資産を持たないことを保証することができます。
開発では、私はすべてのajaxリクエストを複雑なものでock笑します モックジャックス 構成、その後、javascriptのみのモードでアプリを提供できます すべてのキャッシュをオフにした10ラインPython HTTPサーバー. 。これは、何百ものRESTFUL WEBSVICEエンドポイントを備えた非常に大きな「Enterprisey」アプリケーションに拡大されました。バックエンドコードにアクセスできるようにすることなく、実際の制作コードベースを使用できる契約設計者もいます。
Urlargsソリューションには問題があります。残念ながら、あなたとユーザーのWebブラウザーの間にある可能性のあるすべてのプロキシサーバーを制御することはできません。これらのプロキシサーバーの一部は、残念ながらファイルをキャッシュするときにURLパラメーターを無視するように構成できます。これが発生した場合、JSファイルの間違ったバージョンがユーザーに配信されます。
私はついにあきらめました 独自の修正を実装しました require.jsに直接requirejsライブラリのバージョンを変更することをいとわない場合は、このソリューションが機能する可能性があります。
ここでパッチを見ることができます:
https://github.com/jbcpollak/requirejs/commit/589ee0cdfe6f719cd761eee631ce68eee09a5a67
追加されると、必要な構成でこのようなことを行うことができます。
var require = {
baseUrl: "/scripts/",
cacheSuffix: ".buildNumber"
}
ビルドシステムまたはサーバー環境を使用して置き換えます buildNumber
改訂ID /ソフトウェアバージョン /お気に入りの色。
このような要求を使用する:
require(["myModule"], function() {
// no-op;
});
このファイルを要求する必要があります:
http://yourserver.com/scripts/myModule.buildNumber.js
サーバー環境では、URLの書き換えルールを使用してBuildNumberを削除し、正しいJSファイルを提供します。これにより、JSファイルのすべての名前を変更することを実際に心配する必要はありません。
パッチは、プロトコルを指定するスクリプトを無視し、非JSファイルには影響しません。
これは私の環境に適していますが、一部のユーザーは接尾辞よりも接頭辞を好むことを認識しています。ニーズに合わせてコミットを変更するのは簡単です。
アップデート:
プル要求のディスカッションでは、RequireJSの著者は、これが改訂番号に接頭辞の解決策として機能する可能性があることを示唆しています。
var require = {
baseUrl: "/scripts/buildNumber."
};
私はこれを試したことはありませんが、その意味は、これが次のURLを要求するということです。
http://yourserver.com/scripts/buildNumber.myModule.js
これは、プレフィックスを使用できる多くの人にとって非常にうまく機能する可能性があります。
いくつかの可能な複製の質問があります:
に触発された require.js data-mainでキャッシュを期限切れにします 次のANTタスクで展開スクリプトを更新しました。
<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="@Revision@" value="${buildNumber}" />
</target>
main.jsの始まりが次のようになります:
require.config({
baseUrl: '/js',
urlArgs: 'bust=@Revision@',
...
});
生産中
urlArgs
問題を引き起こす可能性があります!
requirejsの主要な著者 使用しないことを好みます urlArgs
:
展開された資産の場合、ビルドディレクトリとしてビルド全体にバージョンまたはハッシュを配置することを好み、次に変更するだけです
baseUrl
プロジェクトに使用される構成は、そのバージョン付きディレクトリを使用しますbaseUrl
. 。その後、他のファイルは変更されず、避けるのに役立ちます いくつかのプロキシの問題は、クエリ文字列が付いているURLをキャッシュしない場合があります。
私のスタイリング。
私はこのアドバイスに従います。
開発中
私は、頻繁に変更される可能性のあるファイルをインテリジェントにキャッシュするサーバーを使用することを好みます。 Last-Modified
と応答します If-Modified-Since
必要に応じて304で。ノードに基づいたサーバーでさえ 特急 静的ファイルを提供するように設定して、これをボックスからすぐに行います。ブラウザに何もする必要はなく、ブレークポイントを台無しにしません。
私はこのスニペットを撮りました Askapache そして、それを私の地元のApache WebServerの別の.CONFファイルに入れます(私の場合/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>
開発のために、これはコードを変更する必要がなく、正常に機能します。制作に関しては、 @DVToeverのアプローチを使用する場合があります。
開発のための迅速な修正
開発のために、あなただけができます Chrome Dev Toolsでキャッシュを無効にします (Webサイト開発のためのChromeキャッシュの無効化)。キャッシュの無効化は、Dev Toolsダイアログが開いている場合にのみ発生するため、通常のブラウジングを行うたびにこのオプションを切り替えることを心配する必要はありません。
注: 'の使用urlargs「生産の適切なソリューションであるため、ユーザーは最新のコードを取得します。しかし、Chromeが更新するたびにブレークポイントを無効にするため、デバッグは困難になります(毎回「新しい」ファイルが提供されているため)。
使用することはお勧めしませんurlargs'必要なjsで破裂するキャッシュの場合。これは問題を完全に解決しないためです。バージョン番号を更新すると、単一のリソースを変更するだけでも、すべてのリソースがダウンロードされます。
この問題を処理するには、改訂版を作成するために「filerev」などのgruntモジュールを使用することをお勧めします。これに加えて、私はGruntFileでカスタムタスクを書き、必要な場所に改訂版を更新しました。
必要に応じて、このタスクのコードスニペットを共有できます。
これは私がDjango / Flaskでそれを行う方法です(他の言語 / VCSシステムに簡単に適合させることができます):
あなたの中で config.py
(私はこれをPython3で使用するので、Python2でエンコードを調整する必要があるかもしれません)
import subprocess
GIT_HASH = subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip().decode('utf-8')
次に、テンプレートで:
{% if config.DEBUG %}
require.config({urlArgs: "bust=" + (new Date().getTime())});
{% else %}
require.config({urlArgs: "bust=" + {{ config.GIT_HASH|tojson }}});
{% endif %}
- 手動ビルドプロセスは必要ありません
- 実行するだけです
git rev-parse HEAD
アプリが起動して、それをに保存したときにconfig
物体
動的解(Urlargsなし)
この問題には簡単なソリューションがあり、すべてのモジュールに一意のリビジョン番号をロードできます。
元のrequirejs.load関数を保存し、独自の関数で上書きし、変更されたURLを元のrequirejs.loadに解析できます。
var load = requirejs.load;
requirejs.load = function (context, moduleId, url) {
url += "?v=" + oRevision[moduleId];
load(context, moduleId, url);
};
建築プロセスでは、「Gulp-Rev」を使用して、使用されているすべてのモジュールのすべての改訂を伴うマニフェストファイルを構築しました。私のガルプタスクの簡素化されたバージョン:
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('./'));
});
これにより、ModuleNamesに改訂番号を備えたAMDモジュールが生成されます。これは、Main.jsで「Orevision」として含まれており、前に示すようにRequesJs.Load関数を上書きします。
これは、@Phil McCullの受け入れられた答えに加えています。
私は彼の方法を使用しますが、ビルド前に実行されるT4テンプレートを作成することにより、プロセスも自動化します。
ビルド前コマンド:
set textTemplatingPath="%CommonProgramFiles(x86)%\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe"
if %textTemplatingPath%=="\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe" set textTemplatingPath="%CommonProgramFiles%\Microsoft Shared\TextTemplating\$(VisualStudioVersion)\texttransform.exe"
%textTemplatingPath% "$(ProjectDir)CacheBuster.tt"
T4テンプレート:
require.config.jsがロードされる前に変数に保存します。
require.config.jsの参照:
私の場合、クリックするたびに同じフォームを読み込みたいと思っていましたが、ファイルで行った変更は必要ありませんでした。この投稿に正確には関係ないかもしれませんが、これは、必要に応じて設定を設定せずにクライアント側の潜在的なソリューションになる可能性があります。コンテンツを直接送信する代わりに、必要なファイルのコピーを作成し、実際のファイルをそのままに保つことができます。
LoadFile(filePath){
const file = require(filePath);
const result = angular.copy(file);
return result;
}