【2023年】Vue2->Vue3移行についてリサーチした

## リサーチした背景
今年2023年の12月31日にVue2の公式サポートが終了するとのことで、それに伴い、職場のフロントエンドがVue2.6, Nuxt2を使用しているため、リプレイスする計画を立てました。
その調査のメモを残したいと思います。
※敬語などがバラバラなのはお許しください

## 会社のフロントエンドの現環境
- Vue2.6
- Nuxt2
- `nuxt-module-decorator`, `vuex-property-decorators`を使用
- MacOS

## 目次
- Vue2サポート終了について
- Nuxt2からのリプレイス先候補
- Vue3の特徴
- Nuxt3の特徴
- Vue3・Nuxt3のコンポーネント間の状態管理の方法
- Nuxt3のhttp通信の方法
- Nuxt3移行のデメリット・リスク
- 徐々に移行する方法（Vue2.7 or NuxtBridge）
- その他懸念点・気になる点
- 今後やるべきこと
- まとめ
- 参考

## Vueサポート終了について
公式のVue2のサポートが2023年12月31日に終了します 
https://v2.vuejs.org/lts/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867775/84b0c431-d151-2aca-d645-a8ea1aba83e8.png)

### もし、サポート終了後もそのまま使い続けた場合
- バグ修正とセキュリティアップデートの欠如:  公式のサポートが終了すると、Vue2は新しいバグ修正やセキュリティアップデートを受け取らなくなります。
これにより、既知のバグやセキュリティ上の脆弱性が修正されずに残る可能性があります。
その結果、アプリケーションの安定性やセキュリティに問題が発生する可能性があります。
- エコシステムのサポートの減少: 
 Vue2のサポート終了に伴い、関連するエコシステムのライブラリやツールもサポートが減少する可能性があります。
新しいライブラリやツールはVue3を対象に開発される傾向があり、Vue2で使用できるオプションが減少する可能性があります。
また、コミュニティの活発さやドキュメンテーションの質も影響を受けるかもしれません。


## Nuxt2からのリプレイス先候補
### Nuxt2はVue2を使用しているので必然的に対応が迫られます
- Nuxt3
    -  Nuxt3はVue3ベースの次世代のフレームワークです。Vue3の新機能や改善点を活用しながら、Nuxt2の機能やコンセプトを引き継いでいます。
Nuxt3はより高速なビルドとレンダリング、改善された開発体験を提供し、パフォーマンスや開発効率性が向上します。
- Next.js・React
    -  Next.jsはReactベースのフロントエンドフレームワークであり、静的サイト生成（SSG）やサーバーサイドレンダリング（SSR）などの高度な機能を提供します。
Nuxt2からNext.jsに移行することで、Reactの豊富なエコシステムやモダンな開発ツールを活用できます。
ただし、ReactはVueとは異なる構文やコンセプトを持つため、学習コストや既存のコードの変換が必要になる可能性があります。

### →現職のプロジェクトはNuxt3への移行が望ましいという結論が出た
- Vuetifyの依存度が高いため
- Next, Reactなど、他だと工数がかかる
- 時間・工数に余裕がある、規模が大きいならReactの方が良いかも

## Vue3の特徴
- Composition APIがデフォルトで導入された
    - Vue2系でも使用できるが、別途プラグインとしてimportが必要
    - Vue2系ではOptionsAPIがデフォルトだった（data, computed, methodsなどのブロック毎管理）
- パフォーマンスの向上
    - バンドルサイズが小さくなる
    - `<script>`タグ→`<template>`タグの順番での記述を推奨
- TypeScriptのサポート
    - Vue 3では、TypeScriptのサポートが強化されています。
Vue 3のコアライブラリはTypeScriptで書かれており、より厳密な型チェックやエディタのサポートを提供します。
これにより、開発中のエラーの早期検出やタイプセーフな開発が可能になります。
- ディレクティブv-modelなどの動きの変更
    - Vue 2ではv-modelを使用することで、自動的にvalueプロパティとinputイベントが関連付けられましたが、Vue 3ではmodelValueプロパティとupdate:modelValueイベントを使用します。
- `watchEffect()`など

