vuetify

Volar で Vuetify2.x の補完を効かせる

Volar + Vuetify 2.x を利用する場合、型定義ファイルを作成してグローバルコンポーネントを定義する必要があります。

先日 Vue2.7 がリリースされたので早速アップデートしてきました。

Vue2.7 では 3.x の機能である Composition API やscript setup がバックポートされており、3.x にすぐにアップデートできないプロジェクトでも最新の構文を使用できます。

さらに 2.7 では依存関係の追加なしで Volar をサポートしています。

https://github.com/vuejs/vue/blob/main/CHANGELOG.md#volar-compatibility

Volar は template 内での型サポートがあるなど、Vuter よりもさらに高い開発者体験を提供してくれます。早速 Volar を導入してみたのですが、1 つ問題が発生しました。

Vuetify の補完が効かない

Vuter から Volar に移行した際に Vuetify の補完が効かなくなるという問題が発生しました。以下の Issue によると Vuetify 2.x では Volar のサポートを提供する予定はないようです。

Yes this is only v3, for v2 you need to use vetur instead.

というわけで、自力で Vuetify の型定義ファイルを作成する必要があります。

Volar でグローバルコンポーネントを定義する

Vuetify の補完が効かない理由としては、Vuetify のコンポーネントがグローバルコンポーネントとして登録されているためです。これを解決するためには型定義ファイルを作成して Volar にグローバルコンポーネントが存在することを教えてあげる必要があります。

Volar でグローバルコンポーネントを定義する方法は以下のように記載があります。

Define Global Components PR: https://github.com/vuejs/vue-next/pull/3399

Local components, Built-in components, native HTML elements Type-Checking is available with no configuration.

For Global components, you need to define GlobalComponents interface, for example:

// components.d.ts
declare module '@vue/runtime-core' {
  export interface GlobalComponents {
    RouterLink: typeof import('vue-router')['RouterLink']
    RouterView: typeof import('vue-router')['RouterView']
  }
}
 
export {}

まずは d.ts ファイルを作成します。ここで declare module '@vue/runtime-core' {} を宣言し、GlobalComponents を拡張してあげればよいわけです。

もし Vue 2.6.14 <= を使っている場合には @vue/runtime-core の代わりに @vue/runtime-dom と記載します。

上記の構文に従って Vuetify に存在するコンポーネントを記述していけばよいわけなのですが、1 つづつ手作業で行うのは骨が折れます。

有志の方が Vuetify の型定義を作成するスクリプトを作成しているので、ありがたく使わせていただきましょう。

// ./scripts/vuetify-type.mjs
import webTypes from 'vuetify/dist/json/web-types.json' assert { type: 'json' }
 
const blackList = ['VFlex', 'VLayout'] // Components not to define in global
 
function convertType(typeStr) {
  switch (typeStr) {
    case 'array':
      return 'any[]'
    case 'function':
      return 'Function'
    case 'date':
      return 'Date'
    case 'regexp':
      return 'RegExp'
    default:
      return typeStr
  }
}
 
function getType(attrType) {
  if (typeof attrType === 'string') {
    return convertType(attrType)
  } else {
    return attrType.map((str) => convertType(str)).join('|')
  }
}
 
const types = webTypes.contributions.html.tags
  .map((vm) =>
    !blackList.includes(vm.name)
      ? vm.name +
        ': DefineComponent<{' +
        vm.attributes
          .map(
            (attr) =>
              (attr.description ? `/** ${attr.description} */\n` : '') +
              `${attr.name.replace(/-./g, (x) =>
                x[1].toUpperCase()
              )}?: ${getType(attr.value.type)}`
          )
          .join('\n') +
        '}>'
      : ''
  )
  .join('\n')
 
console.log(`
import type { DefineComponent } from '@vue/runtime-dom'
import type { DataTableHeader, DataOptions } from 'vuetify'
 
declare module '@vue/runtime-dom' {
  export interface GlobalComponents {
    ${types}
  }
}
 
export {}`)

注意点として、Vue 2.7.0 <= の場合には '@vue/runtime-dom''@vue/runtime-dom' に置換する必要があります。

後は上記のスクリプトを実行してプロジェクトに型定義ファイルを配置すれば、Vuetify のコンポーネントの補完が効くはずです。

node ./scripts/vuetify-type.mjs > ./src/vuetify2.d.ts

トラブルシューティング

スクリプト実行後も変化がない

Ctrl+Shift+P で command palette 表示し、Restart Vue Server を実行してください。

スクリーンショット 2022-07-10 14.44.29

Vuetify のコンポーネントの型が any になる

スクリプト実行後、コンポーネント名は補完されるものの型が any となっていて Props や Emit の型が効かなくなることがあります。

そのような場合はおそらく Vue CLI によって自動生成された src/shims-tsx.d.ts ファイルを削除すれば大丈夫なはずです。

Volar の説明でも Vue CLI によって自動生成されたファイルを削除するように記載があります。

remove .d.ts files if they exist. For projects generated by the Vue CLI, .d.ts files are included. Remove these files.

rm src/shims-tsx.d.ts src/shims-vue.d.ts

スクリプトの実行がエラーになる

Node.js v16.14.0 <= にアップデートしてください。

スクリプトでは import assersion 構文を使用しているためです。


Contributors

> GitHub で修正を提案する
この記事をシェアする
はてなブックマークに追加

関連記事