1. ホーム
  2. コース一覧
  3. Node.js環境構築コース
  4. Webpackを使ってJavaScriptモジュールを管理しよう

Node.js環境構築コース3/10

Webpackを使ってJavaScriptモジュールを管理しよう

ここではwebpackについて詳しく学んでいきます。

Webpackとは?

webpackとは複数のJavaScriptファイルをまとめる高機能なモジュールバンドラーです。モジュールとは一連のファイル群のことで、webpackではCSSや画像もまとめられるため、それらもモジュールと呼びます。バンドル(バンドラー)とは「まとめられたファイル」のことです。

webpackを利用することで、画像の圧縮やパフォーマンスの最適化を行うことができ、様々なケースに応じたフロントエンドの開発環境を構築することができます。

初期設定

webpackをインストールするにあたりnpmを使用する必要があります。

▶参考リンク:npmの使い方

ディレクトリを新たに作成し初期化を行うには以下のコマンドを実行します。

# ディレクトリ作成
mkdir envader-sample
# ディレクトリ移動
cd envader-sample
# 初期化
npm init -y

インストール

作成したディレクトリにwebpackをインストールします。

npm install --save-dev webpack webpack-cli

package.jsonの”devDependencies”が以下のようになっていることを確認してください。

"devDependencies": {
    "webpack": "^5.XX.X",
    "webpack-cli": "^4.X.X"
  }

webpack.config.jsの設定

ここからバンドルを行うために複数のファイルを用意してあげましょう。 以下のようにディレクトリ、ファイルを作成していきます。

envader-sample
├── dist
│   ├── bundle.js
│   └── index.html
├── package-lock.json
├── package.json
├── src
│   ├─ index.js
│   └─ modules
│    └─helloEnvader.js
└── webpack.config.js

「envader-sample」直下に「dist」ディレクトリを作成します。

mkdir dist

「dist」ディレクトリ内に移動して「bundle.js」ファイルと、「index.html」ファイルを作成してください。

# ディレクトリ移動
cd dist
# ファイル作成
touch bundle.js
touch index.html

同様の手順で「envader-sample」直下に「src」ディレクトリを作成します。 「src」ディレクトリ内に「modules」ディレクトリと「index.js」ファイルを作成してください。 「modules」ディレクトリ内に「helloEnvader.js」ファイルを作成します。

最後に「envader-sample」直下に「webpack.config.js」ファイルを作成すれば、ファイルの用意完了です。

「webpack.config.js」の中身に以下の設定を書き込んでください。

const path = require('path');

module.exports = {
  mode: 'development',
  entry: `./src/index.js`,
  output: {
    filename: "bundle.js",
    path: path.join(__dirname, 'dist')
  }
};

modeには三つのいずれかを設定することができます。「development・production・none」のいずれかです。

entryではエントリーポイント(バンドルの構築を開始する場所)を設定でき、これはどこのファイルを読み込むかという設定を行います。output では、出力先のパスやファイル名を指定します。

スクリプト設定

今度はpackage.jsonのscriptsという、コマンドやスクリプトを記述している箇所に設定を行なっていきます。 「envader-sample」直下の「package.json」の「scripts」部分を以下のように書き換えてください。

"scripts": {
    "dev": "webpack --mode development --watch",
    "build": "webpack --mode production"
  },

「dev」の方の末尾の--watchオプションを追加すると、ファイルの更新を監視し、開発中にわざわざコマンドを実行しなくてもバンドルを実行してくれます。

「src/modules/」内の「helloEnvader.js」をモジュールとして扱いたいので、「helloEnvader.js」の中身を以下のように記述します。

export const helloEnvader = (message) => {
  console.log(message);
};

同じく「src/」直下の「index.js」には先ほど作成した「helloEnvader」モジュールを呼び出してあげるという記述を行います。

import { helloEnvader } from './modules/helloEnvader.js';

helloEnvader("hello");

モジュールを呼び出すときには「import {モジュール名} from ‘path’」と記述します。

コンパイルの実行

