ハードルを下げ続けるブログ@task

常に低い意識で投稿していきたいエンジニアのブログ。当ブログの内容は、個人の見解であり所属する組織の公式見解ではありませんよ。

Nuxt で Vue 3.0 (Composition-API) を使いたいとき

ja.nuxtjs.org

composition-api.nuxtjs.org

Vue3.0 がリリースされてからしばらく立ちましたが、Nuxt において Vue3.0 がサポートされた v3.0 がリリースされるのはもうちょっとかかりそうです。

とはいえ、v3.0 がリリースされるのを待って、無理やりバージョンをあげようとしてもおそらく、かなりの痛みを伴うことが、他の皆様のVue3.0移行記事からも読み取れます。

そこで、Vue 3.0 リリースより少し前から、既存の Nuxt Project に composition-API を導入した所感と、導入方法を記録しておきます。

というか、この過渡期においてNuxtへの Composition-API 導入についての日本語記事があまり見当たらなかったので、少しでも参考になれば幸いです。

なお、バージョンは記事公開時点の最新とします。

Nuxt.js v2.14.12
@nuxtjs/composition-api v0.17.0

Motivation

  • Vue 3.0 (Nuxt v3) にスムーズに移行できるように準備する
  • Composition-API を使いたい
  • TypeScript をより使いやすくしたい

Composition-API の導入

@nuxtjs/composition-api を使います。 少し古い記事だと、@vue/composition-api を導入している記事が多いですが、@vue/composition-apiAPIは @nuxthjs/~ で全て公開されているので、今ならNuxt.js 用のものを使った方が良さそうです。また、後述しますがSSRで本格的に Composition-API を使いたい場合は、@nuxtjs/composition-api を使わないと辛いと思います。(とはいえまだRFCなので、ご利用は慎重に。。。)

各 mode 共通

$ npm install @nuxtjs/composition-api --save
{
  buildModules: [
    '@nuxtjs/composition-api'
  ]
}

※ TypeScript の導入は省略

SPA の場合

Vue Composition-API の書き方で大丈夫です。Plugin や Context を使いたいときは root をつかった方が今はいいと思います。 Nuxt 独自の非同期API である asyncDatafetch() についてはなるべく使わず、Vueの書き方に徹した方が、移行しやすいです。

import { defineComponent } from '@nuxtjs/composition-api'

export default defineComponent ({
  setup (_, { root }) {
    const store = root.$store
    const myPlugin = root.$myPlugin
    // 変数に代入しておけば、あとあと root を書き換えやすい
  }
})

SSR の場合 (SSGも同様)

前述のSPAの場合ではなるべくNuxt の独自hook は使わないようにできましたが、SSRが必要な場合はそうもいきません。 @vue/composition-api では、下記のようにキメラにするしかなかったですが、この方法だとテンプレート上の変数情報が失われてしまい、DXが悪くなります。

また、vue-meta を使う場合、setup で定義されたものにアクセスできないので、動的な変更が難しくなります。

キメラの例

import { ref } from '@nuxtjs/composition-api'

export default Vue.extend ({
  head () {
    return {
      title: 'タイトル' // setup 内でアクセスできないため、書き換えできない
    }
  },
  async asyncData ({ app }) {
    const posts = await app.$http.$get('/api/posts')
    return {
      posts // setup でアクセスできない
    }
  },
  setup (_, { root }) {
    const active = ref(false)
    return {
      active
    }
  }
})

@nuxtjs/composition-api では、従来の asyncData, fetch() そして head()に変わる API が用意されています

useAsync - Nuxt Composition API

useFetch - Nuxt Composition API

useMeta - Nuxt Composition API

これらを使うことで、page component でも Composition-API を存分に使うことができますね!

ただ、時期尚早感もあるので、SSR の Pages ではComposition-APIを使わないというのも手だと思います。

半年ほど Nuxt + Composition-API を使った所感

VueとTypeScript は相性が悪いと言われていましたが、Composition-API を導入することで劇的に改善していきました。

とくに、既存のプロジェクトのUIデザイン刷新のタイミングで、Composition-API を使い、state の管理を Vuex store からどんどん移行していったところ、コードも非常にスッキリし、単一責任の原則をより意識して書く事ができるようになり、とても満足しています。

ただ、現段階での辛いところとしては、まだベストプラクティスと呼べるものが出てない(もしくは認知されてない)ので、手探りでやっていく必要があることと、自由度が高いので、プログラマーJavaScript力やリテラシーが試されることがあります。

そういった面を踏まえて、RFCだからといって実用に耐えないかというとそんなことはなく、Nuxt v3.0のリリースも控えてますし、導入できるところはどんどん活用していって知見をためていけるといいのではないでしょうか。

別の記事で、Composition-API をつかったコンポーネント設計についても書きたいと思います。

追記: 書きました

task-kawahara.hatenablog.com