🌻

Nuxt2からNuxt3への移行時のメモ

2023/08/27に公開

はじめに

業務でNuxt2からNuxt3への移行の対応をしました。
その時に行った実際な対応内容について列挙していきます。
実際の移行対応時に困っている項目のみ見ていただければいいかなと思います。

対応時点から少し時間が経っていますので、随時記載しているリンク先のドキュメントもご参照ください。

https://nuxt.com/docs/migration/overview
https://nuxt.com/docs/bridge/overview

前提

移行前のソースの大まかな構成

  • Nuxt2
  • Vue2
  • Vuex
  • Vuetify
  • @nuxtjs/composition-api

Nuxt2のプロジェクトでは@nuxtjs/composition-apiを利用していました。
そのため、Composition APIへの書き換え等はしていません。
(Vue3でもOption APIは利用できるのでアップグレード作業としてはそもそも不要ですが)

外部ライブラリはあまり使用していなかったため、案外スムーズに移行できましたが、Vuetifyの対応は非常に大変でした。(そもそもの仕様変更が多数)

進め方

Nuxt3のプロジェクトを新規で作成して、それをベースに既存のコードを少しずつ移行しました。

Vue

v-modelの書き方

Vue3からv-modelの仕様が変更になりました(破壊的変更)。

prop: value -> modelValue
event: input -> update:modelValue

https://v3-migration.vuejs.org/breaking-changes/v-model.html

Nuxt

Pages

layoutの設定

definePageMetaが追加されたので、
糖衣構文でもlayoutを指定できるようになりました。

definePageMeta({
  layout: 'sample-layout',
})

ページのタイトルの設定

headタグを指定するComposition APIのuseHeadが用意されているのでこれを使用しました。

useHead({
  title: 'サンプルタイトル',
})

ルーティング

URLパラメータを使用する場合のファイル名のルールが変わりました。
pages/users/_id.vue -> pages/users/\[_id\].vue

また、/users/* だけでなく /users でもアクセスしたい場合は以下のようにします。
pages/users/\[\[_id\]\].vue

https://nuxt.com/docs/guide/directory-structure/pages/#dynamic-routes

自動インポート

Nuxt3では自動インポートの機能により、composables/などの特定のディレクトリについてはimportを記述することなく参照することができるようになりました。
ですが、composables/ はデフォルトではサブディレクトリが認識されないので以下の設定を追加しました。

nuxt.config.ts
  imports: {
    dirs: ['composables/**'],
  },

extendRoutes

extendRoutesでのルーティングのカスタマイズは以下のように変更になりました。

nuxt.config.js(Nuxt2)
export default {
  router: {
    extendRoutes (routes) {
      //
    }
  }
}
nuxt.config.ts(Nuxt3)
export default defineNuxtConfig({
  hooks: {
    'pages:extend' (routes) {
      //
    }
  }
})

https://nuxt.com/docs/migration/configuration#migration

Vuetify

Nuxt3用のVuetifyのモジュールが対応されていなかったため、pluginsを利用した記述に修正しました。

plugins/vuetify.ts
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'

export default defineNuxtPlugin(nuxtApp => {
  const vuetify = createVuetify({
    components,
    directives,
  })

  nuxtApp.vueApp.use(vuetify)
})

https://vuetifyjs.com/en/getting-started/installation/

各コンポーネント毎の差分は膨大な量になるため、ここでは記載しません。

Polyfill

Vueutify3はSafariやEdgeなどのブラウザの古いバージョンに対応していません。
そのためPolyfillの対応を追加しました。

nuxt.config.ts
  app: {
    head: {
      script: [
        { src: 'https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver,ResizeObserver,WebAnimations,Object.fromEntries,Array.prototype.at'},
      ],
    },
  },

https://vuetifyjs.com/en/getting-started/browser-support/#browsers

状態管理

状態管理にはVuexからPiniaを使用するように変更しました。
Vue3ではPiniaを公式に推奨されています。
https://ja.vuejs.org/guide/scaling-up/state-management.html#pinia

以下のライブラリが必要です。

  • pinia
  • @pinia/nuxt

Composition APIと同じような書き方ができるようになったので、
非常にシンプルで使いやすくなりました。

HMR

https://github.com/nuxt/nuxt/issues/12003
開発モードのHMRにWebSocketが使われるようになりました。
開発の時点でhttpsを利用する場合はWebSocketのprotocolにwsではなくwssを設定する必要があります。
(localhostで起動する場合は設定不要)

nuxt.config.ts
  vite: {
    ...
    server: {
      hmr: {
        protocol: 'wss',
        clientPort: 443,
        path: 'hmr/',
      },
    },
  },

今回はWebサーバーとしてNginxを使用しました。
その設定ファイルには以下を記述しました。

Nginx
server {
    ...
    location /_nuxt/hmr/ {
        proxy_pass <http://sample-app:24678>;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Web Worker

Web Worker用のloaderは不要になりました。
以下のようにWorkerのインスタンスを生成は以下のような記述にしました。
(worker.jsファイルのimportは不要)

// URLの第一引数にはソース上のパスを記載
this.worker = new Worker(new URL('./worker.js', import.meta.url), {
  type: 'module',
})

https://ja.vitejs.dev/guide/features.html#web-workers

Discussion