メインコンテンツにスキップ ドキュメントナビゲーションにスキップ
Check

webpackでの使用(Bootstrap & Webpack) v5.2.0更新、v5.2.1追加

webpackを使用してBootstrapのCSSとJavaScriptをプロジェクトに組み込みバンドルする方法の公式ガイド。

※"v5.2.0"での変更はv5.2.0-beta1での変更も含みます。
bootstrap-webpack.png

※webpackについては、Webpackってどんなもの?(Qiita)を参照。

セットアップ(Setup)

Bootstrapを使用してwebpackプロジェクトをゼロから構築しているため、実際に始める前に、いくつかの前提条件と事前の手順がある。このガイドでは、既にNode.jsがインストールされており、ある程度ターミナル(コマンドプロンプト)に精通している必要がある。

  1. プロジェクトフォルダを作成し、npmを設定。my-project フォルダを作成し、npmを -y 引数で初期化して、すべてのインタラクティブな質問を回避する。

    実行コマンド$ mkdir my-project && cd my-project
    $ npm init -y
  2. webpackをインストール。次に、webpackのコア用の webpack、ターミナルからwebpackコマンドを実行できるようにする webpack-cli、ローカル開発サーバーを実行できるようにする webpack-dev-server といったwebpack開発の依存関係をインストールする必要がある。--save-dev を使用して、これらの依存関係が開発用であり、本番用ではないことを通知する。

    実行コマンド$ npm i --save-dev webpack webpack-cli webpack-dev-server
  3. Bootstrapをインストール。これで、Bootstrapがインストールできる。ドロップダウン、ポップオーバー、ツールチップはPopperに依存しているため、Popper(@popperjs/core)もインストールする。これらのコンポーネントを使用する予定がない場合は、ここでPopperを省略しても可。

    実行コマンド$ npm i --save bootstrap @popperjs/core
  4. 追加の依存関係をインストール。webpackとBootstrapに加えて、BootstrapのCSSとJSをwebpackに適切にインポートしてバンドルするには、さらにSass、一部のローダー、Autoprefixerといったいくつかの依存関係が必要。

    実行コマンド$ npm i --save-dev autoprefixer css-loader postcss-loader sass sass-loader style-loader

必要な依存関係がすべてインストールされたので、プロジェクトファイルの作成とBootstrapのインポートに取り掛かることができる。

プロジェクト構造(Project structure)

my-project フォルダを作成し、npmを初期化した。次に、src フォルダと dist フォルダも作成して、プロジェクト構造を完成させる。my-project から以下を実行するか、以下に示すフォルダとファイル構造を手動で作成する。

実行コマンド$ mkdir {dist,src,src/js,src/scss}
$ touch dist/index.html src/js/main.js src/scss/styles.scss webpack.config.js

完了すると、プロジェクト全体は以下のようになる。

my-project/
├── dist/
│   └── index.html
├── src/
│   ├── js/
│   │   └── main.js
│   └── scss/
│       └── styles.scss
├── package-lock.json
├── package.json
└── webpack.config.js

この時点では、すべてが適切な場所にあるが、webpack.config.js をまだ入力していないため、webpackは機能しない。

webpackを構成する(Configure Webpack)

