Vue3 + Viteでmaterial iconを使う

みんな大好きmaterial design icon(マテリアルアイコン) をVue3とViteの環境で使ってみたので、その備忘録。

Vite .config.jsに追記するのかと思っていたら、不要でした。
やり方は全部こちらに書いてありますが、一応。

https://www.npmjs.com/package/vue-material-design-icons

アイコンはこちらから探せます。

https://materialdesignicons.com/

インストール

npm i vue-material-design-icons

yarnの場合

yarn add vue-material-design-icons

インポート

import MenuIcon from 'vue-material-design-icons/Menu.vue';

components: {
  MenuIcon;
}

グローバルの場合

import MenuIcon from 'vue-material-design-icons/Menu.vue';

Vue.component('menu-icon', MenuIcon);

描画

<menu-icon />

vue3 componentの読み込み方

親要素からcomponent(コンポーネント)を読み込むときの手順を、復習。

まずは子componentを作成

コンポーネントはキャメルケース。
component/ChildComponent.vue

<template>
  <div class="child_component">
    <h2>This is child component</h2>
  </div>
</template>

読み込む親要素で<script>内にimportし、componentを記載する。

script内もキャメルケース。
views/Parent.vue

<script>
import ChildComponent from '@/components/ChildComponent.vue'

export default {
  name: 'parent',
  components: {
    ChildComponent,
  },
}
</script>

読み込む親要素で描画箇所を記述

描画箇所はスネークケース

<template>
  <div class="parent">
    <h1>Parent page</h1>
    <child-component></child-component>
  </div>
</template>

トラブルシューティング

親のパスは通っていますか?

router/index.jsに親を登録していないと、/parentのuriでページが見られません。

import { createRouter, createWebHistory } from 'vue-router'
import Parent from '../views/Parent.vue'


const routes = [
  {
    path: '/parent',
    name: 'parent',
    component: Parent,
  },
]

const router = createRouter({
  history: createWebHistory(),
  routes,
})

export default router

viteを使っていますか?

Viteを使用し、@でパスの指定をしたい場合は、別途設定が必要です。
vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

[vue3]main.jsでの.use()つなぎ方によるエラー

Vue3 + viteでvuexの設定をいじっている時に、エラーが出たのでその備忘録。
エラー文
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘state’)
↑を解決した後に、

Uncaught RangeError: Maximum call stack size exceeded

という別のエラーが出ました。一難去ってまた一難。

結論から言うと、main.jsのcreateApp(App).use()のチェーンの仕方が悪かったようです。

バージョン

  • MacOS
npm list
├── @vitejs/plugin-vue@3.2.0
├── axios@1.1.3
├── node-sass@7.0.3
├── sass-loader@10.3.1
├── sass@1.55.0
├── vite@3.2.1
├── vue-axios@3.5.2
├── vue-router@4.1.6
├── vue@3.2.41
└── vuex@4.0.2

エラーの出たコード01

.useで使うプラグインを全て1つの()に入れ、コンマで区切っています。

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
import VueAxios from 'vue-axios'

createApp(App).use(router, store, VueAxios, axios).mount('#app')

この際に出たエラー文

Home.vue:5 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'state')
    at Proxy._sfc_render (Home.vue:5:20)
    at renderComponentRoot (runtime-core.esm-bundler.js:898:44)
    at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:5631:57)
    at ReactiveEffect.run (reactivity.esm-bundler.js:187:25)
    at instance.update (runtime-core.esm-bundler.js:5745:56)
    at setupRenderEffect (runtime-core.esm-bundler.js:5759:9)
    at mountComponent (runtime-core.esm-bundler.js:5541:9)
    at processComponent (runtime-core.esm-bundler.js:5499:17)
    at patch (runtime-core.esm-bundler.js:5101:21)
    at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:5711:17)

stateがどうこう言われているので、一旦routerとstoreを引き離してみる。

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
import VueAxios from 'vue-axios'

createApp(App).use(router).use(store, VueAxios, axios).mount('#app')

これでエラーは消えます。

stackoverflowの回答者によれば、.useの引数は1番目は1つのみで、2番目以降はおまとめできるとのことでした。

the use method accept one plugin as first parameter and options (which si optional) as second one app.use(plugin, itsOptions)

Vuex Cannot read property ‘state’ of undefined


ちなみに全部.use()のチェーンを分けて記載すると、別のエラーが出ました。

