Help us understand the problem. What is going on with this article?

webpackでMaterializeを使うにあたりハマったこと

More than 1 year has passed since last update.

モジュールバンドラwebpackでマテリアルデザインベースのCSSフレームワークMaterializeを使おうとしてだいぶハマったので,誰かの役に立つかもしてないと思いメモ

完成したテンプレート

最終的に完成したコードはGitHubに公開してあるので,役に立つことがあれば使って下さい
- 最小構成(スクリプトのバンドルのみ)
- フル(スクリプト、スタイルシート、フォントのコンパイル&バンドル)

ゴール

Materializeの公式サイトにて公開されているStarter Template(DEMO)をwebpackで使う
スタイルシートやフォントのバンドルはハマりどころではないのでここではスクリプトファイルのバンドルのみ
また,MaterializeはjQueryに依存しているが現在,標準でjQuery2.1.1を使用するようになっているので,これを編集時最新版のjQuery3.2.1を使用するようにする(すでにGitHub上ではjQueryのバージョンが更新されているので,近いうちに更新されると思われる)
それぞれ編集時点で最新のものを使用

直面した問題

  1. ページ表示時に$(...).sideNavが見つからないエラー
  2. サイドナビを開こうとすると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のインストール

command
npm install --save materialize-css jquery

※ Materializeのnpmモジュール名はmaterialize-cssなので注意.materializeは別物

webpackのインストール

command
npm install --save-dev webpack

webpackの設定と起点となるスクリプトの追加

jsディレクトリ以下にmain.jsを作成し,これを基点にbundle.jsにバンドルする
ここでは,MaterializeがjQueryに依存しているため,webpackのProvidePluginを使用して$及びjQueryが参照された時にjQueryモジュールを返すようにする

webpack.config.js
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"
    })
  ]
};
main.js
require('materialize-css');
require("./init");

index.htmlの修正

index.html
...
  <!--  Scripts-->
  <script src="js/bundle.js"></script>

  </body>
</html>

buildスクリプトの追加

package.jsonにbuildスクリプトを追加する
必ずしも追加する必要はないが,npm installでプロジェクトのローカルにモジュールをインストールした場合,通常コマンドへのパスが通っていないので,例えばwebpackを実行する時,以下のようにする必要がある

command
$(npm bin)/webpack

毎回これをするのは面倒なので,package.jsonに以下のように追加する
npm scriptにおいては自動的にプロジェクトのローカルのモジュールへのパスは解決してくれる

package.json
  ...
  "scripts": {
    "build": "webpack"
    ...
  },

Mateliarizeで追加されているはずの関数が参照エラーになる

ビルドしてページを表示してみるもエラーが発生

command
npm run build
Uncaught TypeError: $(...).sideNav is not a function

$.fn.sideNavはMaterializeのスクリプト内で宣言されているはずであるが,これが参照できていない
ここでwebpackの出力を見てみると以下のようになっていることが分かる

log
    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の設定ファイルに以下を追加

webpack.config.js
  ...
  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の設定ファイルに以下のように追加する

webpack.config.js
  ...
    new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery"
    })
  ...

ゴールとその他

以上でMaterializeのStarter Templateがwebpackを使用して正常に動作するようになった
あとは,せっかくwebpackを使用しているので,スタイルシートのバンドルをしたり,フォントファイル(robotomaterial icons)のロードをwebpackで行うようにすれば依存ファイルをきれいに管理できる

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away