Webpackとは何か?わかりやすく解説

Web開発でよく使われるWebpack。
当たり前のように自分のプロジェクトでも使っているけど、改めてWebpackとはなにか?と聞かれるとうまく答えられない、ということはないですか?

そんな方に向けて、この記事ではWebpackについて超わかりやすく解説します。
この記事を読み終わる頃には、Webpackとはなにか、なぜ必要なのかが説明できるようになるはずです。
ぜひ最後まで読んでみてください!

Web開発、昔の話

Webpackとは何かをいきなり説明しても、それがなぜ必要なのか理解するのが難しいと思います。
そこで少し遠回りですが、まずはWebpackが登場する前のWeb開発の話から始めさせてください。

ホームページようなブラウザで動くWebアプリを作るにはHTMLとcss、そしてJavaScriptが必要です。
その中で今回のテーマに繋がるのがJavaScriptです。

その昔はJavaScriptの役割はシンプルで、Webサイトに動きを付けるときに使われるくらいでした。
場合によっては1つのファイルに単純にコードをべた書きすれば、それで用が足りたかもしれません。

昔のWebサイトの例

しかし時は進み、現在ではショッピングサイトやSpreadSheetのような大規模なWebアプリが作られるまで進歩しました。
そのため、一つのプロジェクトで使うJavaScriptのコードは飛躍的に多くなりました。

プログラムが大きくなると、モジュール化という概念が重要になります。
モジュール化とは、プログラムを小さな部品(モジュール)に分割することです。
適切にモジュール化することで、それぞれの部品が独立して再利用可能になるため、保守しやすいプログラムを作ることができます。

何百、何千ものコードを一か所の関数やファイルに書いていたら、読むのも変更するのも大変なことになるのは容易に想像つくと思います。

モジュール化をするには、コードを適切なまとまり(機能ごとなど)に分けて、それらを何らかの形で他からも再利用できる形にします。

しかし、JavaScriptはもともと単純なコードで動く想定で作られた言語なので、昔はモジュールという仕組みをサポートしていませんでした。
そのため、JavaScriptでモジュールを扱いたいとすると、そのための外部の仕組み(ライブラリやツールなど)を使う必要がありました。
例えば、CommonJS、Asynchronous Module Definition(AMD)、Browserifyなどの技術は、JavaScriptでモジュールを扱うことを目的としています。

しかし、2015年に登場したES2015(ES6)にて、JavaScriptは言語として公式にモジュールをサポートし始めました。

ES Modulesとも呼ばれるその仕組みは、importとexportというキーワードを使うことで、コードをモジュールとしてエクスポートして、使用したい箇所でインポートできます。
これでJavaScriptでもネイティブにモジュールが扱えて一件落着と思いきや、一つ問題がありました。
それは、ブラウザがモジュールの仕組みに対応できていなかったということです。

例えば、Chromブラウザがimport/export構文に対応したのは、2017年12月に出たバージョン61からです。
つまり、言語側でモジュール化の仕組みはあっても、肝心なブラウザでそれを表示・実行できなかったのです。

また、モジュールの対応状況についてはブラウザごとにばらつきがありました。
ユーザーがの使用環境がさまざまである以上、モジュール化したコードを確実に動作させようとするのは難しいという問題がありました。

そんな時に救世主のように登場したのが、Webpackです。(やっと登場です)

Webpack、The モジュールバンドラー

Webpackはモジュールバンドラーと呼ばれるツールの一つです。
モジュールバンドラーとは、その名の通り、複数のモジュールをバンドル(bundle: 一つまとめるの意味)してくれるツールのことです。

Webpackは、複数のファイルに散らばったモジュール達をまとめて、一つのjsファイルに出力してくれます。
そのまとめる過程で、Webpackはコードのモジュール化の依存関係(どのコードがどのモジュールをimport/exportしているか)を解決し、モジュール化を取り除いたコードを作成します。

その結果、出力されたjsファイルではモジュール化部分のコード(import、export)がありません。
モジュール化がないのであれば、ブラウザがモジュール化に対応しているかどうかは関係なく、どの環境でもコードが実行できます。
このように、Webpackはモジュール化したJavaSciprtをどんなブラウザでも実行したい、という思いを実現させてくれるツールになっています。

それだけじゃない、Webpack

コードのモジュール化をサポートするWebpackですが、先述の通り、ブラウザがモジュールに対応していなかったのは過去の話です。

現在では主要なブラウザはどれもモジュールに対応(import/exportが利用できる)しています。

モジュール化に使うimportの対応状況。すべての環境で対応している。

つまり、わざわざWebpackを使ってimport/exportを取り除いたコードを作成しなくても実行することができます。
それでもなおWebpackを使う理由はなんでしょうか?
その理由は、Webpackには上記以外にもさまざまなメリットがあるからです。

一つは「バンドラー」という特徴がメリットになります。
バンドラーは先述した通り、複数のファイルを一つのファイルにまとめます。
ブラウザではこの出力されたファイルを取得することで、複数のファイルのコードをまとめて取得できます。
本来ブラウザが複数回リクエストを送ってファイルを取得していたところを、たった一回のリクエストで取得できるようになるのです。
結果的に、通信量が減りアプリの表示をより速くすることができます。

