Nuxt Bridgeのドキュメントはこちら

これまでNuxt2とVue3でアプリケーションを作ってきました。2021年の終わり頃に新しくウェブサイトを開発する際に、SSRが必要なことからNuxtを使うことにしました。Nuxt3がすでに公開されていたのですが、今も当時もNuxt3はUnstableであると公式ドキュメントに書かれています。遊びであればそれでもNuxt3を使おうかなとなるのですが、今回は遊びではないので、Nuxt Bridgeを使うことにしました。今からNuxt2を使うのは安定していますが、コストのかかる移行の必要に迫らてるのが近そうだと考えて止めました。

数か月のNuxt Bridgeを使って遭遇した問題とその回避策を紹介します。

更新履歴

2022-02-16
アンカーの誤りを修正しました。

#appは@nuxt/bridge/dist/runtimeである

import { defineNuxtPlugin } from '#app'

公式のドキュメントに#appからのimportが登場しますが、この#appが何を指しているのか分かりませんでした。 探した結果、@nuxt/bridge/dist/runtimeを指しているらしいことが分かりました。#appを@nuxt/bridge/dist/runtimeで置き換えるか、tsconfig.jsonのcompilerOptions.pathsに"#app": ["@nuxt/bridge/dist/runtime"]を加えます。

{
 ...
 "compilerOptions": {
   "paths": {
     "~/*": [
       "./*"
     ],
     "@/*": [
       "./*"
     ],
     "#app": [
       "@nuxt/bridge/dist/runtime"
     ]
    }
  }
  ...
}

defineNuxtPluginだけでなくdefineNuxtComponentやuseNuxt2Meta、useNuxtApp、useRoute、useRuntimeConfigなどもここに定義されています。

import {
  defineNuxtComponent,
  useNuxt2Meta,
  useNuxtApp,
  useRoute,
  useRuntimeConfig
} from '@nuxt/bridge/dist/runtime'

私がプロジェクトを生成したときのテンプレートでは#appがtsconfig.jsonに書かれていなかっただけで、今は書かれているかもしれません。

useAsyncDataとuseFetchが使えないのをfetchとstoreで回避

Nuxt Bridge provides identical features to Nuxt 3 (docs ) but there are some limitations, notably that useAsyncData and useFetch composables are not available. Please read the rest of this page for details.

Nuxt BridgeはNuxt3と同じ機能を提供しますが、いくつかの制限があります。特にuseAsyncDataとuseFetchが使えません。詳細はこのページの残りの部分を読んでください。※私による日本語訳です。

上記の文はドキュメントの先頭に書かれているのですが、私は見落としていました。いざuseAsyncDataを使おうとしたときに使えずに困りました。

これについては、良い回避方法が思いつきませんでした。

WebのAPIから受け取った内容を一時的に保存しておくstores/buckets.tsを以下の内容で作りました。

export const state = (): { hoge: string } => {
  return {
    hoge: '',
  }
}

type State = ReturnType<typeof state>

export const mutations = {
  hoge(state: State, hoge: string) {
    state.hoge = hoge
  },
}

あとはこのストアをfetchの中で呼ぶことで代用します。

import { defineNuxtComponent, useNuxtApp } from '@nuxt/bridge/dist/runtime'

export default defineNuxtComponent({
  async fetch(ctx) {
    ctx.store.commit('buckets/hoge', await API呼び出し())
  },
  setup() {
    // ...
    const hoge = useNuxtApp().nuxt2Context.app.store.state.buckets.hoge
    // ...
  }
}

useNuxt2Metaは内容を動的に変更できないので、head()で代用する

useNuxt2Metaにはhead()が返すオブジェクトが渡せます。しかし制限があり、オブジェクトのvalueはstringかstring[]であることが求められます。私はコンポーネントのpropsの値によって動的にhtmlAttrsを変更したかったので、head()を使うことにしました。

head() {
  return {
    htmlAttrs: {
      class: (this.$props as { isOpened: boolean }).isOpened ? 'clipped' : '',
    },
  }
}

これで実現したかったのは、モーダルのコンポーネントのisOpenedがtrueになったとき、htmlエレメントの属性にclippedを付けることです。

動的にページのタイトルを変更したい場合にも、同じようなことをすることになるでしょう。

publicRuntimeConfigがビルド時に評価されているようなので、ビルド時に環境変数を渡す

公式ドキュメントによれば、publicRuntimeConfigは実行時の環境変数が反映されるはずです。しかし私の環境ではnuxi build時に値が決まっているようでした。privateRuntimeConfigについて試していませんが、同様だと推測します。

しかたがないので、nuxi build時にも環境変数を渡すようにしました。