はじめに
当記事では、Google社製のマテリアルデザイン用のオープンソースライブラリであるMaterial Components for the Web(以下、「MDC Web」)をNuxt.js(v2)に導入するための手順を記載します。
Material Components for the Web 関連リンク
- 公式ドキュメント
- GitHubリポジトリ
Nuxtプロジェクトの作成
まずはNuxtのプロジェクトを作成して行きます。
準備
必要なものを準備しましょう。Node.jsとnpmをインストールします。
【必要なもの】※バージョンは筆者の動作環境のものを記載
- Node.js 8.11.3
- npm 5.6.0
プロジェクト作成
vue-cliをインストールします。今回はyarnも使ったので一緒にインストールします。(npmだけでも問題ないです)
npm install -g vue-cli yarn
vueコマンドでNuxtのテンプレートプロジェクトを作成します。(nuxtpfというディレクトリとします)
実行するといくつか質問されるので、任意のものを入力してください。
vue init nuxt-community/starter-template nuxtpj
作成されたディレクトリに移動します。
cd nuxtpj
次に、必要なモジュールをインストールします。
yarn
http://localhost:3000
をブラウザで開くと、Nuxt.jsのウェルカムページが表示されます。
MDC Webのインストール
ここから本題のMDC Webのインストールについて記載して行きます。
package.json
package.jsonの中身は下記の通りです。追加したのは以下のモジュールです。
手動で個別に入れても構いませんし、package.jsonを書き換えて一括で入れても構いません。
- material-components-web
- node-sass
- postcss-hexrgba
- postcss-loader
- postcss-nested
- postcss-responsive-type
- sass-loader
- style-loader
- vue-loader
- vue-style-loader
{
"name": "nuxtpj",
"version": "1.0.0",
"description": "Nuxt.js project",
"author": "",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
"precommit": "npm run lint"
},
"dependencies": {
"@nuxtjs/axios": "^5.3.6",
"material-components-web": "^0.43.1",
"node-sass": "^4.11.0",
"nuxt": "^2.0.0",
"postcss-hexrgba": "^1.0.1",
"postcss-loader": "^3.0.0",
"postcss-nested": "^4.1.1",
"postcss-responsive-type": "^1.0.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.1",
"vue-loader": "^15.6.1",
"vue-style-loader": "^4.1.2"
},
"devDependencies": {
"babel-eslint": "^10.0.1",
"eslint": "^4.19.1",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^2.1.1",
"eslint-plugin-vue": "^4.0.0"
}
}
nuxt.config.js
次に、nuxt.config.jsにwebpackの設定を行います。
module.exports = {
/*
** Headers of the page
*/
head: {
title: 'nuxtpj',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: 'Nuxt.js project' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
/*
** Customize the progress bar color
*/
loading: { color: '#3B8070' },
/*
** Build configuration
*/
build: {
/*
** Run ESLint on save
*/
extend (config, { isDev, isClient, loaders: { scss } }) {
if (isDev && isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
scss.includePaths = ['node_modules',] // 追加(※後述)
},
// 追加(※後述)
postcss: [
require('postcss-nested')(),
require('postcss-responsive-type')(),
require('postcss-hexrgba')(),
],
},
modules: [
'@nuxtjs/axios',
]
}
設定は以上です。
動作確認のためにdefault.vueファイルを編集します。
<template>
<div>
<button class="mdc-button" ref="button"><span class="mdc-button__label">テスト</span></button>
<nuxt/>
</div>
</template>
<style lang="scss">
@import "~material-components-web/material-components-web";
</style>
<script>
import {MDCRipple} from '@material/ripple'
export default {
mounted() {
this.ripple = new MDCRipple(this.$refs.button)
},
destroyed() {
this.ripple.destroy()
}
}
</script>
サーバを起動します。
yarn dev
http://localhost:3000
にアクセスしてみてください。
表示されたボタンを押下するとマテリアルなRippleエフェクトが付いた動きが確認できると思います。
トラブルシューティング
NuxtにMDC Webを導入するにあたり、情報が少なかったり、エラーが良くわからんかったりと、だいぶ苦労しました。
以下、構築中に発生した問題と解決策を記載しておきます。
SCSSのincludePahts設定
MDC Webを入れて起動した直後のエラーです。
yarn add material-components-web
<template>
<div>
<nuxt/>
</div>
</template>
<style lang="scss">
@import "~material-components-web/material-components-web";
</style>
ERROR Failed to compile with 1 errors friendly-errors 17:09:59
ERROR in ./layouts/default.vue?vue&type=style&index=0&lang=scss& friendly-errors 17:09:59
Module build failed (from ./node_modules/sass-loader/lib/loader.js): friendly-errors 17:09:59
undefined
^
File to import not found or unreadable: @material/button/mdc-button.
in c:\develop\pota\client\node_modules\material-components-web\material-components-web.scss (line 23, column 1)
friendly-errors 17:09:59
@ ./node_modules/vue-style-loader!./node_modules/css-loader??ref--6-oneOf-1-1!./node_modules/@nuxt/webpack/node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/sass-loader/lib/loader.js??ref--6-oneOf-1-3!./node_modules/vue-loader/lib??vue-loader-options!./layouts/default.vue?vue&type=style&index=0&lang=scss& 4:14-395 14:3-18:5 15:22-403
@ ./layouts/default.vue?vue&type=style&index=0&lang=scss&
@ ./layouts/default.vue
@ ./.nuxt/App.js
@ ./.nuxt/index.js
@ ./.nuxt/client.js
@ multi webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=/__webpack_hmr/client ./.nuxt/client.js
friendly-errors 17:09:59
i Waiting for file changes
どうやら、MDC Web自体はnode_modulesのmaterial-components-webの中にあるのですが、実際はnode_modules/@material配下にあるコンポーネントの各ディレクトリを参照する構造になっているようです。
Getting Startedに書いてある通りです。
Note: Configuring includePaths should suffice for most cases where all MDC Web packages are kept up-to-date together. If you encounter problems compiling Sass due to nested node_modules directories, see the Appendix below on how to configure a custom importer instead.
従って、scssにパスの解決をしてあげる必要があるとのこと。includePathsを設定します。
build: {
/*
** Run ESLint on save
*/
extend (config, { isDev, isClient, loaders: { scss } }) {
if (isDev && isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
scss.includePaths = ['node_modules'] // パスを追加
},
ここまででとりあえずマテリアルデザインの基本的なものは使えるようです。
PostCSS設定
次に、こんなエラーが出ました。
WARN Compiled with 2 warnings friendly-errors 17:17:57
WARN in ./layouts/default.vue?vue&type=style&index=0&lang=scss& friendly-errors 17:17:57
Module Warning (from ./node_modules/postcss-loader/src/index.js): friendly-errors 17:17:57
Warning
(6603:5) start value has mixed support, consider using flex-start instead
friendly-errors 17:17:57
@ ./node_modules/vue-style-loader!./node_modules/css-loader??ref--6-oneOf-1-1!./node_modules/@nuxt/webpack/node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/sass-loader/lib/loader.js??ref--6-oneOf-1-3!./node_modules/vue-loader/lib??vue-loader-options!./layouts/default.vue?vue&type=style&index=0&lang=scss& 4:14-395 14:3-18:5 15:22-403
@ ./layouts/default.vue?vue&type=style&index=0&lang=scss&
@ ./layouts/default.vue
@ ./.nuxt/App.js
@ ./.nuxt/index.js
@ ./.nuxt/client.js
@ multi webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=/__webpack_hmr/client ./.nuxt/client.js
friendly-errors 17:17:57
WARN in ./layouts/default.vue?vue&type=style&index=0&lang=scss& friendly-errors 17:17:57
Module Warning (from ./node_modules/postcss-loader/src/index.js): friendly-errors 17:17:57
Warning
(6721:5) start value has mixed support, consider using flex-start instead
friendly-errors 17:17:57
@ ./node_modules/vue-style-loader!./node_modules/css-loader??ref--6-oneOf-1-1!./node_modules/@nuxt/webpack/node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/sass-loader/lib/loader.js??ref--6-oneOf-1-3!./node_modules/vue-loader/lib??vue-loader-options!./layouts/default.vue?vue&type=style&index=0&lang=scss& 4:14-395 14:3-18:5 15:22-403
@ ./layouts/default.vue?vue&type=style&index=0&lang=scss&
@ ./layouts/default.vue
@ ./.nuxt/App.js
@ ./.nuxt/index.js
@ ./.nuxt/client.js
@ multi webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=/__webpack_hmr/client ./.nuxt/client.js
friendly-errors 17:17:57
i Waiting for file changes
これもGetting Statrtedに書いてある通りで、PostCSSにautoprefixerなどの設定をしてあげないといけないそうです。
In order to add vendor-specific styles to the Sass files, we need to configure autoprefixer through PostCSS.
build: {
/*
** Run ESLint on save
*/
extend (config, { isDev, isClient, loaders: { scss } }) {
if (isDev && isClient) {
config.module.rules.push({
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/
})
}
scss.includePaths = ['node_modules',]
},
// 追加
postcss: [
require('postcss-nested')(),
require('postcss-responsive-type')(),
require('postcss-hexrgba')(),
],
},
ちなみに...
MDCRippleをVueで使う際はmountedのところでDOMの参照をしてあげる必要があります。そのため、button要素などにref属性を付けて参照できるようにしてあげる必要があります。
<button class="mdc-button" ref="button">
おわりに
まだMDCButton+MDCRippleの確認程度までしか出来てませんが、一旦はこれで動作するかと思います。
何かあればコメント等頂ければアップデートして行きたいと思いますので、
よろしくお願いいたします。
尚、筆者はやっと実装に入れるー!と大喜びです。
以上