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

推薦する

nginx で同時接続リクエストの数を制限する方法

導入同時接続数を制限するモジュールは http_limit_conn_module です。アドレス:...

jQueryはショッピングカート機能を実装します

この記事の例では、ショッピングカート機能を実装するためのjQueryの具体的なコードを参考までに共有...

Webフロントエンドインターフェースの設計に必須のスキル

[必須] ユーザーインターフェースPhotoShop/花火デザインアーティストと協力して、スケッチを...

シンプルな CSS テキストアニメーション効果

成果を達成する 実装コードhtml <div id=コンテナ> いらっしゃいませ <...

Vue+elementUI コンポーネントは、折りたたみ可能な動的レンダリングのマルチレベル サイドバー ナビゲーションを再帰的に実装します。

かなり前に実装された機能ですが、クリックすると選択したメニュー項目の背景色が白くなることに気付きまし...

Windows で MySQL のルート パスワードをリセットする方法

今日、WordPress がデータベースに接続できないことがわかりました。ウィンドウ サーバーにログ...

Linuxコマンド履歴の調整方法の詳細な説明

Linux システムの bash history コマンドは、以前に実行したコマンドを記憶し、再入力...

MySQL データ挿入効率の比較

データを挿入するとき、以前オフィス システムに取り組んでいたときにはデータベースのパフォーマンスにつ...

MySQL テーブルの読み取り、書き込み、インデックス作成、その他の操作の SQL ステートメントの効率最適化の問題を分析します。

前回は、Explain 実行プランの表示、インデックスの分析など、MySQL での SQL クエリの...

MySQLデータベースのbinlogクリーンアップコマンドの詳細な説明

概要今日は主に、MySQL データベースから binlog ログを正しく削除する方法を紹介します。ロ...

格納可能なセカンダリメニューを実装するための JavaScript

JavaScriptで格納可能なセカンダリメニューを実装するための具体的なコードは参考までに。具体...

MySQLクエリデータを時間別に表示します。データがない場合は0を入力してください。

需要背景統計インターフェースでは、フロントエンドは 2 つの配列を返す必要があります。1 つは 0 ...

SQL実行ステップの詳細な分析

SQL実行ステップの詳細な分析まず、ステートメントが実行される順序を見てみましょう。 (8)選択する...

空のパスがページのパフォーマンスに与える影響に対する解決策

数日前、Google Reader で Yu Bo さんが共有した投稿「空のパスがページのパフォーマ...

JSはタイムラインの自動再生を実現する

最近、次のような効果を実装しました。再生ボタンをクリックするとタイムラインの再生が開始され、一時停止...