RevComm Tech Blog

コミュニケーションを再発明し 人が人を想う社会を創る

Vue3へのアップデートにvue-facing-decoratorを利用した話

はじめに

RevComm, Front-end team の熊谷です。今回は vue-facing-decorator を使って Vue2/Nuxt2 のクラスコンポーネントを Vue3/Nuxt3 に移行した話をします。

各コンポーネントでは既存のソースコードを活かせるところも多かったですが、個別に書き換えが必要なところもありましたのでまとめたいと思います。

なぜ vue-facing-decorator を使用したか

弊社の Vue2/Nuxt2 環境では、 nuxt-property-decorator と、vue-property-decorator を使用したクラスコンポーネントを採用していました。nuxt-property-decorator が Nuxt3 への対応をしないことを決定したため、nuxt-property-decorator が推奨している vue-facing-decorator を使用することにしました。

一気に Vue3 の composition api に書き換えることも検討しましたが、ビックバンリリースになってしまうと通常の機能開発との同時並行作業が難しくなってしまうため、クラスコンポーネントのままで一旦最小限のアップデートを目指すことにしました。

各コンポーネントで書き換えが必要だった所

クラス定義

package のアップデートをして Vue と Nuxt の breaking changes に対応後、 まずは、import の書き換えと mixins の書き換えをしました。

// *** vue2 **************************************************
import { Component, mixins } from 'nuxt-property-decorator';

@Component({
  components: {
    SomeComponent,
  },
})
export default class SomePage extends mixins(PageMixin) {

// *** vue3 **************************************************
import { Component, Vue } from 'vue-facing-decorator';

@Component({
  components: {
    SomeComponent,
  },
  mixins: [PageMixin],
})
export default class SomePage extends Vue {

/pages

/pages の下のコンポーネントは head() や layout() といった Nuxt の便利な機能が使えなくなってしまいました( Nuxt 向けではなく Vue 向けのライブラリに移行したため)。

またなぜか /pages の下だけは原因不明のエラーが頻発したため、pages をラップする親を作成したら回避できることがわかりました。

親は /pages とは別ディレクトリに配置し Nuxt の設定を変更して、新しいディレクトリを Nuxt pages のルートとしました。

この方法により、従来の /pages のディレクトリにはギリギリまで vue2 に対する機能追加・変更などを行いつつ、移行作業を安全に進めることができました。

/layouts も同じ問題があったので、同様にしました。

// *** vue3 **************************************************
// nuxt.config.ts
export default defineNuxtConfig({
  dir: {
    pages: 'pagesV3',
    layouts: 'layoutsV3',
  },
  // 以下略
});

// /pagesV3/user/index.vue
<template>
  <User />
</template>

<script lang="ts" setup>
import { useHead } from 'vue';

import User from '@/pages/user/';

useHead(() => ({
  title: 'ページタイトル',
}));
</script>

hooks

created はいい感じに解釈してくれていましたが destroyed は使えなくなっていました。vue3 のライフサイクルに合わせてhooksは変更したほうが良さそうです。

// *** vue2 **************************************************
private created() {
  console.log('created');
}

private destroyed() {
  console.log('destroyed');
}

// *** vue3 **************************************************
private mounted() {
  console.log('mounted');
}

private unmounted() {
  console.log('unmounted');
}

@Emit

nuxt-property-decorator は return を省略可能でしたが、移行後は returnを書く必要がありました。これは細かい内容ですが全体の作業量は多かったです。(でもこちらの方が正しい印象)

// *** vue2 **************************************************
@Emit('change')
private handleTextAreaChange() {}

// *** vue3 **************************************************
@Emit('change')
private handleTextAreaChange(e: Event) {
  return e;
}

Function

nuxt-property-decorator ではアロー関数が使えていましたが vue-facing-decorator では動作しませんでした。(これもこちらの方が正しい印象)

// *** vue2 **************************************************
private created() {
  this.initialize();
}

private initialize = () => {
  console.log('initialize');
};

// *** vue3 **************************************************
private mounted() {
  this.initialize();
}

private initialize() {
  console.log('initialize');
}

今後について

無事に Vue3/Nuxt3 への移行が完了したので、今後は composition api を使って新機能開発をパワーアップさせたいです。 また既存機能も composition api に置き換えて安定した運用をしていきたいです。