ちょっとがんばるWebサイト開発 on Webpack5

# 前書き

静的Webサイトの開発では、HTML/CSS/JavaScriptを記述することでWebページの見た目や振る舞いを定義します。しかし、HTML/CSS/JavaScript（特にHTML/CSS）を愚直に記述しようとすると、コード記述量/保守性/再利用性の観点で不便に感じることも多いと思います。

このシリーズ記事 **「ちょっとがんばるWebサイト開発 on Webpack5」** では、Webpackというツールを利用しながら、保守性/再利用性の高いWebプログラミングができるようにすることを目指します。

:::note info
この記事では **Webpack5** (version5.X.X) を対象としています。
:::

## 本記事のゴール

Webpackによる静的Webサイト開発の全体像を把握することを目指します。

## この記事で解説する内容

- Webpackの概要について説明します
- 静的Webサイトの構成要素について概観します
- Webpackによる静的Webサイト構成の概要および参考資料を示します

## この記事で解説しない内容

- Webpackの詳細については説明しません
- Webpackによる静的Webサイト構成の詳細については説明しません

:::note info
この記事は、Webpackによる静的Webサイト開発に必要な知識技術を整理することを目標に執筆されています。そのため、各種技術に関する詳細な説明は同シリーズ別記事に譲り、当該記事へのエントリポイントを提供するにとどめています。
:::

# 背景知識

## Webpackとは何か

**[Webpack](https://webpack.js.org/)** とは、JavaScriptアプリケーション用の **モジュールバンドラー** です。最も基本的な機能として、1つ以上のJavaScript系ファイルを入力として受け取り、それらをまとめて1つ（または1つ以上）のJavaScriptファイルを出力するという仕事を果たします。Webpackは、代表的なJavaScript系アプリケーションの1つである **Webサイト/アプリケーション** の開発で広く利用されています。

https://webpack.js.org/

Webpackは、原理的にはJavaScript系ファイル用の **モジュールバンドラー** ですが、より一般に各種プログラム・データの **コンパイラ/トランスパイラ** として利用することができます。Webサイト開発においては、HTML/CSS/JavaScript等ファイルを含むプロジェクト全体をWebpackでビルドすることで目的のWebサイト（の構成ファイル群）を生成する、という形で利用することができます。

例えば、HTMLテンプレート言語である **EJS** のソースファイルからHTMLファイルを生成したり、CSS拡張言語である **Sass** からCSSファイルを生成したり、JavaScriptフロントエンドフレームワーク **Vue.js** / **React** / **Angular** からJavaScriptファイルを生成したりすることができます。

Webサイト開発では多種多様なファイルを取り扱うためその管理が煩雑になることも多いですが、Webpackを利用することでこうしたビルド作業を一元管理することができるようになります。

# 動機

このシリーズ記事では、 **Webpackを導入してより効率的なWebサイト開発環境を得る** ことを目指します。
具体的には、Webpack導入前の開発環境として以下のような状況 [BEFORE] を想定し、Webpack導入後に状況 [AFTER] に改善することを目指します。

- **[BEFORE] Webpack導入前の開発環境**

  - コンテンツ（Webページの文書構造定義）
    - 概要：HTML
    - 実装言語：HTML（`*.html` ファイル）

  - スタイル（Webページのデザイン定義）
    - 実装言語：CSS（`*.css` ファイル）

  - スクリプト（Webページの動作定義）
    - 実装言語：JavaScript（`*.js` ファイル）

- **[AFTER] Webpack導入後の開発環境**

  - コンテンツ
    - 実装言語：HTML または HTMLテンプレート言語 **EJS**（`*.ejs` ファイル） または **Vue.js**（`*.vue` ファイル）
    - 特徴1：共通の雛形および異なる内容を含む複数ページ（企業サイトのニュースリリースページ等）を自動的に作成できる
    - 特徴2：カスタムHTML要素を定義することでコンポーネント指向的にページを作成できる

  - スタイル
    - 実装言語：CSS または CSS拡張言語 **Sass**（`*.sass` / `*.scss`）
    - 特徴1：変数/関数/ミックスイン等の便利な構文を使用できる

  - スクリプト
    - 実装言語：JavaScript または JavaScriptフロントエンドフレームワーク **Vue.js**（`*.vue` ファイル）
    - 特徴1：コンテンツ/スタイルと密接な関係で結び付いており、より直感的に操作できる

# 方法

上記目標を達成するために、この記事では **Webpack** およびWebpack関連ツールを導入することを提案します。
[手順概要（前提）](#手順概要前提) にWebpack開発環境構築に必要な準備を、[手順概要](#手順概要) にWebpack開発環境構築の全体像を、[手順詳細（前提）](#手順詳細前提) [手順詳細](#手順詳細) に各ステップの丁寧な説明および参考資料リストをまとめています。

<!-- [手順概要（前提）](#手順概要前提) [手順詳細（前提）](#手順詳細前提) はWebpack開発環境構築の基礎となるため、手を動かす際には十分に理解した上で動作確認を行うことをお勧めします。 -->

なお、便宜上手順概要/詳細のステップに番号を振っていますが、各ステップは Self-contained になるように配慮しています。そのため、必ずしも最初から順に1つずつ読む必要はありませんし、必要箇所のみを参照して頂ければ理解できるようになっています（ただし、最初から順に1つずつ読むことを想定して内容を構成していることにご留意ください）。

*手順概要/詳細のステップの番号は記事公開後に多少変更される可能性があります。*

## 手順概要（前提）

- [0) Webpack](#0-webpack)
  - 0-1) Node.jsの導入
  - 0-2) Webpackの導入

## 手順概要

- [1) コンテンツ/HTML](#1-コンテンツhtml)
  - 1-1) HTMLのコピー＆ペースト / HTML -> HTML
  - 1-2) EJSのコンパイル / EJS -> HTML
  - 1-3) EJSテンプレート＋JSONデータによるHTMLファイルの自動生成 / EJS + JSON -> HTML

