webpackが静的リソースキャッシュを実装する方法

webpackが静的リソースキャッシュを実装する方法

導入

静的リソースのキャッシュはフロントエンドのパフォーマンス最適化のポイントであるため、フロントエンドの開発プロセスでは、キャッシュが最大限に利用されるのが一般的です (ここでは主に強力なキャッシュ)。この記事の話題に戻りますが、webpack でビルドされたプロジェクトでは、注意しないと、サーバーがキャッシュ戦略を設定しても、ビルドされたプロジェクトで静的リソースのキャッシュを実現できない可能性があります。では、webpack はキャッシュを使用する効果をどのように実現できるのでしょうか? この問題については以下で説明します。

複数の異なるハッシュを区別する

私たちは皆、webpack には各プロジェクトのビルドhash 、さまざまなエントリのchunkhash 、ファイル コンテンツのcontenthashなど、さまざまなハッシュ値があることを知っています。これほど多くのハッシュがある場合、それらの違いは何でしょうか?

ハッシュ

ハッシュは、webpack ビルド プロジェクト全体に関連しています。プロジェクト ファイルが「変更」されていない場合でも、ハッシュに対応する値はプロジェクトがビルドされるたびに異なります。

実際、これは変更されており、webpack がパッケージ化されてコンパイルされるたびに、webpack ランタイム コードが挿入され、プロジェクト全体に変更が加えられるため、ハッシュ値が毎回変更されます。

私のプロジェクト コードを例に、変更を加えずに 2 回のビルドを行う前と後のコードの比較を示します。

対応するプロジェクト ビルドのハッシュが 2 回変更されたことがわかります。ハッシュが毎回変わるため、この方法ではキャッシュを実現できないと推測できます。

チャンクハッシュ

Chunkhash は、その名前が示すように、webpack によってパッケージ化されたチャンクに関連しています。具体的には、webpack はエントリ構成ファイルの依存関係を分析し、それに基づいてエントリのチャンクを構築し、対応するハッシュ値を生成します。チャンクが異なればハッシュ値も異なります。通常、プロジェクトでは、パブリック依存ライブラリとプログラムエントリファイルを分離して別々にパッケージ化し、チャンクハッシュを使用してハッシュ値を生成します。パブリック依存ライブラリが変更されない限り、対応するチャンクハッシュは変更されないため、キャッシュの目的が達成されます。

通常、chunkhash はプロジェクトの webpack エントリに使用され、出力構成項目に具体的に反映されます。

モジュール.エクスポート = {
  エントリー: {
   アプリ: './src/main.js',
   ベンダー: ['react'、'redux'、'react-dom'、'react-redux'、'react-router-redux']
  },
  出力: {
    パス:path.join(__dirname, '/dist/js'),
    ファイル名: '[name].[chunkhash].js'
  }
 ...
}

最後に、アプリとベンダーのチャンクハッシュコンパイル結果は次のとおりです。

コンテンツハッシュ

Contenthash は、ファイル コンテンツによって生成されたハッシュ値を表します。コンテンツが異なると、異なる contenthash 値が生成されます。プロジェクトでは、プロジェクト内の CSS を参照用の対応する CSS ファイルに抽出するのが一般的です。たとえば、次のように webpack 構成で使用します。

