はじめに
会社でとある業務管理システムを開発していて、最近Vue2→Vue3に書き換えました。
しかしながら、だいぶ複雑な構造になりそうだったので、Nuxt.jsに乗せようと思い着手しました。
NuxtでもVue3 + Vuex4のまま書きたかったのですが、意外に試行錯誤したので、ここに備忘録として残します。
本記事で触れる事
Vue3とVuex4の基本的な記述を、Nuxt.js + Composition APIを使用して再現する
※Nuxt.jsの環境構築等は省略します。詳細は公式を参照してください。
開発環境
移行前(Vue3)の環境
"dependencies": {
"balm-ui": "^9.29.1",
"moment": "^2.29.1",
"theme": "^0.1.0",
"typescript": "^4.3.2",
"uikit": "^3.6.21",
"vue": "^3.0.11",
"vue-router": "^4.0.8",
"vuex": "^4.0.0",
"vuex-persistedstate": "^4.0.0-beta.1"
},
"devDependencies": {
"@parcel/transformer-typescript-tsc": "^2.0.0-beta.3.1",
"@parcel/transformer-vue": "2.0.0-beta.2",
"@parcel/validator-typescript": "^2.0.0-beta.3.1",
"@types/uikit": "^3.3.1",
"parcel": "^2.0.0-beta.2",
"sass": "^1.32.13"
},
移行後(Nuxt2)の環境
"dependencies": {
"@nuxtjs/axios": "^5.13.6",
"@nuxtjs/composition-api": "^0.24.5",
"@nuxtjs/dotenv": "^1.4.1",
"balm-ui": "^8.40.4",
"core-js": "^3.15.1",
"moment": "^2.29.1",
"nuxt": "^2.15.7",
"theme": "^0.1.0"
},
"devDependencies": {
"@nuxt/types": "^2.15.7",
"@nuxt/typescript-build": "^2.1.0",
"@types/uikit": "^3.3.1",
"fibers": "^5.0.0",
"nuxt-svg-loader": "^1.2.0",
"sass": "^1.35.1",
"sass-loader": "10.1.1",
"uikit": "^3.6.22"
}
※開発途中なので、まだ増えたり減ったりする予定です。
プロジェクト内ディレクトリ構造
ほとんどデフォルトのままです。※のところが解説で使用するファイルです。
├── assets
├── components
├── layouts
├── plugin
├── types
├── utils
├── pages
│ └── index.vue ※
├── store
│ ├── module1.ts ※
│ └── module2.ts ※
├── package.json
├── tsconfig.json
├── nuxt.config.ts
└── yarn.lock
@nuxtjs/composition-apiを使ってVue3 + Vuex4のように書く
Nuxtプロジェクトに@nuxtjs/composition-api
を追加します。
ちなみにnuxtjs/composition-apiの公式は こちら です。
Vuex4で書いたStoreを少し書き直す
createStore
は@nuxtjs/composition-api
やNuxtのvuex
にはなかったので、
試行錯誤しましたが、結局以下の書き方に落ち着きました。module2.ts
も同じように書きました。
import { InjectionKey, useStore as baseUseStore } from "@nuxtjs/composition-api";
import { Store as VuexStore, Commit } from "vuex";
//ファイル名(module1)でまとめる
export type StoreType1 = {
module1: StateType1
}
type StateType1 = {
data1: string;
data2: string;
}
export const key: InjectionKey<VuexStore<StateType1>> = Symbol();
//CreateStoreは使えない
export const state = (): StateType1 => ({
data1: "テスト1",
data2: "テスト2",
});
export const mutations = {
//省略
};
export const actions = {
setTestAction({ commit }: { commit: Commit }, payload: string) {
//Mutation.SET_TEST_ACTION は別ファイルにて定数で名前を定義
commit(Mutation.SET_TEST_ACTION, payload);
},
};
//useStoreをエクスポート
export const useStore = () => {
return baseUseStore(key);
};
storeをインポートする
index.vue
内は以下のようにしました。
<template>省略</template>
<script lang="ts">
//useStoreはVue3ではvuexからインポートしていたが、composition-apiからインポートする
import { defineComponent, reactive, useStore } from "@nuxtjs/composition-api";
//store内stateのtypeをインポート
import { StoreType1 } from "~/store/module1.ts"
import { StoreType2 } from "~/store/module2.ts"
//Vue3のcomposition APIと変わらない
export default defineComponent({
setup() {
const data = reactive({
aaa: "",
bbb: "",
});
//storeをインスタンス化
const store = useStore<StoreType1 & StoreType2>();
//console.log(store) => storeのモジュールがまとまって取得されている
//stateを試しに参照 - gettersも普通に使えると思われる
const m1 = store.state.module1;
const m2 = store.state.module2;
console.log(m1.data1) //=> テスト1
console.log(m1.data2) //=> テスト2
//値をセット
const setDatas = async () => {
//[モジュール名(ファイル名)]/[actionsで設定した名前]
await store.dispatch("module1/setTestAction", "test")
}
//以下省略
return { data };
},
});
</script>
<style lang="scss" scoped>
//省略
</style>
最後に
せっかくVue3の書き方に慣れたところで、そのままの記述で移行できないかと試行錯誤しました。
いろいろ調べたのですが、情報を探すのになかなか苦労したので記事にしました。
まだまだ改善すべき点はあるとは思いますが、まずは記録として。
その他参考記事
NuxtをTypeScript化する際に参考にさせて頂きました。