はじめに
2022年4月頃に見たら、Vuetify 3がそろそろリリース予定(当時は2022年6月予定と書かれていたような)だったので、Vue 3をぼちぼち触り始めたのですが、なかなかリリースされませんね。。。
ドキュメンテーションに時間がかかっているのでしょうか。
痺れを切らしたので、まだBeta版ですが使い始めてみました。
Vue 2 の頃のコードのコピペでは上手くいかなかったところをメモしておきます。
インストール
Vite / Vue3 でセットアップ済のプロジェクトに Vuetify 3 を後から追加してます。
$ vue add vuetify
いくつかファイルの追加や上書きがされています。
$ git status
On branch add_vuetify
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: index.html
modified: package-lock.json
modified: package.json
modified: src/App.vue
modified: src/main.ts
modified: vite.config.ts
Untracked files:
(use "git add <file>..." to include in what will be committed)
src/assets/logo.svg
src/components/HelloWorld.vue
src/plugins/vuetify.ts
src/plugins/webfontloader.ts
src/views/HomeView.vue
no changes added to commit (use "git add" and/or "git commit -a")
特に上書きされているものは、元のコードが消されてしまっていたりするので要修正でした。
{
"name": "firebase-test",
"private": true,
"version": "0.0.0",
"scripts": {
"serve": "vite preview", // 追記されたが、previewと被ってるので後から削除した
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",
"preview": "vite preview",
"test": "vitest"
},
"dependencies": {
"@mdi/font": "5.9.55", // 追記された
"firebase": "^9.8.3",
"roboto-fontface": "*", // 追記された
"vue": "^3.2.25",
"vue-router": "^4.0.16",
"vuetify": "^3.0.0-beta.0", // 追記された
"webfontloader": "^1.0.0" // 追記された
},
"devDependencies": {
"@testing-library/vue": "^6.6.1",
"@types/webfontloader": "^1.0.0", // 追記された
"@vitejs/plugin-vue": "^3.0.3",
"@vue/test-utils": "^2.0.2",
"jsdom": "^20.0.0",
"typescript": "^4.5.4",
"vite": "^3.0.8", // アップデートされた
"vite-plugin-vuetify": "^1.0.0-alpha.12", // 追記された
"vitest": "^0.22.1",
"vue-cli-plugin-vuetify": "~2.5.5", // 追記された
"vue-tsc": "^0.29.8"
}
}
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin
import vuetify from 'vite-plugin-vuetify' // 追記された
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
vuetify({ autoImport: true }), // 追記された
],
})
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // named exportにしてたらdefault export前提({}なし)に変えられたので後から調整した
import vuetify from './plugins/vuetify' // 追記された
import { loadFonts } from './plugins/webfontloader' // 追記された
loadFonts() // 追記された
createApp(App) // 自作pluginのuseが消されてしまったので後から追記した
.use(router)
.use(vuetify)
.mount('#app')
// まるっと以下に置き換わってたので後から修正した
<template>
<v-app>
<v-main>
<router-view/>
</v-main>
</v-app>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'App',
data () {
return {
//
}
},
})
</script>
また、実行すると以下のWARNが出力されました。
DevTools がソースマップの読み込みに失敗しました(http://localhost:5173/materialdesignicons.css.map のコンテンツを読み込めませんでした(HTTP エラー: ステータス コード 404、net::ERR_HTTP_RESPONSE_CODE_FAILURE))
これは以下を追記したら解消しました。
export default defineConfig({
plugins: [
vue(),
vuetify({ autoImport: true }),
],
// 以下追加
css: {
devSourcemap: true,
},
})
Upgrade Guide
ドキュメントに少しだけガイドの記載があったので確認しましたが、やけに少ないので、今後追記されていくのでは。
Components
# General changes
- light and dark props have been removed from all components. Use theme prop instead
- value prop has been replaced by model-value on components that support
v-model
usage- @input event has been replaced by @update:model-value on components that support
v-model
usage# v-alert
- border prop values
left
andright
have been replaced bystart
andend
- colored-border prop has been replaced by border-color
- dismissable prop has been replaced by closeable
- outlined and text props have been replaced by single prop variant
- text prop has new purpose. It represents the text content of the alert, if default slot is not used
# v-app
- id prop has been removed
https://next.vuetifyjs.com/en/getting-started/upgrade-guide/#general-changes
-
light
やdark
を使ってた部分は、個別の色の設定はやめてthemeベースで設定するように変えました。 -
v-alert
に限らず、dismissable
→closable
の変更やvariant
でのタイプ指定はよく出てきました。
[Vue warn]: Failed to resolve component
Vuetify 3 では削除されたり置き換わったcomponentを使用しているとWARNが出たので、1つ1つ修正していきました。例えば以下。
-
v-content
-
v-main
に置き換え。以前からdeprecatedになってたらしい。
-
-
v-flex
-
v-row
,v-col
に置き換え。
-
-
v-list-item-content
- titleやsubtitleは、代わりに
v-list-item
の直下に記述したり、v-list-item
のプロパティとして指定。
- titleやsubtitleは、代わりに
Formのバリデーション
Vue 2 の頃はこんな感じで書いていました。
<template>
...
<v-form ref="form">
...
</v-form>
...
</template>
<script lang="ts">
import { Vue, Component, Emit } from 'vue-property-decorator';
type VForm = Vue & {
validate: () => boolean;
reset: () => void;
resetValidation: () => void;
};
@Component({})
export default class ItemForm extends Vue {
...
public $refs!: {
form: VForm;
};
private submitItem(): void {
if (this.$refs.form.validate()) {
this.submit(this.item));
}
}
@Emit('submit')
private submit(item): void {
this.$refs.form.resetValidation();
}
}
</script>
setupだとthisが使えないので、validateなどをどう呼ぶのかな?と思いましたが、setup内でrefで定義した変数をv-formのrefプロパティにセットすればよいようです。
<script setup lang="ts">
import { ref } from 'vue';
import { useItem } from '../composables/useItem';
const { submit } = useItem();
const item = ref('');
const form = ref();
const onSubmit = async () => {
const result = await form.value.validate();
if(result.valid) {
submit(item.value);
form.value.reset();
}
};
</script>
<template>
...
<v-form ref="form">
...
</v-form>
...
</template>
バンドルサイズが大きい
Vuetify対応後にビルドすると以下のWARNが出ました。
$ npm run build
> firebase-test@0.0.0 build
> vue-tsc --noEmit && vite build
vite v3.1.0 building for production...
✓ 368 modules transformed.
dist/assets/materialdesignicons-webfont.9bdfaf27.eot 1002.34 KiB
dist/assets/materialdesignicons-webfont.da7fba3c.woff2 317.62 KiB
dist/assets/materialdesignicons-webfont.8bded8f4.woff 454.29 KiB
dist/assets/materialdesignicons-webfont.c14484cf.ttf 1002.13 KiB
dist/index.html 0.42 KiB
dist/assets/webfontloader.b777d690.js 12.42 KiB / gzip: 4.98 KiB
dist/assets/index.63c32017.css 573.56 KiB / gzip: 82.09 KiB
dist/assets/index.1005b1e3.js 628.15 KiB / gzip: 173.54 KiB
(!) Some chunks are larger than 500 KiB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/guide/en/#outputmanualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
ちなみにVuetifyを入れる前は以下です。
$ npm run build
> firebase-test@0.0.0 build
> vue-tsc --noEmit && vite build
vite v3.1.0 building for production...
✓ 97 modules transformed.
dist/index.html 0.36 KiB
dist/assets/index.e91a8232.js 466.58 KiB / gzip: 121.12 KiB
気にしてませんでしたが、もともと結構大きかったようです。
以下を参考に確認したところ、Firebaseまわりが大きすぎですね。。。
https://miyauchi.dev/ja/posts/firebase-bundle-size/
https://zenn.dev/meijin/articles/vite-bundle-analyzer
Firestore Liteというのもあるようですが、リアルタイムアップデートが使えないのが厳しいです。
https://firebase.google.com/docs/firestore/solutions/firestore-lite
とは言え、materialdesignicons-webfont
もかなり大きいので、以下を参考に、アイコンは必要なものだけ個別にimportするようにしてみました。
https://next.vuetifyjs.com/en/features/icon-fonts/#material-design-icons-js-svg
$ npm i -D @mdi/js
// まずこれを削除。冒頭のソースマップの設定も不要になる
// import '@mdi/font/css/materialdesignicons.css'
// Styles
import 'vuetify/styles'
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg' // 追加
// Vuetify
import { createVuetify } from 'vuetify'
export const vuetify = createVuetify({
// 以下を追加
icons: {
defaultSet: 'mdi',
aliases,
sets: {
mdi,
},
},
});
各コンポーネントで使用するアイコンをimportします。
<script setup lang="ts">
import { mdiDelete } from '@mdi/js'; // これを追加
import { Item } from '../domain/models/Item';
import { useItem } from '../composables/useItem';
const props = defineProps<{
item: Item
}>();
const { deleteItem } = useComic();
</script>
<template>
<v-list-item>
<v-list-item-title>
{{ item.name }}
</v-list-item-title>
<template v-slot:append>
<v-btn
icon
variant="plain"
@click.stop="deleteItem(comic)"
>
<!-- <v-icon>mdi-delete</v-icon> -->
<v-icon>{{ mdiDelete }}</v-icon>
</v-btn>
</template>
</v-list-item>
</template>
修正後のビルド結果です。
$ npm run build
> firebase-test@0.0.0 build
> vue-tsc --noEmit && vite build
vite v3.1.0 building for production...
✓ 369 modules transformed.
dist/index.html 0.42 KiB
dist/assets/webfontloader.b777d690.js 12.42 KiB / gzip: 4.98 KiB
dist/assets/index.b127324a.css 311.74 KiB / gzip: 38.67 KiB
dist/assets/index.aa7ed990.js 633.31 KiB / gzip: 175.68 KiB
(!) Some chunks are larger than 500 KiB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/guide/en/#outputmanualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
materialdesignicons-webfont
はなくなりましたが、メインのバンドルはアイコンを組みこんだせいか更に大きくなりましたね。
あとはviewの単位でdynamic importにしたりすれば、viewごとにファイルが分割されて、1ファイルあたりのサイズは小さくなりますが、シンプルなアプリだとあまり分けられる要素もなく、なかなか500KBはきれませんでした。。。
やはりFirebaseが大きい。
単に上記のWARNを出さなくするだけであれば、メッセージ記載のとおり、build.chunkSizeWarningLimit
を上げればよいのですが、根本的な解決ではないので微妙なところです。ビルドエラーになるわけではないので、いったんそのままにしました。
おわりに
シンプルなアプリで試したので、あまり使いこめてはいませんが、それほど大きな変更の印象はなかったです。
ただ、まだドキュメントが出揃っておらず、APIリファレンスへのリンクもほぼ404だったりするので、細かいプロパティ設定の仕方などは調べづらかったです。それでも2.0と同じように設定すれば大体動いたりしました。
正式リリース時に大きな変更が発生したりしなければ大丈夫そうな気がします。