Webpackの出力ファイル名にハッシュ値(digest)を付ける方法を解説!

webpack-hashed-filename

複数のJavaScriptファイルをまとめるために、Webpackというツールがよく用いられます。まとめたファイルは単一のJavaScriptファイルとして出力されますが、今回はそのファイル名にdigest(ハッシュ値)を付与してキャッシュの問題を解決する方法を説明していきます。

Webpackで単一のJavaScriptファイルを出力する

まず、Webpackの基本的な使用方法として単一のjsファイルを吐き出すところからやっていきます。Webpackをまだ導入していない場合は以下のコマンドでインストールができます。

$ npm install --save-dev webpack webpack-cli

Webpackのバージョンは4.29.6、webpack-cliのバージョンは3.3.0を使用しています。

複数のファイルをまとめてひとつのjsファイルを出力するためには、webpack.config.jsに以下のように記述します。webpack.config.jsはWebpackの設定ファイルです。

const path = require('path');

module.exports = {
  entry: [
    './src/js/sample.js',
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/app.js'
  }
}

記述した内容を見ていきましょう。entryにはまとめ上げるファイルのリストを指定しています。配列ではなく単一の文字列を与えても良いです。outputには出力ファイルに関する設定を記述します。pathとfilenameがそれぞれ出力するファイルのパスとファイル名を表しています。

実際にentryで指定したファイルをapp.jsにまとめてみましょう。今回は以下のようなpackage.jsonを使用しています。

{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --mode development"
  },
  "author": "ermi",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0"
  }
}

package.jsonのscript内でbuildコマンドにwebpack –mode developmentを割り当てています。そのため、webpackを実行するためには、僕の環境だと以下のコマンドを実行すれば良いことになります。

$ npm run build

ここまでで、単一のJavaScriptファイルapp.jsが手に入りました。実際にhtmlファイル内で使用する場合には

<script type="text/javascript" src="js/app.js"></script>

のような行をhtmlファイル内に追加するだけで読み込むことができます。

出力ファイル名にハッシュ値を追加する

このままでは、実用的にはひとつ問題があります。それは、出力ファイル名が常にapp.jsであるためにコードに変更を加えてもブラウザがキャッシュしてしまうという問題です。そこで、出力ファイル名にハッシュ値を追加してapp-{hash}.jsのようなファイル名にすることを考えます。ハッシュ値は生成するごとに変更されていくので、ブラウザのキャッシュによる問題は起こらなくなります。

Webpackでこれを行うのは非常に簡単です。webpack.config.jsを以下のように書き換えます。ここで、変更したのはoutputのfilenameの値のみです。

const path = require('path');

module.exports = {
  entry: [
    './src/js/sample.js',
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/app-[hash].js'
  }
}

ここから同じようにビルドを行うとapp-9a969cd6c1f3f9f51ce8.jsのようなハッシュ値付きのファイルが出力されるはずです。

ファイル名にハッシュ値を付けたとして、そのファイルをhtmlファイルから読み込むにはどうすれば良いでしょうか。毎回jsのファイル名が変わってしまうと、ファイル名を直接記述して読み込むことができなくなってしまいます。

そこで、htmlファイルもWebpackで生成することにします。新しく付けたハッシュ値付きのjsファイル名を毎回html内にも記載して出力してくれれば良いわけです。

HTML Webpack PluginでHTMLファイルを生成する

Webpackでhtmlファイルも同時に生成するためには、HTML Webpack Pluginというプラグインを使う必要があります。以下のコマンドでインストール可能です。

$ npm install --save-dev html-webpack-plugin

インストールが終わったら、webpack.config.jsを以下のように変更します。ここでは、pluginsにHtmlWebpackPluginのオブジェクトを追加しています。

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: [
    './src/js/sample.js',
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/app-[hash].js'
  },
  plugins: [
    new HtmlWebpackPlugin()
  ]
}

今までと同様にビルドを行うとjsのファイルと共にhtmlのファイルも出力されます。htmlファイルはdistディレクトリ内に作成されますが、これはoutputのpathにdistが指定されているためです。ファイルの内容は以下のようになっています。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack App</title>
  </head>
  <body>
  <script type="text/javascript" src="js/app-9a969cd6c1f3f9f51ce8.js"></script></body>
</html>

一から新しいhtmlファイルを生成するのではなく、既存のhtmlファイルにscriptタグだけ追加してほしいこともあると思います。その場合は、webpack.config.jsを以下のように修正します。

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: [
    './src/js/sample.js',
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/app-[hash].js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
}

templateにhtmlのファイルを指定するように変更しています。これにより、指定したhtmlファイルに対して「Webpackによって生成したjsファイルを読み込むようなscriptタグ」が追加されたhtmlファイルが新たに出力されるようになります。出力される場所は今までと変わりません。


この記事では、Webpackで出力するファイルにハッシュ値を含めて同時にそのファイルを読み込むようなHTMLを出力する方法を紹介しました。