バンドルを実行するには以下のコマンドを使用します。

npm run dev

すると以下のような表示がされます。スクリプトで—watchオプションを指定したため、プロジェクトのモニタリングモードになっています。モニタリングモードから抜ける時は「Ctrl + C(Mac:Command + C)」と入力してください。

> webpack-test@1.0.0 dev
> webpack --mode development --watch

asset bundle.js 4.29 KiB [emitted] (name: main)
runtime modules 670 bytes 3 modules
cacheable modules 154 bytes
  ./src/index.js 83 bytes [built] [code generated]
  ./src/modules/helloEnvader.js 71 bytes [built] [code generated]
webpack 5.65.0 compiled successfully in 106 ms

「compiled successfully」と表示されていればコンパイルは成功しています。

CSSや画像をバンドルする

webpackではJavaScriptファイル以外もひとつのJavaScriptファイルにまとめることができます。ここでは、CSSと画像の2つのファイルをバンドルする方法について解説します。

既に作成済みのプロジェクトに対して、ファイルの追加・修正を行っていきます。 全て作業を行なった後の最終的なディレクトリの構成は以下のとおりです。

.
├──  dist
│  ├──  bundle.js
│  └──  index.html
├──  package-lock.json
├──  package.json
├──  src
│  ├──  index.css
│  └──  index.js
└──  webpack.config.js

srcディレクトリ内のindex.jsファイルを以下のように修正します。

  • src/index.js
import styles from './index.css'

window.onload = Main

function Main() {
    console.log("Hello world")
}

srcディレクトリにindex.cssファイルを追加します。 中身は以下のように記述してください。

  • src/index.css
.title-class {
    color: red;
    font-weight: bold;
}

CSSをバンドルするためのパッケージの導入

CSSをバンドルするために、新たにパッケージを導入します。以下のコマンドを実行します。

npm install --save-dev css-loader style-loader

今回導入した2つのパッケージの名前と特徴を確認しましょう。

  1. css-loaderはJavaScriptファイルに書かれたCSSファイルのインポート文を読み取り、JavaScript内で使える形式にCSSを変換します。
  2. style-loaderはCSSファイルに書かれたclassなどをHTMLファイルにインライン形式で挿入するパッケージです。インライン形式とは、<style></style>の中にCSSの要素を記述することで、HTMLファイル上でCSSを設定し、反映することができる形式のことを指します。

前者と後者はよくセットで用いられます。2つのパッケージを組み合わせた際の処理の流れとしては、まず最初にcss-loaderがCSSファイルをJavaScript上で扱える形式に変換して取り込みます。

その後、style-loaderがHTMLファイルのheadタグにstyleタグを生成し、CSSの要素がインライン形式で挿入されます。その結果、設定したクラスなどのCSSが正しく反映されるわけです。

CSSをバンドルするための準備が整ったので、事項では実際にCSSファイルをバンドルする作業を行います。

CSSファイルをバンドルする

CSSファイルをバンドルするためには、webpack.config.jsにCSSファイルをバンドルの対象とするよう設定を加えます。webpack.config.jsを以下のように書き換えます。

const path = require('path');

module.exports = {
  mode: 'development',
  entry: `./src/index.js`,
  output: {
    filename: "bundle.js",
    path: path.join(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ]
  }
};

modulesのruleという箇所に、CSSファイルをバンドルする設定を書きました。{}で囲われているうち、testは対象のファイル名を表しています。css$は最後が.cssのファイル全てを対象とする正規表現という記法です。

CSSのバンドル対象を.cssと付いたファイル全てとしています。useは使用するパッケージを表しています。今回の場合は、前項で導入したstyle-loadercss-loaderを記入します。

以上で、バンドルをするための準備が整いました。以下のコマンドを実行してバンドルを行いましょう。

npm run dev

上のコマンドを実行した際、バンドルが完了してもコマンド自体は終了しないまま待機状態となってしまいます。したがって、webpack compiled successfully と表示されたら、control + c を押してコマンドの処理を中断します。distディレクトリを見てみると、bundle.jsが作成されていることがわかります。