## Composition APIがデフォルトで導入された
- OptionsAPIと比較したメリット
    - data, computed, methodsのようにコード上でブロックを分けることなく、関連のあるプロパティや処理の順番を自由な順番で書けるようになった。
散在してしまい管理しづらくなることがなくなった
    - ライフサイクルフックも同様。（onMounted、onUpdated、onUnmountedなどで管理）
`<script setup>`構文で、ネストを浅くできる、コード量を減らせる、素のJSのように記述が可能になった（Vue3.2以降）
    - 再利用性の向上: Composition APIでは、ロジックを単独の関数として抽出し、他のコンポーネントと共有することが容易です。
これにより、コンポジション関数を再利用することができ、コードの重複を減らすことができます。これは、ロジックの抽象化やモジュール化に役立ちます。

### Data, プロパティの定義方法

```ts
// data, プロパティの定義方法の違い

// optionsAPI
data () {
  return {
    XX: [
      { text: "A", to: "/" },
      { text: "B", to: "/〇〇" }
    ]
  }
}
```

```ts
// composition API ↓
const XX = ref<Object>([
  { text: "A", to: "/" },
  { text: "B", to: "/○○" }
])
```

Vue2の時と異なり、素のJS記法で、ネストも浅く数行で表現できます
Vue2では相性が悪かったTSの型指定もできます

### ライフサイクルフックの定義方法
```ts
// options API
export default {
  data() {
    return {
      message: 'Hello, Vue!'
    }
  },
  created() {
    console.log('Component created')
  },
  mounted() {
    console.log('Component mounted')
  },
}
```

```ts
// composition API
import { ref, onCreated, onMounted } from 'vue' // 実際はimport不要 
const message = ref<string>('Hello Vue3!') onCreated(() => {
  console.log('onCreated hook')
}) onMounted(() => {
  console.log('onMounted hook')
})
```

Vue2の時と異なり、素のJS記法で、ネストも浅く数行で表現できます
Vue2では相性が悪かったTSの型指定もできます

### computedの定義方法
```js
// optionsAPI
computed: {
  classes() {
    const savedContentIndex = this.$store.getters.getLearningContentIndex
    for (let i = 0; i <= 7; i++) {
      if (savedContentIndex === i) {
        return `learning-content-index-0${i}`
      }
    }
  },
},
```
```ts
// composition API
import { useNuxtApp } from "@nuxt/bridge/dist/runtime"
const { $store } = useNuxtApp()
const classes = computed(() => {
  const savedContentIndex = $store.getters.getLearningContentIndex
  for (let i = 0; i <= 7; i++) {
    if (savedContentIndex === i) {
      return `learning-content-index-0${i}`
    }
  }
})
```

Vue2の時と異なり、素のJS記法表現できます

### methodsの定義方法
```js
// options API
methods: {
  async toggleWatchAgain() {
    this.$set(this.movie.log, "watchAgain", !this.movie.log.watchAgain)
    const { status } = await this.updateLog(this.movie.log.id, {
      watchAgain: !this.movie.log.watchAgain
    })
  }
}
```
```ts
 // composition API
import { useNuxtApp } from "@nuxt/bridge/dist/runtime";
const { $set } = useNuxtApp()
 const toggleWatchAgain = async () => {
  $set(movie.value.log, "watchAgain", !movie.value.log.watchAgain)
  const { status } = await updateLog(movie.value.log.id, {
    watchAgain: movie.value.log.watchAgain,
  })
}
```

### ref, reactive
- Vue3ではリアクティブな値(vue2でいうdata)はrefとreactiveを使います。
- .vueファイルだけでなく、composablesディレクトリ配下の、.js, .tsファイルでも使用可能です

```vue
<script setup lang="ts">
import { ref } from "vue"

const hogehoge = ref(0)
const hogehoge2 = ref<number>(0)
</script>

 <template>
  <div>{{ hogehoge }}</div>
</template>

 <script setup lang="ts">
import { reactive } from "vue"

const hogehoge3 = reactive({ title: "" , name: "" })
const hogehoge4 = reactive<Object>({ title: "" , name: "" })
</script>

 <template>
  <div>{{ hogehoge }}</div>
</template>
```

### watchEffect()
watchEffectはwatchと似ていますが、監視対象を指定しません。
refやreactiveでリアクティブにした変数のどれかが変更したときに実行をしてくれます。
全体を監視し、同じ処理をさせたい時には便利そう

