Nuxt3 で Vuetify3 を使う

外部モジュールを使うと簡単にできます。

- [Nuxt3 で Vuetify3 + SASS/SCSS を使う (vuetify-nuxt-module 使用)](https://qiita.com/mml/items/5a0f32415440a4212d88)

上記方法は SASS/SCSS も動くことを確認しました。

- [Nuxt3でVuetifyを使えるようにする簡単手順](https://qiita.com/usuijuice/items/985ec44cf138b7304ffd)

この方法は SASS/SCSS の設定がうまくできませんでした（2023/12 現在, Nuxt 3.8.2 / Vuetify 3.4.6）。うまくいく方法があったら教えてください。

そんなわけで、下記の記事はあまり意味がなくなった気はしますが、参考のために残しておきます。

以下の記事は、外部のモジュールに頼らずに Nuxt3 に Vuetify3 を導入する方法について記述しています。SASS/SCSS についても記述しています。

# 主旨

理解は後でいいから、とりあえずコピペで動けばOKという場合は、ページ末尾の「全部盛り」を見てください。

- [The Easy Way to add Vuetify Vue.js 3 Material Components to Your Nuxt 3 / Vue.js 3 Application](https://www.youtube.com/watch?v=DE3HABBzUWY&ab_channel=RazorCXTechnologies)

npm でなく yarn を使ってます。

windows (not WSL) で実行する場合は、yarn や nuxi などのコマンドは、npx 付きで実行します。

たとえば、

```
> npx nuxi init app
> cd app
> npx yarn install
```

こんなかんじです。

# 準備

linx/windows WSL2/mac os でやります。

```
$ npm -v
9.6.7
$ node -v
v16.16.0
$ nuxi -v
Nuxi 3.5.3      
$ yarn -v
1.22.19
```

nuxi がない場合はインストールします。

```
$ sudo npm i -g nuxt@latest
```

# 手順

## アプリの作成とモジュールのインストール

```
$ nuxi init nuxt3-vuetify3-stable
$ cd nuxt3-vuetify3-stable/
$ yarn add vuetify@next
$ yarn add sass
$ yarn install
```
vuetify は `@next` とするか、`@3.8.0` などとバージョンを指定します。記事を書いている時点では、バージョンを指定しないと vuetify@2.x が入ってしまいます。

vuetify のインストール中にバージョンを選択のリストが出たときは、最新版（2023/11時点では3.4.0)を選びます。

## plugins/vuetify.js の追加

```vuetify.js
import { createVuetify } from 'vuetify';
import * as components from 'vuetify/components'

export default defineNuxtPlugin( nuxtApp => {
    const vuetify = createVuetify({
        components
    });

    nuxtApp.vueApp.use( vuetify );
});
```

## app.vue の編集

下記ページにある Basic のところにあるコードをそのまま app.vue にコピペします。

- [Card](https://next.vuetifyjs.com/en/components/cards/)

```app.vue
<template>
<template>
  <v-app>
    <v-container>
      <v-card
        width="400"
        title="This is a title"
        subtitle="This is a subtitle"
        text="This is content"
      ></v-card>

      <div class="mt-4 text-subtitle-2">With slots</div>

      <v-card width="400">
        <template v-slot:title>
          This is a title
        </template>

        <template v-slot:subtitle>
          This is a subtitle
        </template>

        <template v-slot:text>
          This is content
        </template>
      </v-card>

      <div class="mt-4 text-subtitle-2">With markup</div>

      <v-card width="400">
        <v-card-item>
          <v-card-title>This is a title</v-card-title>

          <v-card-subtitle>This is a subtitle</v-card-subtitle>
        </v-card-item>

        <v-card-text>
          This is content
        </v-card-text>
      </v-card>
    </v-container>
  </v-app>
</template>
```

## nuxt.config.ts の編集

```nuxt.consif.ts
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
    css: [
        "vuetify/lib/styles/main.sass"
    ],
    build: {
        transpile: ["vuetify"]
    },
    vite: {
        define: {
            "process.env.DEBUG": false
        },
        // for HMR
        server: {
            watch: {
                usePolling: true
            }
        },
    }
});
```

# テスト

```
$ npm run dev
```

または

```
$ yarn dev
```

これで http://localhost:3000/ にブラウザでアクセスして、下記のようなページが表示されたら成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/dcce1fb4-7700-c6a9-2907-529da7602e7b.png)


# ルーティング機能のテスト

現状の app.vue を pages/index.vue に移動します。

```
$ mkdir pages
$ mv app.vue pages/index.vue
```

新たに app.vue を作ります。

```app.vue
<template>
  <div>
    <NuxtPage />
  </div>
</template>
```

pages/about.vue を下記の内容で作ります。

```pages/about.vue
<template>
    <v-container>
        <h2>{{ title }}</h2>
        <v-btn @click="pushButton">
            PUSH!
        </v-btn>
    </v-container>
</template>
<script>
export default {
    data: () => ({
        title: "This is the test page."
    }),
    methods: {
        pushButton(){
            this.title = "PUSHED!";
        }
    }
}
</script>
```

これで yarn dev しなおします。（HMR だけではエラーになる）

http;//localhost:3000 で表示される内容は、pages/index.vue の中身になるはずです。

http;//localhost:3000/about にアクセスすると、下記のページが表示されるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/77711cae-7ca5-b7cb-73f1-abe3b6cce088.png)

PUSH を押すと、下記のように変わるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b44f40a9-1765-2254-76ed-8ea112fe293a.png)

こんなかんじになれば、正常に動いてます（多分）。

# おまけ

## mdi-font を使う場合

```
$ yarn add @mdi/font
```

としてから、nuxt.config.ts を編集します。

```nuxt.config.ts
    css: [
        "vuetify/lib/styles/main.sass",
        "@mdi/font/css/materialdesignicons.css"
    ],
```

## primary/secondary の色を 2.x と同じにする

vuetify3 のデフォルトのテーマ light の primary / secondary の色は下図のようにになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/043b6a2f-bd90-b2c7-28d0-aa36748a858d.png)

2.x のテーマと同じ色にしたければ、plugins/vuetify.js を下記のようにします。

```vuetify.js
import { createVuetify } from 'vuetify';
import * as components from 'vuetify/components'

export default defineNuxtPlugin( nuxtApp => {
    const vuetify = createVuetify({
        components,
        theme: {
            themes: {
                light: {
                    colors: {
                        primary: '#1976D2',
                        secondary: '#424242',
                        accent: '#82B1FF',
                        error: '#FF5252',
                        info: '#2196F3',
                        success: '#4CAF50',
                        warning: '#FFC107',
                    },
                },
            },
        }
    });

    nuxtApp.vueApp.use( vuetify );
});
```

これで、下記のように色が 2.x のデフォルトと同じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/d47444d8-1860-32ce-bfc9-3ba0c2da901a.png)

