ノエリアラボラトリー

日々の研究と開発の成果を書くよ

Nuxt2のアップデートに苦しむ備忘録

adventar.org

業務でNuxt2をNuxt3に移行している途中ですが、今までに出くわした苦しみをここに書き残しておきます。苦しみが増えると追記する可能性があります。

基本的な移行の話

nuxt.com

zenn.dev

qiita.com

基本的な話は探せば出てくるんですが、これで全てが上手くいったら苦労はしない。

前提

構成

歴史的経緯からこのような構成になっている。何故そうなっているかは私は知らない。

  • Nuxt2 + TypeScript
  • Vue Class Component(property-decorator)
  • Vue Styled Components
  • Vuex

本来はこれらをぶち壊してClass ComponentはComposition APIに、Vuexはpiniaに書き換えるべきなのですが、それをやりだすと時間がいくらあっても足りないということで何とか誤魔化していきます。

方針

  • Vue Class Component

vue-facing-decoratorを使う 併せてvuex-facing-decoratorも使う

zenn.dev

  • Vue Styled Components

vue-styled-componentsがVue3に対応していないためvue3-styled-componentsを使う

  • Vuex

こういうPluginを作って対応。

import type { StoreOptions } from 'vuex'

const storeOption: StoreOptions<any> = {
  modules: {
   // 省略
  },
}

export default storeOption
import { defineNuxtPlugin } from 'nuxt/app'
import { createStore } from 'vuex'
import rootStore from '~/store'

export default defineNuxtPlugin((nuxtApp) => {
  const store = createStore(rootStore)
  nuxtApp.vueApp.use(store)

  return { provide: { store } }
})

遭遇した問題

Vue SFC内でclassの export defaultを消すとWebstormのテンプレートのハイライトが効かなくなる

WebstormはVueのClass Componentを認識してテンプレートに埋め込まれたコンポーネントや変数などのハイライトを行ってくれるが、そのために対象となるclassがdefault exportされていなければいけない。

一方で、vue-facing-decoratorはこのような使い方を想定している。

<script lang="ts">
import { Component, Vue, toNative } from 'vue-facing-decorator'
@Component
class MyComponent extends Vue {}
export default toNative(MyComponent)
</script>

そのため、かなり強引だがviteのプラグインexport default classclassに置換することで解決した。

export default function () {
  return {
    name: 'vue-class-replace-plugin',
    enforce: 'pre' as const,
    transform(code: string, id: string) {
      if (id.includes('.vue')) {
        const modifiedCode = code.replace('export default class', 'class')

        return {
          code: modifiedCode,
          map: null, // ソースマップが不要な場合
        }
      }

      return null // 他のファイルは変更しない
    },
  }
}
<!--suppress JSDuplicatedDeclaration -->
<script lang="ts">
/* eslint-disable import/export */
import { Component, Vue, toNative } from 'vue-facing-decorator'
@Component
// @ts-ignore
export default class MyComponent extends Vue {}
// @ts-ignore
export default toNative(MyComponent)
</script>

decoratorがnuxt build時にエラーになる

vue-facing-decoratorのissueに挙がっていたが、何も手掛かりがなかった。

github.com

色々試した結果解決できたのでissueに報告しておいた。

https://github.com/facing-dev/vue-facing-decorator/issues/93#issuecomment-1832410439

ページ内のリンクを踏んだ場合にエラーが発生する

ページ内のリンクから画面遷移しようとすると、アドレスだけが変わりこのようなエラーが出ていた。

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '__asyncLoader')

非同期コンポーネントを全てdefineAsyncComponent関数でラップすることでエラーが起きなくなった。

ja.vuejs.org

ブラウザのコンソールにvue3-styled-components由来のVue warnが大量に出る

ページを表示した際にこのようなwarnが大量に出る。

[Vue warn]: injection "theme" not found.

traceによるとvue3-styled-components由来のようだが、色々試してみてもこれが消えることはなかったので何かしらのライブラリのバグの可能性がある。

特にレイアウトが崩れているようでもなかったのでこの警告は表示されないようにした。

warnHandlerの設定をnuxt.config.tsから弄る項目が見つけられなかったので適当なmiddleware内で処理した。

useNuxtApp().vueApp.config.warnHandler = (msg: string, _, trace: string) => {
  if (msg.includes('injection "theme" not found')) {
    return
  }
  console.warn(`[Vue warn]: ${msg}\n${trace}`)
}

Titleという名前のコンポーネントがテンプレート内にあるとPropsの処理でエラーが起きる

typeというプロパティを渡しているコンポーネントでこのようなエラーが出てページが表示されなくなった。

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'type')

色々試した結果、テンプレート内にTitleという名前のコンポーネントがあるとこのエラーが発生することがわかった。因果関係は不明。

ViteのHMR設定

zenn.dev

nginxが前段にある環境でこのあたりの設定に合わせても上手くいかなかったが、最終的にdevServerのportとHMRのportを合わせることで上手く動いているように見える。

未解決の問題

this.$nuxt.$on/this.$nuxt.$emitの代替となる機能

Vue3のProvide/Injectを使えば解決できるか、もしくはこういったものを導入するか。

stackoverflow.com

@gmap-vue/v3の表示のスタイル上の問題

そのままでは何も表示されず、スタイルを弄って表示しているが、表示領域からはみ出すという問題が更に発生しているので使うライブラリを変えたほうがいいかもしれない。

:deep(.gmv-map) {
  position: unset !important;
}

おまけ

100以上あるコンポーネントに一つ一つvue-facing-decoratorを適用していくのは正気の沙汰ではないので以下のような正規表現を作成した。

(export default class )(\w+)( extends Vue \{?:|[\s\S]*\}\n)(\n// @ts-ignore\nexport default toNative\(\w+\)\n)?(</script>)

$1$2$3\n// @ts-ignore\nexport default toNative($2)\n$5

おわりに

Nuxt3のマイグレーションガイドがどうにも親切じゃないように思うのと、Nuxt3もVue3もメジャーバージョンアップで破壊的な変更が多くて辛いなって思ってます。