```vue:test.vue
<script setup lang="ts">
import { watchEffect, ref } from "vue"

const count = ref<number>(0)
const addCount = (): void => count.value++
watchEffect(() => console.log(`クリックした回数:${count.value}`))
</script>

 <template>
  <v-container>
    <v-row>
      <v-col cols="12">
        <v-btn @click="addCount">数字を増やす</v-btn>
      </v-col>
    </v-row>
  </v-container>
</template>
```

## パフォーマンスの向上
- バンドルサイズが小さくなる（静的ツリーシェイキング (Static Tree Shaking)）
    - Vue 3では、コンパイラがより効果的な静的ツリーシェイキングを行います。これにより、使用されていないコンポーネントやコードが自動的に削除され、バンドルサイズが削減されます。
    - 静的ツリーシェイキングにより、不要なコンポーネントやライブラリのコードが含まれないため、アプリケーションの起動時間やレンダリングのパフォーマンスが向上します。

- コードの最適化
    - Vue3では、コード生成とコードの最適化が強化されています。
新しいコンパイラアーキテクチャにより、効率的なコード生成と最適化が行われ、アプリケーションのパフォーマンスが向上します。
    - Vue3ではテンプレートコンパイラの最適化も進められており、レンダリング速度やメモリ使用量の改善が図られています。
- `<script>`タグ→`<template>`タグの順番での記述を推奨
    - IDEのサポート: 
Vue 3のComposition APIを活用する際に、`<script>`セクションを先に配置すると、より優れたIDEサポートが得られることがあります。
多くのエディタやIDEは、JavaScript/TypeScriptのコードに対して自動補完やエラーチェック、ドキュメンテーションの表示などのサポートを提供しています。`<script>`セクションが先に配置されることで、これらの機能がより効果的に利用できます。
    - コンポーネントの構造化と再利用性: 
`<script>`セクションが先に配置されることで、コンポーネントのロジックを抽出しやすくなります。
Composition APIを使用してロジックを再利用する際に、関連するロジックを単独の関数として抽出し、他のコンポーネントと共有することができます。
`<script>`セクションが先に配置されることで、このような構造化と再利用性が容易になります。

## Nuxt3の特徴
- Vue3に対応
- ビルドが早くなった
- `useFetch()`など、独自の関数で、API通信が可能

### ビルドが早くなった
従来のWebpackに代わり、Viteというエンジンをデフォルトで使用しています。Viteは自身の高速なビルドシステムを持ち、ESモジュールに基づいた効率的な開発を可能にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867775/9fffa402-453b-2db9-0933-b1291e32d93b.png)

## 状態管理について、選択肢が広がった
### Nuxt3では状態管理には主に3つの方法があります
- compositionAPI提供の`composables`ディレクトリとNuxt3組み込みの`useState()`
- Provide / Inject
- Pinia（Vue公式のVuexと似ておりVue3に対応したVuex4もあるが、Piniaを推したい）

`useState()`は比較的シンプルな状態管理を行う場合に適しています。
複雑な管理をしたい場合は、Vuex同様、ストア管理するPiniaが良いと思われます。

---
compositionAPI提供の`composables`ディレクトリとNuxt3組み込みの`useState()`

- ルートディレクトリに`composables`というディレクトリを配置し、そこにNuxt3提供の`useState()`などを使ってVuexStoreのようにVueコンポーネント間で共有することができます。

- `ref()`もリアクティブな値を扱いますが、特定のVueコンポーネントが破棄された場合、refの値も破棄されます。
しかし`useState()`は特定のVueコンポーネントが破棄されても、そこで管理している値は破棄されません。

```js:composables/useCounter.js
import { useState } from "#app"

export const useCounter = () => {
const count = useState("count", () => 0)
  const increment = () => {
    count.value++
  }
  return {
    count,
    increment,
  }
}
```

```vue:component.vue 
<script setup>
import useCounter from "~/composables/useCounter"

const { count, increment } = useCounter()
</script>

 <template>
　　<div>
　　　　<p>Count: {{ count }}</p>
　　　　<button @click="increment">increment</button>
　　</div>
</template>
```