依存関係がインストールされ、プロジェクトフォルダでコーディングを開始できるようになったら、webpackを構成して、プロジェクトをローカルで実行できる。

  1. エディタで webpack.config.js を開く。ファイルの中は空白なので、サーバーを起動するために定型的な設定を追加する必要がある。構成のこの部分は、webpackがプロジェクトのJavaScriptを探す場所、コンパイルしたコードを出力する場所(dist)、開発サーバーの動作(ホットリロードで dist フォルダから取得)を指示する。

    webpack.config.js の設定例
    const path = require('path')
    
    module.exports = {
      entry: './src/js/main.js',
      output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
      },
      devServer: {
        static: path.resolve(__dirname, 'dist'),
        port: 8080,
        hot: true
      }
    }
  2. 次に、dist/index.html を作成。これは、後の手順で追加するバンドルされたCSSとJSを利用するためにwebpackがブラウザにロードするHTMLページである。その前にレンダリングするものを指定して、前の手順の output JS(main.js)を組み込む必要がある。

    dist/index.html の設定例
    <!doctype html>
    <html lang="ja">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Webpack付きBootstrap</title>
      </head>
      <body>
        <div class="container py-4 px-3 mx-auto">
          <h1>Hello, Bootstrap and Webpack!</h1>
          <button class="btn btn-primary">Primary button</button>
        </div>
        <script src="./main.js"></script>
      </body>
    </html>

    上記では、BootstrapのCSSがwebpackによって読み込まれるタイミングが確認できるように、div class="container"<button> を使用したBootstrapのスタイルを少しだけ入れている。

  3. ここで、webpackを実行するためのnpmスクリプトが必要。package.json を開き、以下に示す start スクリプトを追加(すでにtestスクリプトが用意されているはず)。このスクリプトを使用して、ローカルwebpack開発サーバーを起動する。

    package.json の設定例
    {
      // ...
      "scripts": {
        "start": "webpack serve --mode development",
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      // ...
    }
  4. そして最後に、webpackを起動。ターミナルの my-project フォルダから、新しく追加されたnpmスクリプトを実行:

    実行コマンド$ npm start
    実行中のWebpack開発サーバー

このガイドの次が最後となる項目では、webpackローダーをセットアップし、BootstrapのCSSとJavaScriptをすべてインポートする。

Bootstrapのインポート(Import Bootstrap)

Bootstrapをwebpackにインポートするには、最初の項目でインストールしたローダーが必要。npmを使用して既にインストールしているが、これらを使用するようにはwebpackを構成する必要がある。

  1. webpack.config.js でローダーを設定。これで構成ファイルが完成し、以下のスニペットと一致するはず。ここでの唯一の新しい部分は module セクションである。

    webpack.config.js の設定例
    const path = require('path')
    
    module.exports = {
      entry: './src/js/main.js',
      output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
      },
      devServer: {
        static: path.resolve(__dirname, 'dist'),
        port: 8080,
        hot: true
      },
      module: {
        rules: [
          {
            test: /\.(scss)$/,
            use: [
              {
                loader: 'style-loader'
              },
              {
                loader: 'css-loader'
              },
              {
                loader: 'postcss-loader',
                options: {
                  postcssOptions: {
                    plugins: () => [
                      require('autoprefixer')
                    ]
                  }
                }
              },
              {
                loader: 'sass-loader'
              }
            ]
          }
        ]
      }
    }

    これらすべてのローダーが必要な理由を要約すると、style-loader はCSSをHTMLページの <head><style> 要素に挿入し、css-loader@importurl() の使用を支援し、postcss-loaderAutoprefixer に必要であり、sass-loader はSassの使用を可能にする。

  2. それから、BootstrapのCSSをインポートする。以下を src/scss/styles.scss に追加して、BootstrapのすべてのソースSassをインポート。

    src/scss/styles.scss の設定例
    // BootstrapのCSSをすべてインポート
    @import "~bootstrap/scss/bootstrap";

    必要に応じて、スタイルシートを個別にインポートすることもできる。詳細については、Sassカスタマイズのインポートの項目に記載。

  3. 次にCSSをロードし、BootstrapのJavaScriptをインポートする。以下を src/js/main.js に追加して、CSSをロードし、BootstrapのすべてのJSをインポート。PopperはBootstrapを介して自動的にインポートされる。

    src/js/main.js の設定例
    全てをインポート// カスタムCSSをインポート
    import '../scss/styles.scss'
    
    // BootstrapのJSをすべてインポート
    import * as bootstrap from 'bootstrap'

    バンドルサイズを抑えるために、必要に応じてJavaScriptプラグインを個別にインポートすることもできる。

    個別にインポートimport Alert from 'bootstrap/js/dist/alert'
    
    // または、必要なプラグインを指定:
    import { Tooltip, Toast, Popover } from 'bootstrap'

    Bootstrapのプラグインの使用方法の詳細については、JavaScriptの解説に記載。

  4. これで完了!🎉BootstrapのソースSassとJSが完全に読み込まれると、ローカル開発サーバーは次のようになる。

    Bootstrapで実行されているWebpack開発サーバー

これで、使用するBootstrapコンポーネントの追加が始められる。追加のカスタムSassを組み込み、BootstrapのCSSとJSの必要な部分のみをインポートして構築を最適化する方法については、完全なWebpackサンプルプロジェクトを必ずチェックして下さい。

最適化(Production optimizations)v5.2.1追加

