9
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vuetifyとの上手い付き合い方

Last updated at Posted at 2023-12-11

WEMEX株式会社 Advent Calendar 2023の12日目の記事です。
Vueで利用されるUI Framework Vuetifyが2023−11にv3.4 (Blackguard)をリリースしました。
Labsだったコンポーネントも大分少なくなり、ある程度安定して使える様になってきた印象です。
そこで、プロダクトでVuetify3を利用するにあたって、こんな調整をすれば使い勝手がよくなりますよ、といったチップスを紹介したいと思います。

利用しないコンポーネントをバンドル対象から除外する

Vuetifyでは多様なコンポーネントが用意されていますが、プロジェクトで全てのコンポーネントを利用するケースそうそうないと思います。
使うコンポーネントが限られた状態でいざビルドすると、利用しないコンポーネントも一緒にバンドルされてしまい、結果ファイルサイズが肥大化してしまいます。

// src/plugins/vuetify.ts

// Treeshakingする前
// デフォルトはこの様な形で呼び出していると思います

import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'

const vuetify = createVuetify({
  components,
  directives,
})

export default vuetify

その状態を防ぐために Treeshaking(不要コードの除去)する設定を入れましょう。

利用するモジュールバンドラに合わせて必要なプラグイン(viteならvite-plugin-vuetify)を導入します。

// vite.config.ts

import vue from '@vitejs/plugin-vue'
import vuetify from 'vite-plugin-vuetify'  // プラグインのimport

export default {
  plugins: [
    vue(),
    vuetify(),  // 追加
  ],
}
// src/plugins/vuetify.ts
// Treeshakingした後

import 'vuetify/styles'
import { createVuetify } from 'vuetify'

const vuetify = createVuetify()

export default vuetify

このように設定すればビルドしたときに実際に利用しているコンポーネントのみをバンドル対象にすることが可能になります。

コンポーネントのスタイルを調整

プロダクトで表現するUIデザインはデザイナーと協業しながら作っていくことが多いと思います。
そのため、純粋なVuetifyのコンポーネントをそのまま利用すると言うよりは、微妙な調整をしながらプロダクトにあったコンポーネントへ最適化することが多いのではないでしょうか。

幸いなことにVuetifyの各コンポーネントでは上書き可能なSASS変数を公開しています。
この変数を書き換えることでコンポーネントのスタイルを調整することが可能です。

この作業をするにはTreeshakingの設定が済んでいる必要があります

任意のディレクトリにSASS変数を定義するファイルを作成します

// src/styles/settings.scss

@use 'vuetify/settings' with (
  $button-height: 40px,
);

モジュールバンドラの設定ファイルに読み込むSASSファイルを指定します

// vite.config.ts

import vue from '@vitejs/plugin-vue'
import vuetify from 'vite-plugin-vuetify'

export default {
  plugins: [
    vue(),
    vuetify({
      styles: {
        configFile: 'src/styles/settings.scss',  // SASS変数定義ファイルを指定
      }
    }),
  ],
}

この状態で v-btn を利用するとボタンの高さが40pxになります。
他のSASSに関しても同様にコンポーネントのAPIページを参照しながらスタイルを調整することが可能になります。

ただし、ボタンは直感通りに変更することが可能ですが、中には変更するのに一手間工夫が必要も存在します。

v-text-fieldの調整

中でも分かりにくいのは v-text-field ではないかと思います
(私は結構ハマりました。。。)

デフォルトの高さを狭めたいと思い調整しようとしてもAPIページにそれらしいSASSが公開されておらず。。かと言ってPropsで指定するパターンでもなく。直接スタイルを変更するとデザインが崩れる状態でした。

で、泣く泣くコンポーネントのコード覗いてみると内部ではv-inputv-fieldが使われていました。

つまり、v-text-field の調整には v-inputv-field の変数を調整する必要があったのです!(公式に記載されていないので分かり辛い!)

以下のような形で変数を調整した場合、デフォルトの高さは44pxに変更されます。

// src/styles/settings.scss

@use 'vuetify/settings' with (
  $input-control-height: 44px,  // inputの高さを指定
  $field-input-padding-top: 8px, // inputpadding top/bottom を調整
  $field-input-padding-bottom: 8px,
);

SASSがまったく公開されていない場合

それでも調整できそうもない場合はdeepセレクターを利用して直接スタイルを更新します。

個人的にdeepセレクターは最終手段だと思っています。
実装の内部情報であるクラス名をから辿ることになるめた、バージョンアップなどでクラス名が少しでも変更されるとスタイル適用されません。
そのため、利用する際も必要最低限に留めたほうがよいでしょう。

コンポーネントのグローバル設定を変更

コンポーネントのデフォルトPropsやスタイルクラスを明示的に指定することができます。

// src/plugins/vuetify.ts

import { createApp } from 'vue'
import { createVuetify } from 'vuetify'

export default createVuetify({
  defaults: {
    VBtn: {
      variant: 'outlined'  // v-btnを使った時のデフォルトがoutlinedになる
    },
  },
})

この調整を入れることで利用する側で同じ様なPropsやスタイルを適用する必要がなくなります。

プロダクトで利用するコンポーネントのデフォルトの形が見えてきた段階で、適した形に設定すればDXが向上すると思います。
※こいった設定はエンジニアの判断だけで操作するのではなくデザインと認識を合わせながら進めたほうがお互いのためになるのではないかと考えます。(独断で設定しても後から違う!となり得るので。。。)

まとめ

以上、3つ紹介させていただきました。まとめると

  • バンドルモジュールのサイズを最適化するためにTreeshakingをしよう
  • コンポーネントのSASS変数を調整してプロダクトにあったスタイルに整えよう
  • コンポーネントの標準的な使い方が見えたらグローバルな設定で調整しよう

になります!
それでは、良きフロントエンド開発を🤟🤟🤟

9
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?