### Provide / Inject
- 複数のコンポーネントの階層になっていても、 何度もProps / Emitを行ってバケツリレーをすることなく、値を受け渡すことができます。

```js:store.js 
import { reactive, readonly } from "vue"

const state = reactive({
  count: 0,
})
const increment = () => {
  state.count++
}
export default readonly({
  state,
  increment,
})
```

```vue:root.vue 
<template>
  <div>
    <router-view />
  </div>
</template>

 <script setup>
import { provide } from "vue"
import store from "~/store"

provide("store", store)
</script>
```
ルートにprovideを記述したコンポーネントを配置します


```vue:component.vue
<template>
  <div>
    <p>Count: {{ store.state.count }}</p>
    <button @click="store.increment">Increment</button>
  </div>
</template>
 
<script setup>
import { inject } from "vue"

 const store = inject("store")
</script>
```
Provideで提供されたstoreをコンポーネントで呼び出しています

---
### Pinia
- Vue3, Nuxt3ではストアの状態管理にはPiniaというライブラリがメジャーです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867775/18e8b4bc-69e1-bb6a-0e7e-553603f2de30.png)

- Piniaは、Vuexよりも直感的で分かりやすく、TS, script setup構文, composition APIと一緒に使用することでシンプルに記述できます
- mutationは使用せずactionsで全て管理します

```vue:test.vue
<script lang="ts" setup>
import { defineProps, ref } from 'vue'
import { useCartStore } from '~/store/cart'

const cartStore = useCartStore()
const items = ref([])

const addItem = (name) => {
  cartStore.addItem(name)
}

const removeItem = (name) => {
  cartStore.removeItem(name)
}

const purchaseItems = async () => {
  await cartStore.purchaseItems()
  items.value = []
}

const { items: cartItems } = cartStore
items.value = cartItems
</script>
```

```ts:cart.ts
import { useStore } from 'pinia'
import { defineStore } from 'pinia'

 export const useCartStore = defineStore('cart', {
  state: () => ({
    rawItems: []
  }),
  getters: {
    items: (state) => {
      return state.rawItems.reduce((items, item) => {
        const existingItem = items.find((it) => it.name === item)
        if (!existingItem) {
          items.push({ name: item, amount: 1 })
        } else {
          existingItem.amount++
        }
        return items
      }, [])
    }
  },
  actions: {
    addItem(name) {
      this.rawItems.push(name)
    },
    removeItem(name) {
      const i = this.rawItems.lastIndexOf(name)
      if (i > -1) this.rawItems.splice(i, 1)
    },
    async purchaseItems() {
      console.log('Purchasing', this.items)
      const n = this.items.length
      this.rawItems = []
     return n
    }
   }
})

export function setupStore() {
  const store = useStore()
  return { cartStore: useCartStore(store) }
}
```

## Nuxt3のhttp通信の方法
Nuxt2ではaxiosを使用することが一般的でした。
Nuxt3では以下よくが使用されるようです
- fetch()
    - JavaScript組み込み関数
- ohmyfetch
    - Nuxt3の組み込み関数
        - `$fetch()`：Vueコンポーネント外でも使用可能
        - `useFetch()`：Vueコンポーネント内のみ使用可能

### fetch()
- JavaScript組み込み関数なので、ブラウザ・Node.js両方に使える、サードパーティのライブラリに依存しません
- エラーハンドリングやキャッシュ管理などの機能が少ないです
- レスポンスのデータを取得するためにjson()やtext()などのメソッドを呼ぶ必要があります

```js
// GETリクエスト
const response = await fetch('https://api.nuxtjs.dev/mountains')
const data = await response.json()

// POSTリクエスト
const response = await fetch('https://api.nuxtjs.dev/mountains', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Fuji' })
})
const data = await response.json()
```

### $fetch()
- `$fetch()`はNuxt3が用意しているohmyfetchというライブラリが提供するHTTPクライアントです。
`fetch()`関数と同じようにURLやオプションを引数に取りますが、レスポンスのデータを直接返します。
- `fetch()`よりも簡潔に書けます
- リトライやタイムアウトなどの機能があります
- Ohmyfetchというサードパーティのライブラリに依存します

