Nuxt2で作ったWebアプリをNuxt3で作り変えてみた

  • プロダクション
  • オピニオン
Nuxt2で作ったWebアプリをNuxt3で作り変えてみた

目次

経緯

Vue2は2023年12月31日にサポートが終了いたします。
以前作成した選択式クイズアプリがNuxt2で作っていたので、この機会にNuxt3で作り変えてみました。

Nuxt2で作成したアプリのコラム記事
Nuxt.jsで選択式クイズアプリを作ってみた(1)
Nuxt.jsで選択式クイズアプリを作ってみた(2)

今回作成したNuxt3で作成した選択式クイズアプリのソース
https://github.com/ymtps/questionAppNuxt3

本アプリのNuxt2バージョンとNuxt3バージョンでの比較

  • 移行対象のWebアプリの規模について
    移行対象のWebアプリの規模について

移行対象のWebアプリの規模について

各ディレクトリのコード量
pages:71行
components:459行
store:54行

移行方法について

Nuxt2からNuxt3への移行方法はいくつかあります。

1.アップデートコマンドの実行からエラーをひたすら修正
2.Nuxt2→NuxtBridge→Nuxt3の順でアップデート
3.Nuxt3新規プロジェクトを作成し、1ファイルずつ移植

最初1.でやろうとしたのですがNuxt3に対応していない記述やライブラリのエラーが大量に出力され、何から修正していけばいいのか分かりづらかったので、 今回は3.の方法で実施しました。

Nuxt3のコードに移行するために行ったこと

大きく分けて下記の3つを行いました。
1.非対応ライブラリの置き換え
2.状態管理ライブラリの置き換え(Vuex→Pinia)
3.OptionsAPIからCompositionAPIに置き換え

非対応ライブラリの置き換え

■axios
Nuxt3ではaxiosではなく、useFetch()を使用してAPIを呼び出す。

・Nuxt2での記述

/**
 * 問題情報を読み込む
 */
readQuestions() {
  axios.get(this.selectQuestionPath).then((response) => {
    this.setReadQuestions(response.data.questionList); // 読み込んだ問題情報をstoreに格納
    this.setDispType("questions");
  }).catch((error) => {
    console.log(error);
  })
},
・Nuxt3での記述
/**
 * 問題情報を読み込む
 */
const readQuestions = async () => {
  useFetch(selectQuestionPath.value)
    .then(async (response: any) => {
      setReadQuestions(response.data._rawValue.questionList); // 読み込んだ問題情報をstoreに格納
      commonStore.setDispType("questions");
    })
    .catch((error) => {
      console.log(error);
    });
};

■style-resource
style-resourceがnuxt2で対応していなかったので、viteで定義する。
・nuxt2での記述(nuxt.config.js)
  modules: [
    '@nuxtjs/style-resources'
  ],
  styleResources: {
    scss: [
      '~/assets/scss/_palette.scss',
      '~/assets/scss/_colors.scss',
    ]
  },
・nuxt3での記述(nuxt.config.ts)
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData:
            '@import "@/assets/scss/_palette.scss";@import "@/assets/scss/_colors.scss";',
        },
      },
    },
  },

状態管理ライブラリの置き換え(Vuex→Pinia)

Nuxt3では、状態管理ライブラリはVuexではなくPiniaが公式で推奨されております。

PiniaがVuexと異なる点
・TypeScriptがデフォルトでサポート
・mutationsがactionsと統合されている
・ビルド時間が早い

・Piniaでの記述

import { defineStore } from "pinia";
export interface QuestionPathInterface {
  filePath: string;
  title: string;
}
export interface SettingOptionInterface {
  title: string;
  btnName: string;
  questionPaths: QuestionPathInterface[];
  random: boolean;
  choiceRandom: boolean;
}
export interface QuestionInterface {
  no: number;
  question: string;
  choice: string[];
  answer: string;
}
export const useCommonStore = defineStore("common", {
  state: () => ({
    dispType: "", // 表示する画面情報
    settingOption: {
      title: "",
      btnName: "",
      questionPaths: [] as QuestionPathInterface[],
      random: false,
      choiceRandom: false,
    }, // 設定ファイルの内容
    questionList: [] as QuestionInterface[], // 問題集リスト
    selectAnswerList: [] as string[], // 解答リスト
    correctCount: 0, // 正解数
    selectChoiceStore: "", // 選択した選択肢
  }),
  getters: {
    getDispType: (state) => state.dispType,
    getSettingOption: (state) => state.settingOption,
    getQuestionList: (state) => state.questionList,
    getSelectAnswerList: (state) => state.selectAnswerList,
    getCorrectCount: (state) => state.correctCount,
    getSelectChoiceStore: (state) => state.selectChoiceStore,
  },
  actions: {
    setDispType(dispType: string) {
      this.dispType = dispType;
    },
    setSettingOption(settingOption: SettingOptionInterface) {
      this.settingOption = settingOption;
    },
    setQuestionList(questionList: QuestionInterface[]) {
      this.questionList = questionList;
    },
    setSelectAnswerList(selectAnswerList: string[]) {
      this.selectAnswerList = selectAnswerList;
    },
    setCorrectCount(correctCount: number) {
      this.correctCount = correctCount;
    },
    setSelectChoiceStore(selectChoiceStore: string) {
      this.selectChoiceStore = selectChoiceStore;
    },
  },
});

呼び出し側が記述が結構異なりますが、storeファイル側はVuexとあまり変わらない印象でした。
(Vuexでの記述は前コラムをご参照ください。)

OptionsAPIからCompositionAPIに置き換え

OptionsAPIとCompositionAPIの違いについてChatGptに聞いてみました。

まとめるとCompositionAPIでは、再利用可能なロジックを抽出してコードの再利用や整理をして見やすいコードで書けるようになるとのこと。
修正ファイルは数が多いので、修正したコードは実際のソースをご参照ください。

CompositionAPIはマスト?

Nuxt3でもOptionsAPIは使用することが出来ます。
変数の定義や関数の定義を1つのブロックにまとめて書くほうが好きか、役割ごとのブロックに書くほうが好きかで使い分けるでもいいと思っています。
今から学ぶのであればCompositionAPIのほうをお勧めします。

アップデートにかかった時間

Nuxt2からNuxt3のアップデート作業で、この規模のアプリでも大体10時間ほどかかりました。
慣れていない作業というのもありますが、
・typescriptの型記述
・piniaへの移行
・CompositionAPIへの移行
がとにかく大変でした。

まとめ

Nuxt2からNuxt3に移行するのはとても時間がかかり大変でした。
しかし、Nuxt2で作ったアプリをNuxt3で作り変えるのは、CompositionAPIやPiniaの勉強にもなるので、とても有意義なものとなりました。

この記事の執筆者

Y.M

DXプラットフォーム事業部

この記事に関するご相談やご質問など、お気軽にお問い合わせください。

お問い合わせ

タグ一覧