また、Webpackはバンドルする際にコード内の不要なスペースやコメントなどを削除してファイルサイズを小さくしています。
この仕様もアプリのパフォーマンス向上に寄与しています。

もう一つのメリットとして、Webpackの拡張機能が挙げられます。
WebpackはJavaScriptファイルだけでなく、cssや画像ファイルのようなWeb開発で必要なその他のリソースについても最適化する方法が用意されています。
最適化だけでなく、TypeScriptのトランスパイルやsassをコンパイルのような、コードの実行に必要な作業も一緒に行うことも可能です。
これらはloaderと呼ばれるプラグインをインストールすることで実現できます。

拡張機能についてはいくつか取り上げてみてみましょう。

cssの最適化

Webpackなどのバンドラーを使わない場合、cssはJavaScriptとは個別にHTMLで読み込む必要があります。
これはcssが増えたとき、その分cssの読み込みが必要になるので、管理が煩雑になります。

Webpackを使うとこの問題も解決できます。

Webpackではバンドル後のjsファイルの中にcssもまとめて出力するよう設定できます。
そのため、ブラウザではこのjsファイルを読み込むだけでcssまで取得でき、通信量を減らすことができます。
また、JavaScriptと同様に、CSSも不要なスペースやコメントを取り除いたり、変数を短縮したりしてサイズを小さくしてくれます。

TypeScriptのトランスパイル

最近のWeb開発では、JavaScriptの代わりにTypeScriptで開発するというケースも多いでしょう。
TypeScriptは静的な型付けができるのでより堅牢なコードを書くことができます。

しかしブラウザで最終的にコードを実行するときはJavaScriptである必要があるので、最終的にコードをTypeScriptからJavaScriptに変換(トランスパイル)する必要があります。

トランスパイルは、TypeScriptをインストールして、その中に含まれるtsc(TypeScript Compilier)というツール使って実行できます。
Webpackを使うと、このトランスパイルもバンドル時に一緒に実行してくれるよう設定できます。

つまり、Webpackの実行をするだけで、インプットはTypeScriptですが、アウトプットはバンドルしたjsファイルとし出力してくれます。
このように、コード実行に必要な作業を一緒に行ってくれるのは開発者にとってメリットになります。

画像の最適化

画像はサイズの大きいファイルのため、適切に最適化して、快適にWeb表示できるようにする工夫が大切です。
例えば、次のような方法があります。

画像圧縮・・・画像を圧縮して、品質を下げずに画像サイズを小さくする。これは画像圧縮ソフトやオンラインサービスなどを利用するなどの方法があります。

遅延読み込み・・・必要なタイミングで画像を取得するようにすることで、ブラウザの表示を高速にする。これはライブラリを使ってコード実装するなどで実現ができます。

このように、画像の最適化方法はいくつかあり、何をどう組み合わせるのが良いか考えながら実行するのは大変な一面もあります。

Webpackは、先に挙げた方法を含め、いくつもの最適化案を統合的に管理して、自動的に最適化を行ってくれます。
これにより、開発者はただWebpackを実行するだけで画像を最適化することができます。

実際にWebpackを使ってみよう!

Webpackの役割が分かったところで、今度は実際に使ってみてさらに理解を深めていきましょう。

Webpackはコマンドラインで操作するツールで、対象のプロジェクトごとにnpmを使ってインストールします。
npmとは、パッケージ(モジュールやライブラリ)のインストールや管理、依存関係の解決を行うためのツールです。
Webpackはバンドル時にコードの依存関係も見ているので、npmが必須となります。

Webpackを使わない状態のプロジェクト

前置きはこれくらいで、今回サンプルで使用するプロジェクトを見ておきましょう。
まずはWebpackを導入していない状態です。

<div class="hcb_wrap"><pre class="prism undefined-numbers lang-bash" data-lang="Bash"><code>simple-web-project/
|---index.html(トップページ)
|
|---assets
|      script.js(一つ目のjs)
|      script2.js(二つ目のjs)
|      styles.css(トップページのcss)
|
|---images
       logo.png(ロゴ)</code></pre></div>

このプロジェクトを表示すると、次のように簡単な画面の表示と、JavaScriptによるalertが2回表示されます。

OKを押すと、2個目のalertが表示されます。

コードの中身も簡単に見ておきましょう。

index.htmlはこのようにトップページのHTMLを記載しています。
ここでは使用するcssとJavaScriptも読み込んでいます。

<!DOCTYPE html>
<html>
<head>
    <title>Simple Web Project</title>
    <link rel="stylesheet" type="text/css" href="assets/styles.css">
</head>
<body>
    <h1>Hello, World!</h1>
    <img src="images/logo.png" alt="Logo">
    <script type="module" src="assets/script.js"></script>
</body>
</html>

cssには文字の色やフォントを変更する簡単な装飾があります。

body {
  font-family: Arial, sans-serif;
  background-color: white;
}
h1 {
  color: blue;
}