```js
// GETリクエスト
const data = await $fetch('https://api.nuxtjs.dev/mountains')

// POSTリクエスト
const data = await $fetch('https://api.nuxtjs.dev/mountains', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ name: 'Fuji' })
})
```

### useFetch()
- `useFetch()`はNuxt3が用意している関数。内部的に`$fetch()`を使用
- キャッシュ管理やレスポンスの状態管理などの機能を提供しています
- Vueコンポーネント内でしか使用できない（`$fetch()`は可能）
- レンダリング時以外にデータを取得することができません

```vue
<script setup>
const { data, pending, error, refresh } = await useFetch(
  'https://api.nuxtjs.dev/mountains'
)
</script>

 <template>
  <div v-if="pending">Loading...</div>
  <div v-else-if="error">Error: {{ error.message }}</div>
  <div v-else>
    <ul>
      <li v-for="mountain in data" :key="mountain.id">{{ mountain.name }}</li>
    </ul>
    <button @click="refresh">Refresh</button>
  </div>
</template>
```

## Nuxt3に移行するデメリット・リスク
- Composition APIはクセがあり、学習コストがかかります
- 各構文を修正する必要があります
- Vuex, store管理している箇所の修正範囲が広いです
- デコレータを廃止する場合は、書き方が大幅に変わります
- Nuxt3でもデコレータは対応しているらしいが、Vuetify3はcomposition APIが前提
- サードパーティ製のモジュールで対応していないものがあります
- Node.js, npmのバージョンを変更する必要があります
- Vuetifyの対応

各構文を修正する必要がある
- 例： `Vue.component()`→ `app.mount()`

```ts:vue-pdf-app.ts
import Vue from "vue"
import VuePdfApp from "vue-pdf-app"
Vue.component("VuePdfApp", VuePdfApp)

// vue-pdf-app.ts（置き換え後）
import { app } from "vue-pdf-app"
app.mount("#your-element-id")
```

### サードパーティ製のモジュールで対応していないものがあります
- @nuxtjs/axios
- vue-pdf
- vue-pdf-app→Vue3 Pdf Appで代替可能？
- @nuxtjs/dotenv
- @nuxtjs/proxy
- webpack, vite関連

### Node.js, npmのバージョンを変更する必要があります
- Node.js16.11以上, npm7以上が必要
- 別のプロジェクトも同時に変更するか、Docker環境を用意しない限り、Node.js, npmのバージョンが異なるため、都度変更する必要があり、開発がやりづらいです

### Vuetify3の対応：3への移行は必須ではなく引き続き2を使用できるらしいが、、、
- Vue 3のComposition APIの使用: 
Vuetify 3.xでは、Vue 3のComposition APIを活用したコンポーネントの作成が推奨されています。
Vue 2のOptions APIとは異なるアプローチなので、コンポーネントの作成方法やロジックの配置に関して変更が必要になる可能性があります。
- v-modelの使用: 
Vue 3では、v-modelディレクティブの動作が変更されています。
Vue 2ではv-modelを使用することで、自動的にvalueプロパティとinputイベントが関連付けられましたが、Vue 3ではmodelValueプロパティとupdate:modelValueイベントを使用します。
Vuetify 3.xでは、この変更に合わせてv-modelの使用方法が変更されている場合があります。
- レイアウトシステムの変更: 
Vuetify 3.xでは、グリッドシステムとして従来のv-rowとv-colの代わりにv-container、v-row、v-colを使用する新しいレイアウトシステムが導入されました。また、v-layoutとv-flexは削除されました。
- CSSクラスとスタイルの変更: 
Vuetify 3.xでは、CSSクラス名やスタイルの一部が変更されている場合があります。
特に、v-text-fieldやv-selectなどのコンポーネントのクラス名やスタイルが変更されています。
また、いくつかのスタイルオプションも変更されているため、カスタマイズの際には注意が必要です。
- 一部のコンポーネントの変更: 
Vuetify 3.xでは、一部のコンポーネントが追加、変更、または削除されている場合があります。

## 徐々に移行する方法
いきなりNuxt3に移行するには、対応すべき事項が多いです。 
その緩和策が主に2つあります。

- Vue2.7
    - Nuxt2のまま、Vue2.6->Vue2.7にアップデート
    - Node.js, npmのアップデート変更のリスクが低い