バンドルしたJavaScriptファイルを使ってみる

バンドルされたbandle.jsをHTMLファイル上で読み込み、CSSを反映させます。まずは、distディレクトリの中にindex.htmlを作成します。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="./bundle.js"></script>
    <title>bandle test</title>
</head>
<body>
    <h1 class="title-class">bundled</h1>
</body>
</html>

scriptタグを使って、bandle.jsを読み込みます。また、h1タグには、CSSファイル上で設定を記述したtitle-classをクラスとして指定します。

先ほど作成したdist/index.htmlをブラウザ上で表示します。 文字が赤い太文字で表示されていれば、CSSが反映されています。

画像をバンドルする

CSSの次は画像をバンドルします。CSSとは違い、webpackのversion5以降では画像をバンドルする際にパッケージを追加でインストールする必要はありません。

早速、webpack.config.jsを以下のように編集します。

const path = require('path');

module.exports = {
  mode: 'development',
  entry: `./src/index.js`,
  output: {
    filename: "bundle.js",
    path: path.join(__dirname, 'dist'),
    assetModuleFilename: "asset/[name][ext]"
  },
  module: {
    rules: [
      {
        // 拡張子 css のファイル(正規表現)
        test: /\\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\\.(jpg|png|svg|ico)$/,
        type "asset",
      }
    ]
  }
};

modulesのruleという箇所に、画像をバンドルする設定を書きました。testでバンドルの対象を設定するので、今回はjpg, png, svg, ico形式のファイル全てを対象とする正規表現を記述しました。typeには、画像をどのようにバンドルするかを指定することができます。今回はassetを選択していますが、本来以下のtypeから状況に適したものを選択することになります。

  • asset → 下記2つの設定から自動で1つを選択する。
  • asset/resource → アセットを指定したディレクトリに新たなファイルとして出力する。
  • asset/inline → アセットを1つのJavaScriptファイルに取り込む。

outputのassetModuleFilename では、distディレクトリにどのような名前で画像ファイルを出力するかを設定します。今回はdist/asset/画像ファイルとなるように設定しました。後に記述するJavaScriptファイルでも、このパスを指定して画像を読み込みます。

次に、バンドルする対象の画像を用意します。srcディレクトリの中に画像ファイルを1つ、好きなものを置いておいてください。説明時にはajisai.jpgをsrcディレクトリの中に置いた前提で話を進めます。

次に、index.jsを以下のように編集します。

import styles from './index.css'
import './ajisai.jpg'

window.onload = Main

function Main() {
    console.log("Hello world")

    // ajisaiという名前のimgを作成
    const ajisai = document.createElement("img")
    // ajisaiというimgにバンドルされた画像のURLを設定
    ajisai.setAttribute('src', './asset/ajisai.jpg')
    ajisai.setAttribute('width', '400')
    document.body.appendChild(ajisai)
}

ここでは、ajisaiという名前のimg要素を生成し、それに対してバンドルした画像を400pxの大きさで表示するよう設定しています。その際、2行目にはajisai.jpgをインポートするようにしています。ajisai.jpgをインポートしなければ、バンドルの対象にならないので注意しましょう。

画像をバンドルするための準備が整ったので、以下のコマンドを実行します。

npm run dev

先ほど作成したdist/index.htmlをブラウザ上で表示します。

画像が表示されていれば、バンドル成功です。

まとめ

今回はwebpackの使い方について解説しました。

webpackを使うことで、JavaScriptやCSSファイル、画像ファイルを1つのJavaScriptファイルにまとめることができます。その工程をバンドルと言います。バンドルすることで、バンドルをしない状態のJavaScriptアプリケーションよりもパフォーマンスの向上が期待できます。

webpackは今回説明した内容以外にもさまざまな設定項目や追加のパッケージがありますが、近年のフロントエンド開発では必須の技術ですので、少しずつ慣れていきましょう。

問題を解くためには、十分な画面サイズのPC環境をご利用下さい。