📌

簡単にVue.jsからNuxt.js(SPA)へ移行する手引き

2021/08/02に公開1

こんにちは! しっぽくんです
Vue.js をずっとやってきましたが、社内で Vue.js から Nuxt.js へ移行するプロジェクトが出てきたので参考程度に記事を書くことにしました
本記事では Vue.js から Nuxt.js(SPA) へ移行する手順を説明します

はじめに

Vue.js から Nuxt.js へ移行するモチベーションは色々あります
例えばSEO対策、SSR・SSGをやりたい、 middlewareplugin を使って楽をしたい、 Nuxt.js 特有の機能を使いたいなどなど…
「Vue.js Nuxt.js 移行」と検索すると様々な記事がヒットしますが、大抵がフルスクラッチか移行するメリットの列挙程度でした[1]
この記事では Vue.js で作られたプロジェクトを Nuxt.js へ移行する手順を示すことで上記に挙げている動機のお手伝いを出来ればと考えています

この記事のサンプルとして簡単なTodoアプリを作りました 参考程度にどうぞ
修正前
https://github.com/shippokun/try-vue-to-nuxt-todo/releases/tag/vue
修正後
https://github.com/shippokun/try-vue-to-nuxt-todo/pull/1

移行手順について

まず移行するための方針と全体の行程について考えていきます

方針

  1. 出来る限り元々のコードは修正しない
  2. 移行前後では Vue.js(@vue/cli)Nuxt.js(@nuxt/cli) どちらでも動作できるようにする

大抵のプロジェクトは複数のメンバーで開発をしているため、不要なコンフリクトを生み出すのは避けるべきなので出来る限りコードの修正は行いません[2]
修正する場合は元の動作に影響がない範囲に抑えます
また移行直後に不具合があり開発がストップすることもなるべく避けるべきなので、一時的な共存をできるように修正します

全体の行程

  1. nuxt の導入
  2. nuxt.config.js の設定
    • ディレクトリ構成のギャップ補完
    • エントリーポイントの対応
    • ルーティングの上書き
  3. その他微修正

移行作業

1. nuxt の導入

必要なライブラリ群をインストールしていきます

npm i nuxt
npm i -D @nuxt/types @nuxt/typescript-build @nuxtjs/eslint-config-typescript @nuxtjs/eslint-module @nuxtjs/router

インストールしているものは Nuxt.js をTSで作ったプロジェクトでデフォルトで入っているもの+routerを入れています

2. nuxt.config.js の設定

Nuxt.js では Vue.js と違いディレクトリ名や場所そのものに意味があることや、 Vue.js とは異なりエントリーファイルの扱いや Vueインスタンスにオプションを追加する方法など違いが多数あります

nuxt.config.js
export default {
  // SPAのみ対応
  ssr: false,

  // Target: https://go.nuxtjs.dev/config-target
  target: "static",

  // デフォルトのソース管理を src/ に変更
  srcDir: "src/",

  // エントリーファイルindex.htmlの代わり
  head: {
    title: "try-vue-to-nuxt-todo",
    htmlAttrs: {
      lang: "en",
    },
    meta: [
      { charset: "utf-8" },
      { name: "viewport", content: "width=device-width, initial-scale=1" },
      { hid: "description", name: "description", content: "" },
      { name: "format-detection", content: "telephone=no" },
    ],
    link: [{ rel: "icon", type: "image/x-icon", href: "/favicon.ico" }],
  },

  // Global CSS: https://go.nuxtjs.dev/config-css
  css: [],

  // エントリーファイル(main.ts)で書いていたプラグインオプションなどを外だしして組み込む
  plugins: ["@/plugins/hoge.ts"],

  buildModules: [
    "@nuxtjs/eslint-module",
    "@nuxt/typescript-build",
    
    // Vue.js で使用した router の使い回し
    ["@nuxtjs/router", { fileName: "router/index.ts" }],
  ],
};

ある程度は nuxt.config.js で補完ができますが、できない部分もあります

  • src/App.vue
    • エントリーファイルから最初にマウントするコンポーネント[3]
    • Nuxt.js ではエントリーファイルである main.ts もないので代わりに layouts/default.vue で代替します
  • public/favicon.ico
    • Nuxt.js ではファビコンなどの滅多に変更されないファイルなどは static ディレクトリに保存します
    • srcDir に関連するディレクトリなので今回は src/static を作成してここにファビコンをコピーします

3. その他微修正

ここまでの修正である程度は動きますが、いくつかのファイルはさらに修正が必要です

router: createRouter 関数をexportする修正

開発環境を立ち上げると下記のワーニングが表示されます
Nuxt.js 側で認識する形式に合わせる必要があるため追記します

"export 'createRouter' (imported as 'customCreateRouter') was not found

src/router.ts
import Vue from "vue";
import VueRouter, { RouteConfig } from "vue-router";

Vue.use(VueRouter);

const routes: Array<RouteConfig> = [
  {
    path: "/",
    name: "Home",
    component: () =>
      import(/* webpackChunkName: "list" */ "@/pages/todo/todo-list").then(
        (m) => m.TodoListPage
      ),
  },
  {
    path: "/:id",
    name: "Detail",
    component: () =>
      import(/* webpackChunkName: "detail" */ "@/pages/todo/todo-detail").then(
        (m) => m.TodoDetailPage
      ),
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

// これを追加
export const createRouter = () => {
  return router;
};

export default router;

store: index.tsの扱いについて

Vue.js でデフォルトで作成される内容は下記のコード
このままでは Nuxt.js では Vuexのインスタンスを返す必要があるため、元のコードに修正を加える必要があります
使用する側の呼び出し方法を変更するか、 Nuxt.js ではモジュール単体でも認識してくれるため他のディレクトリに src/store/index.ts を移動させてエントリーファイルで呼び出すファイル自体を変更するのも手段の一つです

store/index.ts should export a method that returns a Vuex instance.

src/store/index.ts
import Vue from "vue";
import Vuex from "vuex";

Vue.use(Vuex);

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  modules: {},
});

plugins: エントリーファイルで設定していた内容を外だし

エントリーファイル(src/main.ts)でプラグインのオプションをpluginとしてそれぞれ書き出します
Nuxt Composition APIではTS用の関数が提供されているので、TSの対応をする場合はこちらのご利用をおすすめします

最後に

ここまでの対応で最低限 Nuxt.js(SPA) での動作が可能になるはずです
package.json に nuxt コマンドを追加して動作検証を行いましょう
大きな変更は行っていないので Vue.js or Nuxt.js どちらでも動作検証は行えるはずです
差分があるかどうかを確認しマージ作業を行うことで晴れて Nuxt.js への移行作業の第1段階は完了です

ここからより Nuxt.js に最適化するための作業はいくつか残っています

これらの対応は変更量の少ない部分から順に対応していくのがいいでしょう
SEO対策などで疲弊しているプロジェクトも多いかと思われますが、移行自体は簡単なのでプロジェクトの規模が大きくなる前に移行の検討をするのはいかがでしょうか?

誰かの手助けになれば幸いです

脚注
  1. 2021/08/01現在。 Google検索でヒットした記事を2ページ目(20記事)まで確認したけどめぼしいものはなかった ↩︎

  2. 持論です ↩︎

  3. 語弊があるかもしれない。 ↩︎

Discussion

しっぽくんしっぽくん
nuxt.config.js
  build: {
    extend(config) {
      config.module.rules.push({
        test: /\.(graphql|gql)$/,
        exclude: /node_modules/,
        loader: 'graphql-tag/loader',
      });
    },
  },

loaderを拡張する場合は↑感じで出来ます