Uncaught RangeError: Maximum call stack size exceeded
    at isPlainObject (utils.js:129:23)
    at assignValue (utils.js:287:9)
    at forEach (utils.js:261:10)
    at merge (utils.js:299:21)
    at assignValue (utils.js:290:21)
    at forEach (utils.js:261:10)
    at merge (utils.js:299:21)
    at assignValue (utils.js:290:21)
    at forEach (utils.js:261:10)
    at merge (utils.js:299:21)

実験してみると、2つ目のエラーは分けたことが原因なのではなく、VueAxios, axiosの順番で読み込まないといけないということだったみたいです。
NG

createApp(App).use(router).use(store).use(axios).use(VueAxios).mount('#app')

NG

createApp(App).use(router).use(store).use(axios, VueAxios).mount('#app')

OK

createApp(App).use(router).use(store).use(VueAxios, axios).mount('#app')

axiosとstoreは一緒に入れても問題ないようでしたが、気持ち悪いので分けました。

[Vue.js]続・Viteを導入してみる

以前の記事でvueでviteを導入する方法を書いたのですが、

https://nolyc.net/programming/vuejs-install-vite/(新しいタブで開く)

npm create vite でプロジェクト作成した時はstoreやらrouteやらを自分で入れなければいけないみたいですね。というわけで続編です。`npm create vite@latest`した後の、routerやvuex(store), axiosなどの追加方法を書いています。

# npm 6.x
npm create vite@latest

Vue routerの設定

vue3の場合は、v4をインストール

 npm install vue-router@4

srcディレクトリ下に、routerディレクトリを作成

routerディレクトリ内にindex.jsを作成し、以下を記述。
まず、createRouter、createWebHistoryをインポート。createRouter()で、ルーティング情報を扱うルータの生成ができるようになる。history設定にはcreateWebHistory()を定義する。

参考 
Vue Routerとは
[Vue.js] vue-routerのhashモードとhistoryモードの違いをざっくり理解する

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import Profile from '../views/Profile.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home,
  },
  {
    path: '/profile',
    name: 'profile',
    component: Profile,
  },
]

const router = createRouter({
  history: createWebHistory(),
  routes,
})

export default router

main.jsに追記

エントリポイントとなるJavaScriptファイルに記述を追加する src/main.js

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

# Vue.jsにVue Routerを導入して、タグで画面遷移する方法!
# 今さら聞けない?Vue Router

storeの設定

npm install vuex@next --save

storeディレクトリの作成

src/store/index.jsを作成。

import { createStore } from 'vuex'
export default createStore({
  state: {},
  getters: {},
  mutations: {},
  actions: {},
  modules: {},
})

参考 # Vuexのインストール
注 store > index.jsの中でexport default しているのにmain.jsで { store }としたらだめです
参考 The requested module does not provide an export named in JS

main.jsに追記

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App).use(router, store).mount('#app')

axiosの設定

npm install --save axios vue-axios

main.jsに追記

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
import VueAxios from 'vue-axios'

createApp(App).use(router, store, VueAxios, axios).mount('#app')

ほか追加する場合

好みで

Prettier

.prettierrcというファイルをプロジェクトフォルダ直下に作成。
おすすめ設定↓

{
  "semi": false,
  "arrowParens": "always",
  "trailingComma": "es5",
  "singleQuote": true,
  "quoteProps": "preserve",
  "endOfLine": "auto"
}

eslint

npm i&nbsp;eslint-plugin-vue
npm install eslint

プロジェクトファイル直下に設定ファイルを作成

module.exports = {
  root: true,
  env: {
    node: true,
  },
  'extends': ['plugin:vue/vue3-essential', 'eslint:recommended'],
  parserOptions: {
    parser: '@babel/eslint-parser',
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
  },
}

scssを導入

sass-loaderのv11.0.0以降はwebpackのバージョン5以上しか対応していないようなので、Viteでプロジェクト作成した際はsass-loader v10をインストール
https://zenn.dev/itouuuuuuuuu/articles/284c8420d835ed

npm install --save-dev sass sass-loader@10

参考 https://amg-solution.jp/blog/25614

Viteを利用していない場合は、webpackのバージョン確認の上、該当するsass-loaderを導入しよう。
https://zenn.dev/itouuuuuuuuu/articles/284c8420d835ed