JavaScriptは分かりやすい処理としてalertでメッセージを表示しています。
また、もう一つのjsファイルであるscript.2.jsからモジュール化された関数をインポートして実行しています。

import { Greet } from './script2.js';
alert('Hello from script.js!');
Greet();

script2.jsは以下のようにalertを出力する関数をモジュールとしてエクスポートしています。

export function Greet() {
    alert('Hello from script2.js!');
}

このように、モジュールのインポート/エクスポートを伴うコードに対してWebpackを使っていきます。
先述したように、現在はJavaScriptは言語としてモジュールをサポートしているので、Webpackを入れていない状態でも正常にアプリが表示できます。

補足ですが、モジュールを使ったJavaScriptを読み込む際には、HTMLのスクリプトタグにtype=”module”という属性を指定しないと動かないので注意してください。

<script type="module" src="assets/script.js"></script>

Webpackを導入!

それでは先ほどのプロジェクトにWebpackを入れていきます。

まずはWebpackをインストールするためにnpmを用意します。
npmはNode.jsの一部として提供されいてるツールなので、Node.jsをインストールすればnpmが使えるようになります。
公式サイトからNode.jsをインストールします。

次に、コマンドラインからプロジェクトのルートフォルダに移動し、以下のコマンドを実行してプロジェクト内にWebpackをインストールします。

npm install webpack webpack-cli --save-dev

このコマンドで、WebpackとWebpackのコマンドラインツール(webpack-cli)がプロジェクトに追加されます。
下記コマンドを実行して、webpackがインストールされていることを確認できます。

npx webpack --version

Webpackがインストールされると、プロジェクト内にnode_modulesというフォルダが作成され、Webpack関連のファイルや依存パッケージが格納されます。

simple-web-project/
|---index.html(トップページ)
|---assets
|      script.js(一つ目のjs)
|      script2.js(二つ目のjs)
|      styles.css(トップページのcss)
|---images
|      logo.png(ロゴ画像)
|---node_modules
|      多数のファイル…
|---package-lock.json(パッケージ管理)
|---package.json(パッケージ管理)

また、npmでパッケージの管理に使われるpackage.jsonも作成され、中を見るとインストールしたWebpackのバージョンが記載されています。

{
  "devDependencies": {
    "webpack": "^5.88.2",
    "webpack-cli": "^5.1.4"
  }
}

Webpackを実行するためにもう一つ必要なのが、設定ファイルの作成です。
Webpackが読み込むファイルのエントリ、出力ファイル名、出力先などの情報をこのファイルで指定します。
プロジェクトにwebpack.config.jsという名前のファイルを作成して、以下の内容を記載します。

const path = require('path');
module.exports = {
  entry: './assets/script.js', // エントリーポイント
  output: {
    filename: 'bundle.js', // バンドル後のファイル名
    path: path.resolve(__dirname, 'dist') // 出力ディレクトリ
  }
};

このように、jsファイルの起点となるエントリーファイルを指定します。
今回、エントリーはscript.jsを指定します。script.jsがメインでこの中からscript2.jsを利用しているためです。
バンドル後のファイル名は任意で、今回はbundle.jsとしました。

これで準備ができたので、下記のコマンドでWebpackを実行します。

npx webpack

実行後、webpack.config.jsで指定した出力ディレクトリにbundle.jsというファイルが作成されます。
これがscript.jsとscript2.jsをバンドル(結合)したファイルになります。

simple-web-project/
|---index.html(トップページ)
|---assets
|      script.js(一つ目のjs)
|      script2.js(二つ目のjs)
|      styles.css(トップページのcss)
|---dist
|      bundle.js(バンドルしたjs)
|---images
|      logo.png(ロゴ画像)
|---node_modules
|      多数のファイル…
|---package-lock.json(パッケージ情報)
|---package.json(パッケージ情報)
|---webpack.config.js(webpackの設定ファイル)

出力されたbundle.jsを利用するため、HTMLを修正してscriptタグのsrcにbundle.jsを指定します。
バンドル後のファイルはモジュール部分は取り除かれているので、モジュールを表示する場合に必要なtype=”module”は削除して大丈夫です。

<!DOCTYPE html>
<html>
<head>
    <title>My Project</title>
    <link rel="stylesheet" type="text/css" href="assets/styles.css">
</head>
<body>
    <h1>Hello, World!</h1>
    <img src="images/logo.png" alt="Logo">
    <script src="dist/bundle.js"></script>
</body>
</html>

ブラウザを読み込むと、期待通り実行されました。

ついでに出力されたbundle.jsの中身を見てみましょう。

このように二つのjsファイルが結合されていることが分かります。
import/exportキーワードは取り除かれており、モジュールの依存関係が解決されていることも分かりますね。

(()=>{"use strict";alert("Hello from script.js!"),alert("Hello from script2.js!")})();

終わり

以上でWebpackの超基本的な動きを確認しました。

Webpackの拡張機能であるloaderについては、また勉強し終わったら追記しようと思います。

この記事では、Webpackとは何か?なぜ必要なのか?を解説しました。

ありがとうございました(‘ω’)ノ

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です