セットアップによっては、プロジェクトを本番環境で実行するのに役立つ追加のセキュリティと速度の最適化を実装したい場合がある。これらの最適化はWebpack サンプルプロジェクトでは適用されず、実装するのはユーザー次第であることに注意して下さい。

CSSの抽出(Extracting CSS)

上記で設定した style-loader は、CSSをバンドルに出力するため、手動で dist/index.html にあるCSSファイルを読み込む必要がなく便利。しかし、この方法は厳格なコンテンツ・セキュリティ・ポリシーでは機能しない可能性があり、バンドルサイズが大きいためアプリケーションのボトルネックになる可能性がある。

CSSを分離して dist/index.html から直接読み込めるようにするには、mini-css-extract-loader Webpackプラグインを使用する。

まず、プラグインをインストール:

実行コマンド$ npm install --save-dev mini-css-extract-plugin

次に、Webpackの設定でプラグインをインスタンス化して使用:

差分の表示--- a/webpack/webpack.config.js
+++ b/webpack/webpack.config.js
@@ -1,8 +1,10 @@
+const miniCssExtractPlugin = require('mini-css-extract-plugin')
 const path = require('path')
 
 module.exports = {
   mode: 'development',
   entry: './src/js/main.js',
+  plugins: [new miniCssExtractPlugin()],
   output: {
     filename: "main.js",
     path: path.resolve(__dirname, "dist"),
@@ -18,8 +20,8 @@ module.exports = {
         test: /\.(scss)$/,
         use: [
           {
-            // DOM に `<style>` タグを挿入して CSS を追加
-            loader: 'style-loader'
+            // CSSを含む各JSファイルに対してCSSを抽出
+            loader: miniCssExtractPlugin.loader
           },
           {

npm run build を再度実行すると、src/js/main.js で読み込んだすべてのCSSを含む新しいファイル dist/main.css が新たに作成される。そこでブラウザで dist/index.html を表示すると、dist/main.css の中にあるため、スタイルが消えてしまう。生成されたCSSを dist/index.html に組み込むには、以下のようにする。

差分の表示--- a/webpack/dist/index.html
+++ b/webpack/dist/index.html
@@ -3,6 +3,7 @@
   <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="stylesheet" href="./main.css">
     <title>Bootstrap w/ Webpack</title>
   </head>
   <body>

SVGファイルの抽出(Extracting SVG files)

BootstrapのCSSは、インラインの data: URIを経由したSVGファイルへの複数の参照が組み込まれている。画像の data: URIをブロックするコンテンツ・セキュリティ・ポリシーをプロジェクトに定義した場合、これらのSVGファイルは読み込まれない。この問題は、Webpackのアセットモジュール機能を使って、インラインのSVGファイルを抽出することで回避できる。

以下のように、インラインSVGファイルを抽出するようにWebpackを設定:

差分の表示--- a/webpack/webpack.config.js
+++ b/webpack/webpack.config.js
@@ -16,6 +16,14 @@ module.exports = {
   },
   module: {
     rules: [
+      {
+        mimetype: 'image/svg+xml',
+        scheme: 'data',
+        type: 'asset/resource',
+        generator: {
+          filename: 'icons/[hash].svg'
+        }
+      },
       {
         test: /\.(scss)$/,
         use: [

再度 npm run build を実行すると、SVGファイルが dist/icons に展開され、CSSから適切に参照されていることが確認できる。

【変更履歴】
  • 【v5.0.0-alpha1】
    • src/js/main.js の設定:import 'bootstrap'import {プラグイン名} from 'bootstrap'(必要なプラグインが指定可能に)
  • 【v5.0.0-alpha2】
    • webpack.config.js の設定:potcss-loaderpostcssOptions キーを使用するようになったので変更
  • 【v5.0.0-beta1】
    • Popper v2の対応により、追加コマンドが npm install popper.js から npm install @popperjs/core に変更
  • 【v5.1.1】
    • src/js/main.js の設定:全てをインポートする方法を追加(JavaScriptインポートの使用法を明確にした)
  • 【v5.2.0】
    • ガイドを全面的に書き直して更新
    • webpack.config.js の設定:JavaScriptの記述をES6(ES2015)に変更

ここで何か間違いがあったり、情報が古くなっていたら、GitHubのIssuesを開いて指摘して下さい。トラブルシューティングのサポートが必要なら、GitHubで検索するか、ディスカッションを始めて下さい。