npm list webpack
my-vue-project@0.1.0 /Users/neko/Documents/my-vue-project
├─┬ @vue/cli-plugin-babel@5.0.8
│ ├─┬ babel-loader@8.2.5
│ │ └── webpack@5.74.0 deduped
│ ├─┬ thread-loader@3.0.4
│ │ └── webpack@5.74.0 deduped
│ └── webpack@5.74.0
├─┬ @vue/cli-plugin-eslint@5.0.8
│ ├─┬ eslint-webpack-plugin@3.2.0
│ │ └── webpack@5.74.0 deduped
│ └── webpack@5.74.0 deduped
└─┬ @vue/cli-service@5.0.8
  ├─┬ @soda/friendly-errors-webpack-plugin@1.8.1
  │ └── webpack@5.74.0 deduped
  ├─┬ @vue/vue-loader-v15@npm:vue-loader@15.10.0
  │ └── webpack@5.74.0 deduped
  ├─┬ copy-webpack-plugin@9.1.0
  │ └── webpack@5.74.0 deduped
  ├─┬ css-loader@6.7.1
  │ └── webpack@5.74.0 deduped
  ├─┬ css-minimizer-webpack-plugin@3.4.1
  │ └── webpack@5.74.0 deduped
  ├─┬ html-webpack-plugin@5.5.0
  │ └── webpack@5.74.0 deduped
  ├─┬ mini-css-extract-plugin@2.6.1
  │ └── webpack@5.74.0 deduped
  ├─┬ postcss-loader@6.2.1
  │ └── webpack@5.74.0 deduped
  ├─┬ progress-webpack-plugin@1.0.16
  │ └── webpack@5.74.0 deduped
  ├─┬ terser-webpack-plugin@5.3.6
  │ └── webpack@5.74.0 deduped
  ├─┬ vue-loader@17.0.0
  │ └── webpack@5.74.0 deduped
  ├─┬ webpack-dev-server@4.11.1
  │ ├─┬ webpack-dev-middleware@5.3.3
  │ │ └── webpack@5.74.0 deduped
  │ └── webpack@5.74.0 deduped
  └── webpack@5.74.0 deduped

5以上なら普通にインストールすればOK。
5以下なら、前述の通りsass-loader v10をインストール(npm install –save-dev sass sass-loader@10)。

npm install sass-loader node-sass --save-dev

参考  https://amg-solution.jp/blog/25614

errror ## TypeError: this.getOptions is not a functionが出る場合はバージョンを下げる

npm install sass-loader@10.1.1

scss書く時は<style lang="scss">とすればOK。
諸々追加した後はpackage.jsonで追加されているかを確認できます

{
  "name": "my-recipe-app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "vue": "^3.2.41",
    "vue-router": "^4.1.6",
    "vuex": "^4.0.2"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^3.2.0",
    "node-sass": "^7.0.3",
    "sass": "^1.55.0",
    "sass-loader": "^10.3.1",
    "vite": "^3.2.0"
  }
}

ほか参考

Vite

[Vue.js]Viteを導入してみる

早い早いと話題のVite(ヴィート)。フランス語で「素早い」の意味らしいです。
Webpackではアプリケーション起動前に、アプリ全体を走査し依存を解決→バンドルしたソースを出力という流れだったのに対し、ViteはNative ESModulesのimportを利用し、ブラウザから直接モジュールを読み込むことで高速化を実現しています。

モジュールバンドラーRollup を使用してコードをバンドル…とあるので、ノーバンドルツールと言われつつもバンドルしない訳ではないようです。

この辺りの解説はANTEZさんの記事やっぱりwebpackがわからない(エピソード1)が超絶わかりやすかったです。

プロジェクト作成

前提

Viteを使うには、Node.jsが14.18+、16+でなければなりません。

% cd projects
% npm create vite@latest
Need to install the following packages:
  create-vite@3.2.0
Ok to proceed? (y) y
✔ Project name: … vite-app
✔ Select a framework: › Vue
✔ Select a variant: › JavaScript

Scaffolding project in /Users/meow/Documents/projects/vite-app...

プロジェクト名や使用するテンプレートはオプションでも指定可能。

# npm 6.x
npm create vite@latest my-vue-app --template vue

とりあえず起動

npm install
npm run dev

テーン!!

後からわかったのですが、`npm create vite’でプロジェクト作成した時はstoreやらrouteやらを自分で入れなければいけないみたいですね。というわけでこちらにまとめました。

Vite / vue.js / vue3

ほか参考

Vite