オリジナルのvue-codemodからフォークされた@originjs/vue-codemodを試してみる

# 結論

[vue-codemod](https://www.npmjs.com/package/vue-codemod)からフォークされた[@originjs/vue-codemod](https://www.npmjs.com/package/@originjs/vue-codemod)は意外と使える。
element-uiからelement-plusの変換もある。issueによると固定の古いバージョンに変換されるっぽい。
もうメンテナンスされていないツールなのかもしれない。

# Vue3.3へのアップグレード

```sh
vue upgrade
npm i vue@3.3
npm i -D @vue/compiler-sfc@3.3
npm uninstall vue-template-compiler -D
```

# eslint-plugin-vueのアップグレード

```sh
npm i eslint-plugin-vue@9 -D
```

# eslintの修正

変更前
```json
"plugin:vue/essential",
```
変更後
```json
"plugin:vue/vue3-recommended",
```

# vuex 4へのアップグレード


```sh
npm i vuex@4
```
# eslint実行

```sh
npm run lint
```

```sh
> vue-cli-service lint --fix

The following files have been auto-fixed:

  src\App.vue
  src\components\CountValue.vue
  src\components\HelloWorld.vue


\my-appvue\src\components\HelloWorld.vue
  113:5  warning  Prop 'msg' requires default value to be set  vue/require-default-prop

✖ 1 problem (0 errors, 1 warning)
```

# @originjs/vue-codemod実行

```sh
npx @originjs/vue-codemod src -a
```

# 動作確認

問題なし
```
npm run serve
```

## @originjs/vue-codemodの実行前後

my-appvue\src\App.vue

実行前
```vue
<template>
  <div id="app">
    <CountValue />
  </div>
</template>

<script>
import CountValue from './components/CountValue.vue';

export default {
  name: 'app',
  components: {
    CountValue,
  },
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

実行後
```vue
<template>
  <div id="app">
    <CountValue />
  </div>
</template>

<script>
import CountValue from './components/CountValue.vue';

export default {
  name: 'App',
  components: {
    CountValue,
  },
};
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

my-appvuey\src\main.js

「new Vue」が「Vue.createApp」に変わっている。
「import Vue from 'vue';」は「import { createApp } from 'vue';」に変更して、
「Vue.createApp」は「createApp」に変更したほうがよい。


実行前
```js
import Vue from 'vue';
import App from './App.vue';
import store from './store';

Vue.config.productionTip = false;

new Vue({
  store,
  render: (h) => h(App),
}).$mount('#app');
```

実行後
```js
import * as Vue from 'vue';
import App from './App.vue';
import store from './store';

const app = Vue.createApp(App).use(store);
app.mount("#app");
```

my-appvuey\src\store.js

「Vuex.Store」が「Vuex.createStore」に変わっている。
「import * as Vuex from 'vuex';」は「import { createStore } as Vuex from 'vuex';」に変更して、
「Vuex.createStore」は「createStore」に変更したほうがよい。

実行前
```js
import Vue from 'vue';
import Vuex from 'vuex';
import counter from './store/modules/counter';
import VuexPersist from 'vuex-persist';

Vue.use(Vuex);

const vuexLocalStorage = new VuexPersist({
  key: 'sano-vuex', // The key to store the state on in the storage provider.
  storage: window.localStorage, // or window.sessionStorage or localForage
  // Function that passes the state and returns the state with only the objects you want to store.
  // reducer: state => state,
  // Function that passes a mutation and lets you decide if it should update the state in localStorage.
  //
});

export default new Vuex.Store({
  strict: process.env.NODE_ENV !== 'production',
  modules: {
    counter,
  },
  state: {},
  mutations: {},
  actions: {},
  plugins: [vuexLocalStorage.plugin],
});
```

実行後
```js
import * as Vuex from 'vuex';
import counter from './store/modules/counter';
import VuexPersist from 'vuex-persist';

const vuexLocalStorage = new VuexPersist({
  key: 'sano-vuex', // The key to store the state on in the storage provider.
  storage: window.localStorage, // or window.sessionStorage or localForage
  // Function that passes the state and returns the state with only the objects you want to store.
  // reducer: state => state,
  // Function that passes a mutation and lets you decide if it should update the state in localStorage.
  //
});

export default Vuex.createStore({
  strict: process.env.NODE_ENV !== 'production',
  modules: {
    counter,
  },
  state: {},
  mutations: {},
  actions: {},
  plugins: [vuexLocalStorage.plugin],
});
```

my-appvuey\src\store\modules\counter.js

変更なし

実行前
```js
const state = {
  step: 1,
  count: 0,
};

const getters = {
  step: (state) => state.step,
  count: (state) => state.count,
};

const actions = {
  increment({ commit }) {
    commit('increment');
  },
};

const mutations = {
  increment(state) {
    state.count += state.step;
  },
};

export default {
  state,
  getters,
  actions,
  mutations,
};
```

実行後

```js
const state = {
  step: 1,
  count: 0,
};

const getters = {
  step: (state) => state.step,
  count: (state) => state.count,
};

const actions = {
  increment({ commit }) {
    commit('increment');
  },
};

const mutations = {
  increment(state) {
    state.count += state.step;
  },
};

export default {
  state,
  getters,
  actions,
  mutations,
};
```

my-appvuey\src\components\CountValue.vue

eslintで修正されたところ以外の変更無し

実行前
```vue
<template>
  <div>
    <button @click="increment">increment {{ step }}</button>
    <span>total {{ count }}</span>
  </div>
</template>

<script>
export default {
  name: 'CountValue',
  computed: {
    step() {
      return this.$store.getters.step;
    },
    count() {
      return this.$store.getters.count;
    },
  },
  methods: {
    increment() {
      this.$store.dispatch('increment');
    },
  },
};
</script>

<style scoped></style>
```

実行後
```vue
<template>
  <div>
    <button @click="increment">
      increment {{ step }}
    </button>
    <span>total {{ count }}</span>
  </div>
</template>

<script>
export default {
  name: 'CountValue',
  computed: {
    step() {
      return this.$store.getters.step;
    },
    count() {
      return this.$store.getters.count;
    },
  },
  methods: {
    increment() {
      this.$store.dispatch('increment');
    },
  },
};
</script>
```

## メモ

他に[gogocode](https://www.npmjs.com/package/gogocode)というのもあるので試してみたい。