- NuxtBridge

### Vue2.7：概要
- 「Vue」では、すでにバージョン3が標準となっており、2.xを使っている開発者は互換性などの問題でやむを得ずとどまっていると考えられます。
「Vue 2.7」では、バージョン3の一部重要な機能を取り込むことで、2.xを使っている開発者に新機能による恩恵を受けてもらうことを考えています。
- Vue 3から取り込んだ機能としては、Composition API、SFC（Single-File Components）上での `<script setup="">`、同じくSFC上でのCSSのv-bindディレクティブの3点が挙げられます。
Composition APIは、大規模プロジェクトの開発時にソースコードの見通しをよくするための各種機能を提供します。
- `<script setup>`は、SFCでComposition APIを使うときに使用する構文で、使用することで同じ文の繰り返しを避けることができ、TypeScriptを使用した際にコードを書きやすくなるなどの理由から、使用を推奨しています。
 また、CSSのv-bindディレクティブは、CSSの属性を動的に変更することを可能にします。
- そのほか、defineComponent()、h()、useSlot()、useAttrs()、useCssModules()、set()、del()、nextTick()といったAPIが利用可能になった。
- その他参考になりそうなもの 
Vue2.7にバージョンアップする際はcomposition-apiのroot(特にvue-router)に注意！
 https://zenn.dev/monica/articles/7d3417c07b6cf4

### Nuxt Bridge：概要
 https://nuxt.com/docs/bridge/overview
- NuxtBridgeは、Nuxt2からNuxt3への移行をサポートするための公式のツールです。
Nuxt3では、ビルドエンジンがViteに変更され、一部の機能やAPIが変更されています。
NuxtBridgeは、Nuxt2のプロジェクトをNuxt3に移行する際に、コードの互換性を確保するためのツールとして提供されています。
- NuxtBridgeを使用すると、Nuxt3に移行するための準備作業を支援するいくつかの機能が提供されます。
具体的には以下のような機能があります：
    - ビルドエンジンの変換: 
NuxtBridgeは、Nuxt2で使用されていたwebpackをViteに自動的に変換します。
この変換により、ビルドパフォーマンスが向上します。
    - コードの互換性チェック: 
NuxtBridgeは、Nuxt2で使用されていた機能やAPIがNuxt3で廃止された場合に、その変更箇所を検出します。
これにより、移行後のコードで互換性のない部分を特定し、修正することができます。
    - 自動修正: 
NuxtBridgeは、一部の互換性のないコードを自動的に修正する機能も提供します。
移行作業が容易になり、手動での修正作業を減らすことができます。

Nuxt Bridge：対応表
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/867775/95508025-a7ed-b7b5-8280-05ea6ae79112.png)

### Nuxt Bridge：インストール方法
- 下記のコマンドを実行します
```sh
// コマンド
$ yarn add --dev @nuxt/bridge@npm:@nuxt/bridge-edge
# or 
$ npm install -D @nuxt/bridge@npm:@nuxt/bridge-edge
```

### Nuxt Bridge：懸念点
- NuxtBridgeは、CommonJSがサポートされなくなった
    - `nuxt.config.ts`, 環境別で使用されるような`env.staging.js`などの`require("dotenv").config()`, `module.exports`構文は使用できなくなる
- Nuxt2, Nuxt3では使用できるものが、一部使用できない
    - `definePageMeta`(layout)など
- Node.jsのバージョンを上げる必要があります
- 公式は推奨しているが、まだベータ版なので、どこまで信頼して良いかわからない

### Nuxt Bridge：ファイル修正
- `package.json`を修正
```diff_json:package.json
"scripts": {
- "dev": "nuxt",
+ "dev": "nuxi dev",  //nuxi のみではダメ
- "build": "nuxt build",
+ "build": "nuxi build",
+ "start": "node .output/server/index.mjs",
- "generate": "nuxt generate",
+ "generate": "nuxi generate",
- "start2": "nuxt start",
+ "start2": "nuxi review",
},
"dependencies": {
- "nuxt": "^2.15.7"
+ "nuxt-edge": "latest"
},
```