モジュール.エクスポート = {
  ...
  プラグイン: [
     新しいExtractTextPlugin({
	ファイル名: 'static/[name]_[chunkhash:7].css',
	無効: false、
	すべてのチャンク: true
     })
  ...
  ]

上記の構成では、chunkhash が使用され、それに依存するチャンクと chunkhash が共有されるため、問題が発生します。

たとえば、上記のアプリ チャンクの例では、index.css ファイルに依存しています。index.css のハッシュは、アプリのチャンクハッシュに従います。アプリ ファイルが変更される限り、index.css ファイルが変更されなくても、そのハッシュ値も変更され、キャッシュが失敗します。

次に、extra-text-webpack-plugin のcontenthash値を使用して、CSS ファイルが配置されているモジュール内の他のファイルの内容が変更された場合でも、CSS ファイルの内容が変更されない限り、そのハッシュ値は変更されないことを保証できます。

js キャッシュの実装

webpack プラグインCommonsChunkPluginの主な機能は、webpack プロジェクト エントリ チャンクの共通部分を抽出することです。具体的な使用方法については詳しく説明しません。よくわからない場合は、webpack 公式サイトの紹介を参照してください。

このプラグインは、Webpack プロジェクトでよく使用される最適化機能であり、ほぼすべての Webpack プロジェクトで使用されます。このプラグインを使用する利点:

  • webpack のパッケージ化速度とプロジェクト サイズの改善: webpack エントリのチャンク ファイルからすべての共通コードを抽出してコード サイズを削減し、同時に webpack のパッケージ化速度を改善します。
  • キャッシュ メカニズムを活用する: 依存するパブリック モジュール ファイルは通常、ほとんど変更されないか、まったく変更されないため、独立したモジュール ファイルを抽出して長期間キャッシュすることができます。

ただし、プロジェクトでプラグインが誤って開かれると、上記の 2 番目のポイントは達成できません。その理由は次のとおりです。

変更されていないパブリック コードまたはライブラリ コードにパッケージ化されたエントリ チャンクは、他のビジネス コードの変更によって変更され、ページ上のロング キャッシュ メカニズムが失敗する原因になります。

それでは、 CommonsChunkPlugin正しく開きましょう。

CommonsChunkPlugin の誤った使用法

react、react-dom、react-router などのプロジェクトの共通ライブラリをビジネス コードから分離し、ベンダー チャンクとして抽出すると、webpack 構成は次のようになります。

webpack は、次のコードで定義されます。
定数パス = require('path');
モジュール.エクスポート = {
  エントリー: {
    アプリ: "./src/main.js",
    ベンダー: ["react","re​​act-dom", "redux", "react-redux", "react-router-redux"]
  },
  出力: {
    パス: path.resolve(__dirname, 'output'),
    ファイル名: "[name].[chunkhash].js"
  },
  プラグイン: [
    新しい webpack.optimize.CommonsChunkPlugin({names: ["vendor"]})
  ]
};

上記では、プロジェクトのいくつかの基本ライブラリが vendor と呼ばれるチャンクにパッケージ化され、ビジネス関連のコードは app と呼ばれるチャンクにパッケージ化されています。

webpack のパッケージ化とコンパイルの結果は次のとおりです。

ビジネス コード app.js を変更した後、再コンパイルの結果は次のようになります。

CommonsChunkPlugin の設定では、ビジネス コード アプリが変更されると、ライブラリ コードも変更され、ベンダーのチャンクハッシュも変更されることがわかります。このように、ベンダーの参照の名前が変更され、ブラウザー上のロング キャッシュ メカニズムが失敗する原因になります。

問題の原因

webpack がコンパイルされるたびにベンダーが変わる理由:

Webpack はビルドするたびにランタイム コードを生成します。ファイルが 1 つしかない場合は、ランタイム コードがそのファイルに直接詰め込まれます。ファイルが複数ある場合、ランタイム コードは共通ファイル、つまり上記の CommonsChunkPlugin によって構成されたベンダー チャンクに抽出されます。

グローバル webpackJsonp メソッドの定義やモジュール依存関係の維持など、コンパイルのたびに webpack によって生成されるランタイム コードについては、こちら >> を参照してください。

したがって、上記の webpack の CommonsChunkPlugin 構成では、これらのコードはコンパイルされるたびにベンダーにパッケージ化され、ベンダーのチャンクハッシュが毎回変更されることになります。

次に、ベンダー チャンクを構成して共通コード、つまり webpack ランタイム コードを抽出し、プロジェクトが依存する基本ライブラリ モジュールをビジネス モジュールから分離できるようにします。これらのファイルは変更されないため、これらのファイルはロング キャッシュの効果を実現できます。具体的な構成は以下のとおりです。

モジュール.エクスポート = {
  エントリー: {
    アプリ: "./app.js",
    ベンダー: ["react","re​​act-dom", "redux", "react-redux", "react-router-redux"]
  },
  ....
  プラグイン: [
    新しい webpack.optimize.CommonsChunkPlugin({names: ["vendor"]})、
    新しい webpack.optimize.CommonsChunkPlugin({
        名前: 'マニフェスト',
        チャンク: ['ベンダー']
    })
  ]
};

この方法では、業務アプリのコードが変更されても、プロジェクトが依存する基本ライブラリのベンダー チャンクは変更されません。抽出されたマニフェスト チャンクのみが毎回変更されますが、このファイルのサイズは非常に小さく、この方法はベンダーよりも大きなメリットがあります。以下のように表示されます。

アプリコードを変更した後のパッケージコンパイル結果は以下のようになります。ベンダーチャンクハッシュは変更されていないことがわかります。

webpack で CommonsChunkPlugin を設定する際に注意すべき点がいくつかあります。

1. webpack の出力項目を設定する場合、そのfilenamechunkFilenameは chunkhash を使用する必要があります。ハッシュを使用しないでください。そうしないと、上記の構成でも期待される効果が得られません。ハッシュとチャンクハッシュの違いについては、githubの回答を参照してください。

2. 画像やフォントなどの静的リソースを抽出するために使用されるfile-loaderの場合、構成されたハッシュは静的ファイルのコンテンツハッシュ値を表します。パッケージ化およびコンパイルされるたびに webpack によって生成されるハッシュ値ではありません。覚えておいてください。 ! !

3. 抽出された CSS スタイル ファイルには、 file-loaderの hash と同じ意味を持つcontenthashを使用する必要があります。これはチャンクハッシュにすることはできません。そうしないと、スタイル ファイルが抽出されるエントリ チャンクのチャンクハッシュと一致してしまい、キャッシュの目的が達成されません。

CSSキャッシュの実装

Webpack は、上で紹介した contenthash を使用して CSS キャッシュを実装します。hash 属性値は、実際にはextra-text-webpack-pluginによって計算されます。 CSSキャッシュを実装するには、次のようにcontenthashを使用します。

モジュール.エクスポート = {
  ...
  プラグイン: [
     新しいExtractTextPlugin({
	ファイル名: 'static/[name]_[contenthash:7].css',
	無効: false、
	すべてのチャンク: true
     })
  ...
  ]

画像/フォントのキャッシュを実装する

画像やフォントなどの静的リソースの場合、webpack を使用してビルドおよび抽出するときに、実際にはfile-loaderを使用して完了し、対応するファイル ハッシュ値は対応するfile-loaderによって計算されます。では、これらの静的ファイルにはどのようなハッシュ値が使用されるのでしょうか? 実は、それらはhash属性値です。次のコードに示すように:

モジュール.エクスポート = {
 ...
 ルール:
   ...
    {
      テスト: /\.(gif|png|jpe?g)(\?\S*)?$/,
      ローダー: require.resolve('url-loader'),
      オプション:
        制限: 10000、
        名前: path.posix.join('static', '[name]_[hash:7].[ext]')
      }
    },
    フォント:
      テスト: /\.otf|ttf|woff2?|eot(\?\S*)?$/,
      ローダー: require.resolve('url-loader'),
      オプション:
        制限: 10000、
        名前: path.posix.join('static', '[name]_[hash:7].[ext]')
      }
    }
 ]
}