- [2) スタイル/CSS](#2-スタイルcss)
  - 2-1) CSSのコピー＆ペースト / CSS -> CSS
  - 2-2) SCSSのコンパイル / SCSS -> CSS

- [3) スクリプト/JavaScript](#3-スクリプトjavascript)
  - 3-1) JavaScriptのコピー＆ペースト / JS -> JS
  - 3-2) Vue.jsのコンパイル / Vue -> JS

- [4) アセット](#4-アセット)
  - 4-1) 画像のコピー
  - 4-2) 画像の最適化
  - 4-3) Favicon画像生成

## 手順詳細（前提）

### 0) Webpack

#### 0-1) Node.jsの導入

**[Node.js](https://nodejs.org/ja/)** はJavaScript実行環境です。Node.jsをインストールすることで、ローカル環境でもJavaScriptプログラムを実行できるようになります。このシリーズ記事では、Node.jsのパッケージを活用してWebサイト開発を進めていきます。

Webpackを含む各種Node.jsパッケージの利用には [Node.js](https://nodejs.org/ja/) が必要です。
インストールが未実施の場合には、以下のリンクからインストールしておいてください。

https://nodejs.org/ja/

#### 0-2) Webpackの導入

**Webpack** とは、JavaScriptアプリケーション用の **モジュールバンドラー** です。Webpackの概要については [上記説明](#webpackとは何か) をご参照ください。

Webpackの利用にはNode.jsパッケージ　`webpack` `webpack-cli` をインストールします。

```shell:ターミナル
npm install --save-dev webpack@5 webpack-cli@5
```

https://qiita.com/Sharkkii/items/5931041087b8205f81fe

## 手順詳細

### 1) コンテンツ/HTML

#### 1-1) HTMLのコピー＆ペースト / HTML -> HTML

一般にプロジェクト開発では、プロジェクトのソースコードを `/src` ディレクトリに、実際に利用/公開するコードを `/dist` ディレクトリに格納して管理することがあります。C/Java言語のようにコンパイルを必要とするプロジェクトに限らず、HTML/CSS/JavaScriptの各種最適化（空白除去等）を行うWebサイトのプロジェクトでも基本的には `/src` `/dist` の分割管理を行います。

この記事では、**Webサイトの開発においては（各種変換処理/最適化の有無によらず） `/src` `/dist` の分割管理を行うことを推奨します**。より詳細には、以下のような思想に基づいて開発環境を構築するのが良いと考えています。

- プロジェクトのソースコードを `/src` ディレクトリに格納する
- 実際に利用/公開するコードを `/dist` ディレクトリに格納する
- `/dist` ディレクトリ配下のファイル群はそのままの形で利用/公開できる（`/dist` ディレクトリ配下のファイル群をアップロードすれば完全なWebサイトとして機能する）

こうした理由から、実装したソースコードと利用/公開するコードが全く同一の場合でも、 `/src` ディレクトリから `/dist` ディレクトリに移動させる（コピー＆ペーストする）ようにします。HTMLファイルのコピー＆ペースト作業はシェルスクリプト等でも実現できますが、統一性の観点からWebpackを利用することにします。

https://qiita.com/Sharkkii/items/033e3d8119bfe60f520e

#### 1-2) EJSのコンパイル / EJS -> HTML

HTML形式には文書構造を宣言するための限られた構文しか用意されていないため、生HTMLのコーディングは非常に面倒です。そのため、文書構造の宣言に一般的なプログラミング言語の各種制御構文（条件分岐/ループ等）を使用したいと考えることがあるかと思います。`<ul>` `<li>` 要素のように、Webページには規則的な要素配列・構造が現れることが珍しくありませんが、その定義にループ構文が使用できれば非常に便利です。

これを実現するための1つのアプローチが **[EJS](https://ejs.co/)** です。EJSとは、JavaScriptプログラムが埋め込まれたHTMLテンプレートを記述するための言語仕様です。EJSを利用することで、JavaScriptの制御構文（if/while等）を使用したHTML文書構造の定義を行うことが可能です。EJSファイルをコンパイルすることで（JavaScriptプログラム実行によって展開された）HTMLファイルを得ることができますが、そのコンパイル作業にWebpackを利用します。

https://qiita.com/Sharkkii/items/9598c75707d2ffa600e1

#### 1-3) EJSテンプレート＋JSONデータによるHTMLファイルの自動生成 / EJS + JSON -> HTML

一般にWebサイトは1つ以上のWebページから構成されていますが、その中には共通の文書構造を有するWebページ集合が存在することがあります。企業サイトのニュースリリースページ集合のように、テキストや画像等のデータは相異なるものの文書構造が全く同一のWebページ群を作成する場合には、共通の文書構造部分（テンプレート）と個別のデータ部分（外部データ）に分離することで開発・保守運用コストを抑えることができると期待されます。

これを実現するために、 **Webpack** + **EJS** + **JSON** を組み合わせて利用します。共通のEJSテンプレートをコンパイルする際に個別のJSONデータを挿入することで、そのデータを反映したページを生成することができます。テンプレートに対する個別データの挿入作業を管理するためにWebpackを利用します。

*詳細記事は現在執筆中です。*

### 2) スタイル/CSS

#### 2-1) CSSのコピー＆ペースト / CSS -> CSS

この記事では、Webサイトの開発においては（各種変換処理/最適化の有無によらず） `/src` `/dist` の分割管理を行うことを推奨します。それに伴って、実装したソースコードと利用/公開するコードが全く同一の場合でも、 `/src` ディレクトリから `/dist` ディレクトリに移動させる（コピー＆ペーストする）ようにします。CSSファイルのコピー＆ペースト作業はシェルスクリプト等でも実現できますが、統一性の観点からWebpackを利用することにします。

https://qiita.com/Sharkkii/items/7903c117dfa99042239e

#### 2-2) SCSSのコンパイル / SCSS -> CSS

CSS言語にはスタイル定義のための限られた構文しか用意されていないため、生CSSのコーディングは非常に面倒です。そのため、スタイル定義に変数/関数/ミックスイン等の便利な道具を使用したいと考えることがあるかと思います。同じようなスタイルを別の場所でも利用したいと思うこともしばしばありますが、そうした場合にスタイル定義ブロックを再利用する仕組みがあれば非常に便利です。

これを実現するための1つのアプローチが **[Sass](https://sass-lang.com/)** です。Sassとは、CSSの拡張言語であって、変数/関数/ミックスイン等の糖衣構文を提供するものです。Sassが提供する2種類の記法 **SASS**/**SCSS** のうち、SCSS記法が特に好まれているという印象です。SCSSファイルをコンパイルすることで生のCSSファイルを得ることができますが、そのコンパイル作業にWebpackを利用します。

https://qiita.com/Sharkkii/items/18a82048a16c291b248a

### 3) スクリプト/JavaScript

#### 3-1) JavaScriptのコピー＆ペースト / JS -> JS

この記事では、Webサイトの開発においては（各種変換処理/最適化の有無によらず） `/src` `/dist` の分割管理を行うことを推奨します。それに伴って、実装したソースコードと利用/公開するコードが全く同一の場合でも、 `/src` ディレクトリから `/dist` ディレクトリに移動させる（コピー＆ペーストする）ようにします。JavaScriptファイルのコピー＆ペースト作業はシェルスクリプト等でも実現できますが、統一性の観点からWebpackを利用することにします。

https://qiita.com/Sharkkii/items/130a68c6f8f7cbe0b224

#### 3-2) Vue.jsのコンパイル / Vue -> JS

Webサイトの開発では「テンプレート（HTML）」「スタイル（CSS）」「スクリプト（JavaScript）」という分類法に従って管理するのが基本です。このとき、テンプレート/スタイル/スクリプトが互いに独立になるようにコーディングすることで、保守性等の観点においてメリットがあるとされています。

ただし、テンプレート/スタイル/スクリプトが互いに強く依存する場合には **コンポーネント指向的** なアプローチをとるのが良い場合もあります。コンポーネント指向的なアプローチとは、内部の相互依存性が高い要素集合を1つの **コンポーネント（部品）** と考え、コンポーネントを組み立てることでWebページを構成するというものです。コンポーネント指向的な設計思想はPython/Java/C#等多数のプログラミング言語でも見ることができます[^1]。

コンポーネント指向的設計を実現するための1つのアプローチが **[Vue.js](https://ja.vuejs.org/)** / **[React](https://ja.reactjs.org/)** / **[Angular](https://angular.jp/)** 等のJavaScriptフロントエンドフレームワークです。こうしたフロントエンドフレームワークでは、テンプレート/スタイル/スクリプトをまとめてコンポーネント単位で管理する仕組みが整えられています。フロントエンドフレームワークのソースファイルをコンパイルすることで生のJavaScriptファイルを得ることができますが、そのコンパイル作業にWebpackを利用します。

このシリーズ記事ではVue.jsフレームワークのみを取り扱います。それ以外のフロントエンドフレームワークについては別記事を参考にしてください。

*詳細記事は現在執筆中です。*

### 4) アセット

#### 4-1) 画像アセットのコピー＆ペースト

この記事では、Webサイトの開発においては（各種変換処理/最適化の有無によらず） `/src` `/dist` の分割管理を行うことを推奨します。それに伴って、原画像アセットと利用/公開する画像アセットが全く同一の場合でも、 `/src` ディレクトリから `/dist` ディレクトリに移動させる（コピー＆ペーストする）ようにします。画像アセットのコピー＆ペースト作業はシェルスクリプト等でも実現できますが、統一性の観点からWebpackを利用することにします。

https://qiita.com/Sharkkii/items/675e670b7841481532e3

#### 4-2) 画像アセットの最適化

Webサイトは不特定多数のユーザに閲覧してもらうものであるため、UI/UXを意識することは非常に重要です。UXを左右する要因としてはWebサイトの表示速度や反応速度等が挙げられますが、こうした指標の一部はWebサイト全体のリソースのサイズと関係があります。Webサイトにおいて最もサイズの大きなリソースの1つは画像アセットであるため、画像アセットを最適化することはWebサイトのパフォーマンスを改善することに大きく貢献すると考えられます。

画像アセットの最適化処理には自動実行できる共通プロセス（画一的なサイズ圧縮等）と手動で対応すべき個別プロセス（クロップ/リサイズ処理等）があると思いますが、共通プロセスに関してはWebpackを利用します。

*詳細記事は現在執筆中です。*

#### 4-3) Favicon設定

**Favicon** とは、Webサイトのアイコンで、Webブラウザのページタブやブックマーク等で使用されています。Faviconを設定することでWebサイトのイメージを提示したり、多数のページタブ/ブックマークの中で自身のWebサイトの項目を目立たせたりすることができます。

しかし、Faviconの設定は非常に煩雑です。Webサイトを閲覧するデバイスやWebブラウザ等の環境によってFaviconの設定方法が異なるため、想定環境すべてに対応するためには多数の設定を行う必要があります。Favicon設定には主に (1)Favicon画像準備 および (2)Favicon画像読み込み設定記述 がありますが、いずれも手動で管理するのは非常に面倒です。

Favicon設定を自動化するためのアプローチとして、ここではWebpackを利用する方法を提案しています。Favicon画像生成サービスを利用することも考えられますが、それよりも自動化の度合いが高く、かつ統一性の観点でも優れていると考えられます。

https://qiita.com/Sharkkii/items/7a0d3316beaa223607a7

# 後書き

**サンプルコード**
**[/website/website-dev-on-webpack5/ @Sharkkii](https://github.com/Sharkkii/tech-blog-code/tree/develop/website/website-dev-on-webpack5)**

<!--
# 参考文献

- [Node.js公式サイト](https://nodejs.org/ja/)
- [Webpack公式サイト](https://webpack.js.org/)
- [EJS公式サイト](https://ejs.co/)
- [Sass公式サイト](https://sass-lang.com/)
- [Vue.js公式サイト](https://jp.vuejs.org/)
- [React公式サイト](https://ja.reactjs.org/)
- [Angular公式サイト](https://angular.jp/)
-->

[^1]: 厳密にはPython等の言語は **オブジェクト指向** 的な思想を持っており、コンポーネント指向とは微妙に異なる部分があります。オブジェクト指向とコンポーネント指向の差異については例えば [こちらの記事](https://qiita.com/wolfmagnate/items/f9fc2ac39ef74d9d8fbd) に詳しいです。