bootstrap
npm
webpack

webpackでbootstrapのcssやfontファイルを配置する

最近、「gulpとかのタスクランナーを使わなくてもwebpack単体でいろいろできるよ!」という声がよく聞こえてきます。
流行りに乗ってwebpackだけで環境構築しようとしたのですが、npmで落としてきたbootstrapのcssなどをプロジェクトに引っ張ってこようとしたら結構突っかかったのでまとめます。

今回やること

そもそもwebpackは複数のファイルをまとめて扱いやすくするものです。
そのため、cssやfontファイルなどもurl-loaderというモジュールを使うと、url化してjsファイルに組み込む、といったこともできます。
しかし、個人的にはbootstrapなどの外部モジュールは自作のjsファイルとは別にしておきたい。fontファイルなどもurl化せずに必要なものをプロジェクト内に配置するだけにしたい。

事前準備

まずは、必要なものをnpmを使ってインストールしていきます。

npm install webpack file-loader style-loader css-loader extract-text-webpack-plugin bootstrap

インストール後、webpack.config.jsを作成し、そこに設定情報を書き込んでいきます。

webpack.config.js
const app = {
  entry:[
    __dirname + '/webroot/js/script.js'
  ],
  output: {
      path: __dirname + '/webroot/js/',
      filename: 'bundle.js'
  }
};

module.exports = app;
script.js
import Bootstrap from 'bootstrap';

とりあえず、bootstrapのjsをimportするscript.jsを作ってwebpackを実行します。
npmの設定ファイル(package.json)のscriptにwebpack用のscriptを書いて実行します。

package.json
{

  "scripts": {
    "build": "webpack"
  },

}
npm run build

これにより、bootstrapのjsファイルが取り込まれたbundle.jsが出力されます。
自前のscriptをscript.jsに書けば、それらと結合されて1つのjsファイルになるということです。

cssと関連ファイルを出力する

webpack.config.js

const ExtractTextPlugin = require('extract-text-webpack-plugin');
const bootstrap = {
  entry:[
    __dirname + '/node_modules/bootstrap/dist/css/bootstrap.css'
  ],
  output: {
      path: __dirname + '/webroot/css/',
      filename: 'bootstrap.css'
  },
  module: {
    loaders: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract("css-loader")
      },
      {
        test: /\.(woff|woff2|eot|ttf|svg)$/,
        loader: 'file-loader?name=../font/[name].[ext]'
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin( "../css/bootstrap.css" )
  ]
};

module.exports = [app, bootstrap];

webpack.config.jsは上述のようになります。
1つ1つ見ていくと、entryで対象のcssを指定して、ExtractTextPluginを使って指定した場所に出力します。最終的な出力場所はoutputで指定した場所ではなく、pluginsのnew ExtractTextPluginの引数として指定した場所になります(output自体はないとエラーになるので、書いておく必要があります)。
画像やfontの関連ファイルはfile-loaderを使用してそのままの形で出力します。このとき、fontフォルダ以下に出力したいのでname属性を使って出力場所を指定しています。
最後に、module.exportsで対象をappとbootstrapの両方を実行するように配列で指定します。

まとめ

これでcssとその関連ファイルをとってきて、プロジェクトの配下に移動してくることができました。この時、cssの内容を解釈して必要なファイルだけを対象にしたり、自動的にファイルの内容を出力場所に合わせて書き換えたりするので、自力で修正をしなくてもcssを使っていくことが可能です。
また、今回はcssをそのまま持ってきていますが、webpackにはlessやsassのloaderもあるのでそれらをコンパイルしてcssとして出力する、なんてことも可能です。

ただ、今のままだとwebpackを実行するたびにbootstrapの内容を毎回取得しに行くようになっています。外部モジュールだと頻繁に変更したりはないと思うので、普段はappだけを実行してbootstrapのほうは対象から除外したいということもあります。
そのあたりの設定は探したのですが、見つからず…。
整合性を合わせるために毎回bundle化したほうがいいということなのでしょうかね。
gulpだとそのあたりも結構自由度が効いたと思うので、そのあたりのカスタマイズが必要な時はgulpを使ったほうがいいかもしれません。