簡単にVue.jsからNuxt.js(SPA)へ移行する手引き
こんにちは! しっぽくんです
Vue.js
をずっとやってきましたが、社内で Vue.js
から Nuxt.js
へ移行するプロジェクトが出てきたので参考程度に記事を書くことにしました
本記事では Vue.js
から Nuxt.js(SPA)
へ移行する手順を説明します
はじめに
Vue.js
から Nuxt.js
へ移行するモチベーションは色々あります
例えばSEO対策、SSR・SSGをやりたい、 middleware
や plugin
を使って楽をしたい、 Nuxt.js
特有の機能を使いたいなどなど…
「Vue.js Nuxt.js 移行」と検索すると様々な記事がヒットしますが、大抵がフルスクラッチか移行するメリットの列挙程度でした[1]
この記事では Vue.js
で作られたプロジェクトを Nuxt.js
へ移行する手順を示すことで上記に挙げている動機のお手伝いを出来ればと考えています
この記事のサンプルとして簡単なTodoアプリを作りました 参考程度にどうぞ
修正前
修正後
移行手順について
まず移行するための方針と全体の行程について考えていきます
方針
- 出来る限り元々のコードは修正しない
- 移行前後では
Vue.js(@vue/cli)
とNuxt.js(@nuxt/cli)
どちらでも動作できるようにする
大抵のプロジェクトは複数のメンバーで開発をしているため、不要なコンフリクトを生み出すのは避けるべきなので出来る限りコードの修正は行いません[2]
修正する場合は元の動作に影響がない範囲に抑えます
また移行直後に不具合があり開発がストップすることもなるべく避けるべきなので、一時的な共存をできるように修正します
全体の行程
-
nuxt
の導入 -
nuxt.config.js
の設定- ディレクトリ構成のギャップ補完
- エントリーポイントの対応
- ルーティングの上書き
- その他微修正
移行作業
nuxt
の導入
1. 必要なライブラリ群をインストールしていきます
npm i nuxt
npm i -D @nuxt/types @nuxt/typescript-build @nuxtjs/eslint-config-typescript @nuxtjs/eslint-module @nuxtjs/router
インストールしているものは Nuxt.js
をTSで作ったプロジェクトでデフォルトで入っているもの+routerを入れています
nuxt.config.js
の設定
2. Nuxt.js
では Vue.js
と違いディレクトリ名や場所そのものに意味があることや、 Vue.js
とは異なりエントリーファイルの扱いや Vueインスタンスにオプションを追加する方法など違いが多数あります
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. その他微修正
ここまでの修正である程度は動きますが、いくつかのファイルはさらに修正が必要です
createRouter
関数をexportする修正
router: 開発環境を立ち上げると下記のワーニングが表示されます
Nuxt.js
側で認識する形式に合わせる必要があるため追記します
"export 'createRouter' (imported as 'customCreateRouter') was not found
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.
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対策などで疲弊しているプロジェクトも多いかと思われますが、移行自体は簡単なのでプロジェクトの規模が大きくなる前に移行の検討をするのはいかがでしょうか?
誰かの手助けになれば幸いです
Discussion
loaderを拡張する場合は↑感じで出来ます