Table of Contents

tips_javascript

Webpackを使用してhtmlの共通部分をテンプレート化

WordPressやコンポーネントの概念があるReactなどのように、htmlでもヘッダーやフッターなど共通部分をテンプレート化して効率的にコーディングをすることが可能です。

実現したいこと

  • ヘッダーやフッターなどの共通部分をテンプレート化する
  • WordPressやReactなどを使用せずHTMLのみでコーディング

事前準備

npmパッケージのインストール

Webpackのプラグイン html-webpack-pluginhtml-loader をインストールします。

shell
npm i --save-dev html-webpack-plugin html-loader

プラグインの基本的な使用方法の説明は省略します。

サンプルサイトの構成

例としてトップページと下層ページの2ページのサイトを作成します。JavaScriptのファイルは common.jsindex.js の2種作成し、 index.js はトップページでのみ読み込むようにします。

htmlの作成

テンプレートの header.html を作成します。単純に共通化したい部分のhtmlを抜き出しただけのファイルです。 src/template/ に保存します。

header.html
<header>
  <nav>
    <ul>
      <li><a href="./index.html">Home</a></li>
      <li><a href="./page.html">Page A</a></li>
    </ul>
  </nav>
</header>

テンプレートを読み込む側の index.htmlpage.html を作成します。テンプレートのhtmlを読み込むには html-loader を使用します。テンプレートを読み込みたい場所に <%= require('html-loader!ここに読み込みたいhtmlを記述') %> と記述します。JavaScriptファイルの読み込みは、Webpackのプラグインを使用してbuild後に出力されるhtmlに記述されるようにするため、ここでは記述しません。

page.html<title></title><h1></h1> を変えるだけです。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Home</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

</head>
<body>
<%= require('html-loader!./template/header.html') %>

<main>
  <h1>This page is Home</h1>
</main>

</body>
</html>

JavaScriptファイルの作成

src/js/common.jsindex.js も作成します。ファイルの中身は何でも構いません。サンプルでは意図した通りに読み込まれるかを確認するため、以下のようにしています。

common.js
console.log('index.htmlとpage.htmlの両方で読み込まれる');
index.js
console.log('index.htmlでのみ読み込まれる');

webpack configの設定

html-webpack-plugin を使用して、build後にdistフォルダにhtmlファイルが出力されるように設定します。index.htmlpage.html の2ページ分を記述します。

pluginsnew HtmlWebpackPlugin() と記述するだけでデフォルトのindex.htmlファイルが出力されますが、プラグインに用意されているオプションでカスタマイズしていきます。

template には先ほど作成したhtmlファイル(コーディング時に編集するファイル)を記述します。 filename は記述しない場合デフォルトの index.html になるため、 index.html 以外のページは必ず記述するようにします。

webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    common: './src/js/common.js',
    index: './src/js/index.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new HtmlWebpackPlugin({
      template: './src/page.html',
      filename: 'page.html'
    })
  ]
}

次に index.js (index.min.js)index.html でのみ読み込まれるようにします。

指定したchunkのみを含める chunks: ['含めるentryの名前を記述'] か 指定したchunkを除外する excludeChunks: ['除外するentryの名前を記述'] のどちらかをオプションに記述します。

サンプルサイトでは以下のように、page.html ではcommon.js (common.min.js) のみを読み込まれるようにします。

webpack.config.js
new HtmlWebpackPlugin({
  template: './src/page.html',
  filename: 'page.html',
  chunks: ['common']
})

ここまでで npm run build を実行すると dist フォルダにJavaScriptを読み込む <script> タグを含んだhtmlファイルが生成されます。

html-webpack-pluginのその他のオプション

ページタイトルをwebpackのconfigで管理する

webpackのconfigで title オプションを使用して、ページタイトルを記述します。例えば index.html のページタイトルを「Home | サイト名」にする場合は以下のように記述します。

webpack.config.js
new HtmlWebpackPlugin({
  title: 'Home | サイト名',
  template: './src/index.html'
}),

キャッシュ対策

build後のhtmlで読み込まれるJavaScriptファイルにユニークなhashを付与することができます。オプションの hashtrue にするだけです。

webpack.config.js
new HtmlWebpackPlugin({
  title: 'Home | サイト名',
  template: './src/index.html',
  hash: true
}),

JavaScriptファイルの読み込む位置を指定する

inject オプションを使用することで、build後のhtmlでJavaScriptファイルを読み込む <script> タグの位置を変更できます。指定できるのは true || 'head' || 'body' || false の4つで、それぞれ以下のようになります。

説明
true body終了タグの直前(bodyを指定した場合と同じ)
head head終了タグの直前
body body終了タグの直前(trueを指定した場合と同じ)
false <script> タグの記述なし

デモ・ソース

Source
「Webpackを使用してhtmlの共通部分をテンプレート化」のデモ

最後に

記事内で作成したサンプルサイトのように、テンプレートのhtmlを読み込む側と異なるディレクトリに設置する場合は、画像やリンクのパスの記述に注意が必要です。

参照