web-dev-qa-db-ja.com

インポートされたバストモジュールをes6にキャッシュするにはどうすればよいですか?

ES6モジュールを使用すると、次のように単一のエントリポイントを作成できます。

// main.js

import foo from 'foo';

foo()
<script src="scripts/main.js" type="module"></script>

foo.jsはブラウザのキャッシュに保存されます。これは、新しいバージョンのfoo.jsを本番環境にプッシュするまで望ましいです。

ブラウザーにjsファイルの新しいバージョンを取得するように強制するために、一意のIDを持つクエリ文字列パラメーターを追加することは一般的な方法です(foo.js?cb = 1234

Es6モジュールパターンを使用してこれをどのように実現できますか?

25
spinners

救出へのHTTPヘッダー。ファイルのチェックサムである ETag を使用してファイルを提供します。 S3はそれを行います デフォルトでは 例では。ファイルを再度インポートしようとすると、ブラウザーはファイルを要求し、今度はETagを " if-none-match "ヘッダーに添付します。サーバーはETagが現在のファイルと一致するかどうかを確認しますそして、304 Not Modifiedで帯域幅と時間を節約するか、ファイルの新しいコンテンツ(新しいETagを含む)を送り返します。

これにより、プロジェクト内の単一のファイルを変更した場合、ユーザーは他のすべてのモジュールのコンテンツ全体をダウンロードする必要がなくなります。短い_max-age_ヘッダーも追加することをお勧めします。これにより、同じモジュールが短時間に2回リクエストされた場合、追加のリクエストは発生しません。

キャッシュ無効化を追加する場合(例:バンドルを使用して?x = {randomNumber}を追加するか、すべてのファイル名にチェックサムを追加する)、ユーザーはすべての新しいプロジェクトバージョンで必要なすべてのファイルの完全なコンテンツをダウンロードする必要があります。

どちらのシナリオでも、とにかく各ファイルに対してリクエストを実行します(カスケードでインポートされたファイルは新しいリクエストを生成し、etagsを使用する場合、少なくとも小さな304で終了します)。これを回避するには、動的インポートを使用できますe.g if (userClickedOnSomethingAndINeedToLoadSomeMoreStuff) { import('./someModule').then('...') }

4
Riccardo Galli

私の観点からは 動的インポート がここでの解決策となり得ます。

手順1)gulpまたはwebpackを使用してマニフェストファイルを作成します。そこで、次のようなマッピングがあります。

export default {
    "/vendor/lib-a.mjs": "/vendor/lib-a-1234.mjs",
    "/vendor/lib-b.mjs": "/vendor/lib-b-1234.mjs"
};

ステップ2)パスを解決するファイル関数を作成する

import manifest from './manifest.js';

const busted (file) => {
 return manifest[file];
};

export default busted;

ステップ3)動的インポートを使用する

import busted from '../busted.js';

import(busted('/vendor/lib-b.mjs'))
  .then((module) => {
    module.default();
});

Chrome=で少し試してみれば、機能します。相対パスの処理は、ここではトリッキーな部分です。

2
d-bro82

現時点では考えただけですが、weboackですべての分割されたバンドルにコンテンツハッシュを挿入し、そのハッシュをインポートステートメントに書き込むことができるはずです。私はそれがデフォルトで2番目を行うと思います。

1
user11639687

クエリ文字列を含まない、これらすべてのソリューションが1つあります。モジュールファイルが/modules/にあるとします。モジュールをインポートするときに、相対モジュール解決./または../を使用してから、サーバー側のパスを書き直してバージョン番号を含めます。 /modules/x.x.x/などを使用し、パスを/modules/に書き換えます。これで、最初のモジュールに<script type="module" src="/modules/1.1.2/foo.mjs"></script>を含めることで、モジュールのグローバルバージョン番号を取得できます。

または、パスを書き換えることができない場合は、開発中にファイルをフォルダー/modules/version/に入れ、versionフォルダーの名前をバージョン番号に変更し、公開時にスクリプトタグのパスを更新します。

1
Wanton

相対パスの使用は私にとってはうまくいきます:

import foo from './foo';

または

import foo from './../modules/foo';

の代わりに

import foo from '/js/modules/foo';
0
Fifi

以前の回答で指摘されているようにETagを使用するか、またはLast-Modifiedと関連してIf-Modified-Sinceを使用することができます。

考えられるシナリオは次のとおりです。

  1. ブラウザは最初にリソースをロードします。サーバーはLast-Modified: Sat, 28 Mar 2020 18:12:45 GMTおよびCache-Control: max-age=60で応答します。
  2. 最初のリクエストから60秒より前に2回目のリクエストが開始された場合、ブラウザはキャッシュからファイルを提供し、サーバーへの実際のリクエストは行いません。
  3. リクエストが60秒後に開始された場合、ブラウザはキャッシュファイルが古くなっていると見なし、If-Modified-Since: Sat, 28 Mar 2020 18:12:45 GMTヘッダーを含むリクエストを送信します。サーバーはこの値をチェックし、
    • 上記の日付以降にファイルが変更された場合、本文に新しいファイルを含む200応答が発行されます。
    • 日付以降にファイルが変更されていない場合、サーバーはa304 "変更なし"ステータスを空のボディで発行します。

私はこれでApacheサーバー用に設定されました:

<IfModule headers_module>
  <FilesMatch "\.(js|mjs)$">
    Header set Cache-Control "public, must-revalidate, max-age=3600"
    Header unset ETag
  </FilesMatch>
</IfModule>

max-ageをお好みに設定できます。

ETagの設定を解除する必要があります。それ以外の場合、Apacheは毎回200 OKで応答し続けます( バグです )。また、変更日に基づくキャッシュを使用する場合は必要ありません。

0
Tigran