上記では、ハッシュ属性値が使用されていることがわかります。このハッシュは、プロジェクトがビルドされるたびに webpack がビルドするハッシュではありません。これは、ファイルの内容に基づいて file-loader によって計算されます。webpack によってビルドされるハッシュと間違えないでください。

参照する

1. webpackのCommonsChunkPluginを開く正しい方法
2. Webpack ピット充填道路抽出独立ファイル(モジュール)
3. Webpackコード分割スキル
4. ファイル名のハッシュを処理するために webpack を使用していると聞きました。次に、生成したハッシュが正しいかどうかを確認することをお勧めします。
5. チャンクハッシュ
6. 複数のコモンズチャンク
7. Webpackを使用して永続キャッシュを実装する
8. Webpack のハッシュとチャンクアッシュの違い、および js と css のハッシュ フィンガープリント分離ソリューション

これで、webpack で静的リソース キャッシュを実装する方法についての記事は終了です。より関連性の高い webpack 静的リソース キャッシュ コンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • Electron-vueはwebpackを使用して複数ページのエントリファイルをパッケージ化します
  • webpackのモバイル適応ソリューションの概要
  • vue-cli を使用してプロジェクトを作成し、webpack でパッケージ化する方法
  • webpackでHMRを手動で実装するいくつかの方法
  • vue の webpack -v エラー解決の概要