- [Vuetify2: テーマの設定](https://vuetifyjs.com/ja/features/theme/#section-30c630fc30de5bfe5fdc)

## Roboto フォントにする

デフォルトでは Roboto フォントが読み込まれないので、2.x とは違うフォントになります。下記は Roboto フォントを使えるようにする方法のひとつです。

### webfontloader を使う

```
$ yarn add webfontloader
```

`plugins/webfontloader.client.js` を作成します。

```plugins/webfontloader.client.js
import webFontLoader from 'webfontloader';

export default defineNuxtPlugin( nuxtApp => {
  webFontLoader.load({
    google: {
      families: ['Roboto:100,300,400,500,700,900&display=swap'],
    },
  })
});
```

これで Roboto フォントになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/59937cd9-d729-24ad-57a2-bfbeacfd1c24.png)

`@nuxt/google-fonts` でもできそうなのですが、nuxt3 でうまく読み込ませられませんでした。わかる方がいましたら教えてください。

# directive

ディレクティブを使う場合は、vuetify.js に追記が必要です。

```vuetify.js
import { createVuetify } from 'vuetify';
import * as components from 'vuetify/components';
import * as directives from 'vuetify/directives';

export default defineNuxtPlugin( nuxtApp => {
    const vuetify = createVuetify({
        components,
        directives,
    });
    nuxtApp.vueApp.use( vuetify );
});
```

