Open6

Nuxt Bridge移行の知見まとめ

wattanxwattanx

Nuxt Bridgeにしなくてもできる対応

defineNuxtMiddleware, defineNuxtPlugin

defineNuxtMiddleware, defineNuxtPluginが Bridgeだとなくなっている。
https://github.com/nuxt/bridge/blob/main/packages/bridge/src/runtime/capi.legacy.ts#L81-L82

https://nuxt.com/docs/bridge/bridge-composition-api を参考に修正する必要がある。

また、以下のコマンドで自動変換できるツールを作っている

npx @wattanx/nuxt-bridge-migration define-nuxt-middleware <files...>
npx @wattanx/nuxt-bridge-migration define-nuxt-plugin <files...>

Vue 2.7への移行

migration guide

Nuxt Bridge にしないとできない対応

bridge.capi: trueの場合、@nuxtjs/composition-apiというimportはそのままで利用できる。
しかし、一部APIは変更がある。

useFetch

@nuxtjs/composition-apiのuseFetchの返り値である $fetch, $fetchStateが bridgeではなくなっている。

https://github.com/nuxt/bridge/blob/main/packages/bridge/src/runtime/capi.legacy.ts#L516-L517

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

const {
- $fetchState,
- $fetch,
+ fetchState,
+ fetch,
} = useFetch(async () => {
  ...
})

useRoute

useRouteの返り値がcomputedではなくなる

const route = useRoute();
- const query = route.value.query;
+ const query = route.query;
wattanxwattanx

@nuxtjs/composition-apiの対応

Nuxt Bridge、Nuxt 3では、#importsからuseRouteruseNuxtAppといったcomposablesをimportできる。
なので、Nuxt Bridgeにあげる段階で@nuxtjs/composition-api#importsに変えておくと、Nuxt 3になってからもimport先を変えなくて済む。

ts
- import { useRouter } from '@nuxtjs/composition-api';
+ import { useRouter } from '#imports';

また、bridge.capi: trueにすると@nuxtjs/composition-apiをそのまま利用できます。
ただし、Bridge では@nuxtjs/composition-apiのaliasはnode_modules/@nuxt/bridge/dist/runtime/capi.legacy.mjsになる。

https://github.com/nuxt/bridge/blob/main/packages/bridge/src/capi.ts#L34

bridge.capi: trueにしておくと、@nuxtjs/composition-apiを使いながら、徐々に#importsに置き換えることができる。

page.vue
<script setup lang="ts">
// useAsync, useFetchは`useLazyAsyncData`に置き換える
import { useLazyAsyncData } from '#imports';

// useContextだけそのまま以前のまま使う
import { useContext } from '@nuxtjs/composition-api';

</script>

nuxtコマンドで動かした場合、.nuxt/tsconfig.jsonが出力されないので自前で用意する

tsconfig.json
{
  compilerOptions: {
    paths: {
      "#app": ["node_modules/@nuxt/bridge/dist/runtime/index"],
      "#head": ["node_modules/@nuxt/bridge/dist/runtime/head"],
      "#head/*": ["node_modules/@nuxt/bridge/dist/runtime/head/*"],
      "#imports": [".nuxt/imports"],
      "@nuxtjs/composition-api": [
        "node_modules/@nuxt/bridge/dist/runtime/capi.legacy"
      ]
    }
  }
}

Nuxt Bridgeへ移行する段階で#importsに変更するのは、場合によってはとんでもない変更差分になってしまう。
Nuxt 2系から#importsにしておくと、Bridge移行、Nuxt 3への移行がちょっと楽になる。
(auto importを使わない場合の話だが)

wattanxwattanx

nuxtjs/proxy

@nuxtjs/proxy はBridge, Nuxt 3に対応していない。
その代わり、@nuxtjs/proxyの機能はnitroの機能で代替できる

https://nitro.unjs.io/config#devproxy

nuxt.config.ts
export default defineNuxtConfig({
-  modules: ['@nuxtjs/proxy']
-  proxy: {
-    '/api': 'http://example.com',
-  }
+  nitro: {
+    devProxy: {
+      '/api': 'http://example.com',
+    }
+  }
})
wattanxwattanx

Nuxt Bridge を使った Nuxt 3 へのマイグレーション方法(2023/06/15 現在)

2023/04/29 時点における Nuxt Bridge を使った Nuxt 3 へのマイグレーション方法を考える。(仮説なので、必ずしもうまくいくとは限らない)

1. bridge: falseの状態で、Nuxt Bridge を導入する。

2. bridgeオプションを有効化する。

  • bridge.capi: trueにして、@nuxtjs/composition-api互換のcomposables が使えるようにする

    • @nuxtjs/composition-apiとは微妙に違いがあるので気を付ける必要がある。
    • https://zenn.dev/link/comments/075dcc7c4b2a30
    • @nuxtjs/composition-apibuildModulesからは削除するが、パッケージは残しておく。(importでエラーが出るため)
  • bridge.meta: trueにする。

  • bridge.nitro: falseにする。

  • nuxtコマンドでビルドする。

    • bridgeオプションを有効化しても、まだnuxtコマンドが利用できる。

3. Nuxt 3 互換のAPIに変更する

Nuxt Bridge では Nuxt 3 互換の useNuxtAppuseLazyAsyncDataなどが利用できる。
(@nuxtjs/composition-apiと共存はできるはずなので、少しずつ移行できる。)

  • useContext -> useNuxtApp に変更する
  • useAsync, useFetch -> useLazyAsyncDataに変更する。
  • useMeta -> useHeadに変更する
  • useStore -> const { $store } = useNuxtApp() に変更する。

4. nuxiコマンドに置き換える。

  • nitro: trueに変更して、nuxtコマンドを nuxiコマンドに変更する。
    • dist -> .outputディレクトリに変わる。

5. Vuex を Pinia または useState にする

Nuxt 3 では storeディレクトリのサポートがなくなる。
なので、Pinia に移行しておく。
また、Nuxt Bridge では useStateが使えるのでそちらでも良い

6. Nuxt 3, Vue 3 に移行する

wattanxwattanx

エラーと対処法

エラー

Failed to load url #build/composition-globals.mjs (resolved id: #build/composition-globals.mjs) in pj/node_modules/@nuxt/bridge/dist/runtime/capi.legacy.mjs. Does the file exist?

対処法

vitest.config.ts
export default defineConfig({
  test: {
    deps: {
      inline: ['@nuxt/bridge'],
    },
  }
})
test.ts
vi.mock('#build/composition-globals.mjs', () => ({
  isFullStatic: false,
}));