- `nuxt.config.js`を修正
```js:nuxt.config.js
export default {
  ssr: false,
  ......
}

// ↓に変更

import { defineNuxtConfig } from '@nuxt/bridge'
export default defineNuxtConfig({
  ssr: false,
  alias: {
    tslib: 'tslib/tslib.es6.js',
  },
  ......
})
```

- `ts.config.json`を修正
```json:ts.config.json
{
  "extends": "././nuxt/ts.config.json",
  "compilerOptions": {
    ...
  },
  "vueCompilerOptions": {
    "experimentalCompatMode": 2,
  }
}
```

### Nuxt Bridge： Nuxt Bridge->Nuxt3移行の工数
- 移行の工数は、ざっくり7人日〜12人日？ ※1人日8h
 https://labs.1-10.com/2023/01/20/2290
    - Nuxt2->NuxtBridgeへの移行時間は含みません
    - NuxtBridge導入前の作業として
        - Vuex->Piniaに変更
        - axios変更
        - `process.env.*`からruntimeConfigへの移行

## その他の懸念点・検討すべき点
- 他のリポジトリのフロントもリプレイス対応するか？
- 非同期通信はaxiosライブラリを継続して使うか？それとも`useFetch()`を使うか？
- 状態管理は引き続きVuexを使用するか？Piniaか？useState, Composablesを使うか？
- Nuxt3にした場合でも、nuxt-module-decoratorを使用し続けるのか？
- Nuxt3に移行した場合、状態管理をpiniaにする場合、nuxt-module-decoratorは引き続き使用するのか？
- VSCodeのプラグインはVeturから、Volarに変更が必要
    - Volar Extension, TypeScript Vue Plugin(Volar)を追加
- Nuxtに限らずだが、リプレイス作業中に新機能追加はナンセンスなので、開発は完全STOPし、リプレイスに集中せざるを得ない

## 今後やるべきこと
- Vue3, nuxt3に対応していないpackage.json内のモジュールを精査
- Vuetify3に移行するかどうか、またVuetifyで、vue3, Nuxt3に対応していないタグ、オプション、APIを精査
- Dockerなどで、別途開発環境を用意
- Vue2.7, NuxtBridgeのサンプルを用意し検証
- VuexStoreでの管理、非同期通信ライブラリの選定
- composition APIに変更するか、module-decoratorをそのまま使うかの方針決め（Vuetify3を考慮するならcomposition API化した方が良い）
- 方針を固めた後に、実際にリプレイス

## まとめ
- 「Nuxt2のまま徐々に変更」の場合は、NuxtBridgeを利用したい（Node.js, npmバージョンアップ必要？）
- Nuxt3にアップデートする場合は、Node.js, npmのバージョンアップも同時に必要なため、リスクがあります
- Nuxt2->Nuxt3に移行する場合でも、工数が大幅にかかります
- Vuetifyは3に上げなくても良い。上げる場合はcomposition API化した方が良いです

## 参考
- Vue2.7アップグレード最強ガイド
 https://tech-blog.lapras.com/techBlogs/vue-2-7-upgrade-guide
- CloudSign の社内用管理画面を Vue2.7 に移行した話 
https://creators.bengo4.com/entry/2023/03/27/083000
- Vue2.7アップデートに伴うv-deep移行で詰まったところ 
https://creators.bengo4.com/entry/2023/06/14/083000
- 公式：# Migration Build 
https://v3-migration.vuejs.org/migration-build.html
- NuxtBridgeとは（M&A Cloud） 
https://kubotak.page/articles/1zMAE0c01TIKpHl75E5w2P/
- NuxtBridge導入してみた②　nuxtをnuxiに変えたら怒られたの巻【前編】 
https://zenn.dev/mihorin1729/articles/9904057fc24fa4
- NuxtBridge　CompositionAPI書き換えまとめ（だいたい完成） 
https://zenn.dev/mihorin1729/articles/100eabb7219e82
- Nuxt3でaxiosはなくなり、Fetch APIをつかうらしい 
https://www.memory-lovers.blog/entry/2022/06/02/170000
- Nuxt2(bridge)からNuxt3へのフレームワーク移行とその工数（2023/01/20）
 https://labs.1-10.com/2023/01/20/2290
- Nuxt 3 公式ドキュメント 日本語訳 
https://zenn.dev/torish/scraps/16676a3500ad99