- [Vyetify3 Directive: Click outside
](https://next.vuetifyjs.com/en/getting-started/installation/)

# SASS/SCSS を使う

現状 (Nuxt 3.8.2 + Vuetify 3.4.6 の組み合わせで)使うには `vite-vuetify-plugin` を追加する必要があります。

```bash
$ yarn add vite-plugin-vuetify
```

`nuxt.config.ts` に追記します。

```nuxt.config.ts
import vuetify from "vite-plugin-vuetify";
export default defineNuxtConfig({
  ...
  css: [
    "vuetify/styles"
  ],
  hooks: {
    'vite:extendConfig': (config) => {
      config.plugins!.push(
        vuetify({
          autoImport: true,
          styles: {
            configFile: 'styles/settings.scss',
          },
        })
      );
    },
  },
}
```

```styles/settings.scss
@use 'vuetify/settings' with (
  $button-height: 100px,
);
```

これで使えるようになります。ただし `yarn dev` すると大量のワーニングがコンソールに出力されます。このワーニングは、下記のようにすると一応消すことはできます。

```nuxt.config.ts
export default defineNuxtConfig({
  ...
  sourcemap: {
    client: false,
    server: false,
  },
  ssr: false,
```

これだと ssr が無効化されてしまうのですが、ssr を有効にすると、どうしてもワーニングが出ることは避けられないようです。ssr を有効化してもワーニングが出るだけで動作自体には問題はないのですが、気持ち悪くはあります。

なお `ssr: true` としても `yarn build` や `yarn generate` ではワーニングはでないので、気にしなければOKなのかもしれません。

一方で、下記のように `vue` ファイル内にダイレクトに `@use` などを書く方法は、現状うまくいかないようです。

```test.vue
<template>
  <v-container class="h-100">
    <v-btn>
      Test
    </v-btn>
  </v-container>
</template>

<style lang="scss">
@use 'vuetify/settings' with (
  $button-height: 100px,
);
</style>
```

一応、下記を `nuxt.config.ts` に追記し、なおかつ `styles/setting.scss` を使わない場合は動くように見えます。しかし `styles/setting.scss` との共存はどうしてもうまくいかないようです。

```nuxt.config.ts
  experimental: {
    inlineSSRStyles: false
  }
```

こんな感じで SASS/SCSS 周りの動作は怪しいところが多いです。

なお `vuetify-nuxt-module` を使うとこのあたりの問題は（ワーニング出る部分以外は）解決しているようです。SASS/SCSS を使うならその選択肢一択かもしれません。

# 全部盛り

とりあえず Vuetify2 と同じ見た目になれば OK という場合は、下記をコピペすれば幸せになれます（多分）。sass 周りはワーニングが出てしまうので追加してません。必要なら、前述の sass/scss の項目を見て追記してください。

```
$ nuxi init nuxt3-vuetify3-stable
$ cd nuxt3-vuetify3-stable/
$ yarn add vuetify@next sass @mdi/font webfontloader
```

```nuxt.configs.ts
export default defineNuxtConfig({
    css: [
        "vuetify/lib/styles/main.sass",
        "@mdi/font/css/materialdesignicons.css"
    ],
    build: {
        transpile: ["vuetify"]
    },
    
    vite: {
        define: {
            "process.env.DEBUG": false
        },
        // for HMR
        server: {
            watch: {
                usePolling: true
            }
        },
    },
})
```

```plugins/vietify.js
import { createVuetify } from 'vuetify';
import * as components from 'vuetify/components';
import * as directives from 'vuetify/directives';

export default defineNuxtPlugin( nuxtApp => {
    const vuetify = createVuetify({
        components,
        directives,
        theme: {
            themes: {
                light: {
                    colors: {
                        primary: '#1976D2',
                        secondary: '#424242',
                        accent: '#82B1FF',
                        error: '#FF5252',
                        info: '#2196F3',
                        success: '#4CAF50',
                        warning: '#FFC107',
                    },
                },
            },
        }
    });

    nuxtApp.vueApp.use( vuetify );
});
```

```plugins/webfontloader.client.js
import webFontLoader from 'webfontloader';

export default defineNuxtPlugin( nuxtApp => {
  webFontLoader.load({
    google: {
      families: ['Roboto:100,300,400,500,700,900&display=swap'],
    },
  })
});
```

# 関連記事

- [Vuetify3 beta のレイアウトに関するメモ](https://qiita.com/mml/items/7bdffe5eb5044f861cf1)
- [Vuetify3 beta でよく使うコンポーネントのメモ（１）](https://qiita.com/mml/items/ec0a4c63f9d29d8c0203)
- [Vuetify3 beta でよく使うコンポーネントのメモ（２）](https://qiita.com/mml/items/16030c4404b4a814956b)

# つぶやき

nuxt で開発するなら、作業用のディスクは SSD (できれば PCIe) を使うことを強くお勧めします（HDDだと非常に遅いです。