モジュールバンドラwebpackでマテリアルデザインベースのCSSフレームワークMaterializeを使おうとしてだいぶハマったので,誰かの役に立つかもしてないと思いメモ
完成したテンプレート
最終的に完成したコードはGitHubに公開してあるので,役に立つことがあれば使って下さい
- 最小構成(スクリプトのバンドルのみ)
- フル(スクリプト、スタイルシート、フォントのコンパイル&バンドル)
ゴール
Materializeの公式サイトにて公開されているStarter Template(DEMO)をwebpackで使う
スタイルシートやフォントのバンドルはハマりどころではないのでここではスクリプトファイルのバンドルのみ
また,MaterializeはjQueryに依存しているが現在,標準でjQuery2.1.1を使用するようになっているので,これを編集時最新版のjQuery3.2.1を使用するようにする(すでにGitHub上ではjQueryのバージョンが更新されているので,近いうちに更新されると思われる)
それぞれ編集時点で最新のものを使用
直面した問題
- ページ表示時に
$(...).sideNav
が見つからないエラー - サイドナビを開こうとすると
e.velocity
が見つからないエラー
webpackとMaterialize
webpack
モジュールバンドラ
スクリプト,スタイルシート,イメージ,フォント,その他リソースを依存関係を解決しながらまとめるもの
webpack2を使用
Materialize
Googleが提唱するマテリアルデザインをベースにしたCSSフレームワーク
Googleから公式にMaterial Design Liteというフレームワークも提供されているが,機能があまり多くないのと個人的に使いにくかったため,今回はドキュメントも多いMaterializeを選択
動作確認済み環境(バージョン)
- webpack 2.6.1
- Materialize 0.98.2
- jquery 3.2.1
環境構築
テンプレートの入手
http://materializecss.com/templates/starter-template.zip よりMaterializeのStarter Templateを入手する
materialize, jqueryのインストール
npm install --save materialize-css jquery
※ Materializeのnpmモジュール名はmaterialize-css
なので注意.materialize
は別物
webpackのインストール
npm install --save-dev webpack
webpackの設定と起点となるスクリプトの追加
js
ディレクトリ以下にmain.js
を作成し,これを基点にbundle.js
にバンドルする
ここでは,MaterializeがjQueryに依存しているため,webpackのProvidePluginを使用して$
及びjQuery
が参照された時にjQueryモジュールを返すようにする
const path = require("path");
var webpack = require("webpack");
module.exports = {
entry: path.join(__dirname, "js", "main.js"),
output: {
path: path.join(__dirname, "js"),
filename: "bundle.js"
}
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
]
};
require('materialize-css');
require("./init");
index.htmlの修正
...
<!-- Scripts-->
<script src="js/bundle.js"></script>
</body>
</html>
buildスクリプトの追加
package.json
にbuildスクリプトを追加する
必ずしも追加する必要はないが,npm install
でプロジェクトのローカルにモジュールをインストールした場合,通常コマンドへのパスが通っていないので,例えばwebpack
を実行する時,以下のようにする必要がある
$(npm bin)/webpack
毎回これをするのは面倒なので,package.json
に以下のように追加する
npm scriptにおいては自動的にプロジェクトのローカルのモジュールへのパスは解決してくれる
...
"scripts": {
"build": "webpack"
...
},
Mateliarizeで追加されているはずの関数が参照エラーになる
ビルドしてページを表示してみるもエラーが発生
npm run build
Uncaught TypeError: $(...).sideNav is not a function
$.fn.sideNav
はMaterializeのスクリプト内で宣言されているはずであるが,これが参照できていない
ここでwebpackの出力を見てみると以下のようになっていることが分かる
Asset Size Chunks Chunk Names
bundle.js 754 kB 0 [emitted] [big] main
[0] ./~/materialize-css/~/jquery/dist/jquery.js 258 kB {0} [built]
[1] ./js/init.js 139 bytes {0} [built]
[2] ./~/materialize-css/bin/materialize.js 149 kB {0} [built]
[3] ./js/main.js 187 bytes {0} [built]
[4] ./~/hammerjs/hammer.js 73.8 kB {0} [built]
[5] ./~/jquery/dist/jquery.js 268 kB {0} [built]
[6] (webpack)/buildin/amd-options.js 82 bytes {0} [built]
これをよく見てみると,[0]
でMaterializeが内包しているjQueryが読み込まれており,[5]
でインストールしたjQueryが読み込まれていることが分かる.実際に,例えばmaterialize.js
内及びinit.js
内でconsole.log($.fn.jquery);
などとして参照されているjQueryのバージョンを出力させてみると異なるバージョンとなっていることが確認できた
これはMaliterializeのスクリプトの先頭で変数jQuery
の存在確認をして存在しない場合にjQueryをrequireしているためで,この時Materizlizeが内包しているjQueryが参照されてしまっている
解決策
これを解決するためには,webpackにより参照されるjQueryモジュールを一意に定める必要がある
そこでwebpackの設定ファイルに以下を追加
...
resolve: {
alias: {
jquery: path.join(__dirname, 'node_modules', 'jquery')
}
},
...
これにより,jquery
モジュールが参照された時は常にnpmでインストールしたjQueryを参照しにいくようになる
sideNav
を開こうとするとエラー
ここまででページを表示してもエラーは出なくなったが,ウィンドウ幅を小さくして,ページ左上のハンバーガーアイコンをクリックしてサイドナビを開こうとすると以下のエラーが発生する
Uncaught TypeError: e.velocity is not a function
今度はvelocity
という関数が参照エラーになっている
細かいことは省略するが,これはMaterializeが内部で使用しているVelocityJS
で宣言されているはずである
解決策
結論から言うと,VelocityJS
では$
でもjQuery
でもなくwindow.jQuery
を参照しているようなので,webpackの設定ファイルに以下のように追加する
...
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
...
ゴールとその他
以上でMaterializeのStarter Templateがwebpackを使用して正常に動作するようになった
あとは,せっかくwebpackを使用しているので,スタイルシートのバンドルをしたり,フォントファイル(roboto
,material icons
)のロードをwebpackで行うようにすれば依存ファイルをきれいに管理できる