<<:  dubbo での Zookeeper リクエストのタイムアウト問題: mysql8.0.15 に接続する mybatis+spring の構成

>>:  Linux で実行可能ファイルを実行するときに「そのようなファイルまたはディレクトリはありません」というプロンプトが表示される場合の解決策

推薦する

docker を使用して crownblog プロジェクトを Alibaba Cloud にデプロイする方法

フロントエンドプロジェクトのパッケージ化.env.productionを見つけて、自分のIPまたはド...

Vueでaxiosをカプセル化する方法

目次1. インストール1. はじめに3. インターフェースルートアドレス4. 使用例4.1 ダウンロ...

MySQL の null と not null、null と空の値の違いの詳細な説明 ''''

MySQL を長い間使用してきた多くの人は、これら 2 つのフィールド属性の概念をまだよく理解して...

nginx でディレクトリ ホワイトリストと IP ホワイトリストを設定する方法

1. ディレクトリホワイトリストを設定する:指定されたリクエストパスに制限を設定しないでください。た...

Nexus を使用して Docker リポジトリを作成する方法

公式の Docker レジストリを使用して作成されたウェアハウスでは、イメージを削除してもデフォルト...

各グループの最新データを取得するためにMySQLベースのグループを実装する

序文:グループ化関数はグループ内の最初のデータを取得しますが、各グループ内の最新のデータを取得する必...

Vue での weixin-js-sdk の一般的な使用方法の詳細な説明

リンク: https://qydev.weixin.qq.com/wiki/index.php?ti...

非常に実用的なMySQL関数の包括的な概要、詳細な例の分析チュートリアル

目次1. MySQLの関数の説明2. 単行関数の分類3. キャラクター機能4. 数学関数5. 日付と...

Docker ケース分析: MySQL データベース サービスの構築

目次1 設定ディレクトリとデータディレクトリを作成する3 イメージからホストに構成ファイルをコピーす...

el-table のテーブルを最適化するために仮想リストを使用する方法についての簡単な説明

目次序文解決具体的な実装満たすべき前提条件質問序文テーブルをよく使用します。データ量が多い場合は直接...

入力タグの名前と値の違い

type はブラウザでの入力と出力に使用されるコントロールです (たとえば、type="t...

dockerプライベート倉庫の構築と利用の詳細説明

1. リポジトリイメージをダウンロードする docker プルレジストリ 2. プライベートウェアハ...

17 個の JavaScript ワンライナー

目次1. DOMとBOM関連1. 要素にフォーカスがあるかどうかを確認する2. 要素の兄弟ノードをす...

docker のインストールが完了し、bridge-nf-call-iptables が無効であると報告される問題を解決します

Centos マシンで docker のインストールが完了したら、docker info コマンドを...

HTML の iframe と frame の違いを例を使って説明します

プロジェクトで frameset 属性を使用したことがあるかどうかはわかりません。昨年、オンライン ...