2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

DENSOAdvent Calendar 2023

Day 18

Vue2 ⇒ Vue3への移行日記 ~ビルド編~

Last updated at Posted at 2023-12-18

はじめに

この記事は DENSO アドベントカレンダー 2023 の18日目の記事です。

私は、社内でWebアプリを開発しているのですが、Rails6×Vue2で作っています。
ただ、Vue2のサポートが今年いっぱいで切れてしまうので、Vue3へ移行することになりました。
せっかくなので、移行の経緯を残しておこうと思い、筆を執っています!

前回Vue3対応のライブラリに更新したので、今回はVue3でビルドできるようにしていきます。

現状のビルド

現状の環境は下記のようになっています。

  • Rails 6.1.7.6
  • webpack 5.78.0
  • jsbundling-rails 1.2.1
  • Vue 3.3.12

Rails6でよく使われるWebpackerはRails7で不要になったことにより引退済みなので、jsbundling-rails + webpackにすでに切り替えてあります。

webpack.config.jsjsbundling-railsGithubの内容をベースにVue用に追加・修正しています。

webpack.config.js
const path = require("path");
const webpack = require("webpack");
const mode = process.env.RAILS_ENV === 'production' ? 'production' : 'development';
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FixStyleOnlyEntriesPlugin = require('webpack-fix-style-only-entries');

module.exports = {
  mode,
  entry: {
    // add your css or sass entries
  },
  output: {
    filename: "[name].js",
    path: path.resolve(__dirname, '..', '..', 'app/assets/builds')
  },
  optimization: {
    moduleIds: 'deterministic',
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.(sa|sc|c)ss$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
      },
    ]
  },
  resolve: {
    alias: {
      'vue': path.resolve('./node_modules/vue')
    },
    extensions: ['.js', '.jsx', '.scss', '.css'],
  },
  plugins: [
    new VueLoaderPlugin(),
    new FixStyleOnlyEntriesPlugin(),
    new MiniCssExtractPlugin(),
  ],
}

エラーを1つずつ解決していく

現状でビルドすると、下記エラーが出てきます。

[webpack-cli] Error: Cannot find module 'vue-loader/lib/plugin'

vue-loaderのライブラリをバージョンアップ影響ですね。
公式ドキュメントwebpack.config.jsの書き方が載っていたので、そのとおりに修正します。

また、方針決定編に記載した通り、Vue3に移行しますが、Options APIを使い続けることにしています。Vue3でOptions APIを使うにはwebpack.config.jsに設定が必要です。
加えて、ビルドのエラーを解消した後にブラウザから画面を確認するとコンソールに下記のようなメッセージが表示されます。

Feature flags __VUE_OPTIONS_API__, __VUE_PROD_DEVTOOLS__ are not explicitly defined

こちらも解消するために、__VUE_PROD_DEVTOOLS__webpack.config.jsに明示的に設定しておきます。

webpack.config.js
const webpack = require("webpack");
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
    // 省略
    plugins: [
        new VueLoaderPlugin(),
        new webpack.DefinePlugin({
            __VUE_OPTIONS_API__: true,
            __VUE_PROD_DEVTOOLS__: false,
        }),
    ]
}

この修正で、webpack.config.jsの設定自体は問題がなくなりました。

再度ビルドしてみると、エラーもワーニングも大量に出ています。だいぶ気分が萎える量のエラーとワーニングですが、こちらも1つずつ解決していきます。
一番多いワーニングは、各javascriptファイルでvueをインポートする箇所です。

export 'default' (imported as 'Vue') was not found in 'vue'

調べてみるとVue2からVue3でVueインスタンスの生成方法コンポーネント登録プラグインインストール方法が変わったようです。

// Vue2
import $ from 'jquery';
import Vue from 'vue';
import App from '../components/App.vue';
import MyComponent from 'mycomponent';
import MyPlugin from './plugins/MyPlugin';

Vue.component('my-component', MyComponent);
Vue.use(MyPlugin);

document.addEventListener('DOMContentLoaded', () => {
  new Vue({el: '#app', render: h => h(App, {props: {}})}).$mount();
});
// Vue3
import $ from 'jquery';
import { createApp, h } from 'vue';
import App from '../components/App.vue';
import MyComponent from 'mycomponent';
import MyPlugin from './plugins/MyPlugin';

document.addEventListener('DOMContentLoaded', () => {
  createApp({render: () => h(App, {})}).component('my-component', MyComponent).use(MyPlugin).mount('#app');
});

大量にあるVueファイルをすべて書き換えていきます。
これでワーニングは全てなくなりました。

残りのエラーですが、前回更新したvue-multiselectが読み込めないとエラーが出ます。
どうも元々の読み込み方が良くなかったようで、こちらも、公式ドキュメントを参考に、インポートする箇所を修正します。

<template>
</template>

<script>
import VueMultiselect from 'vue-multiselect'
import 'vue-multiselect/dist/vue-multiselect.css'
export default {
  components: { VueMultiselect },
  data () {
    return {
    }
  }
}
</script>

最後に残ったエラーは<をHTMLの平文で使っているというエラーでした。

VueCompilerError: Illegal tag name. Use '&lt;' to print '<'.

エラーメッセージにあるように&lt;に置き換えたらすんなりエラーが消えてくれました。

終わりに

これで無事にビルドでのエラー・ワーニングは全て対処できました。
ビルドが一番苦戦するかと思ったのですが、思っていたよりはすんなり解決できました。

残りは、画面を1つずつ確認していきながら動作がおかしいところを直していく作業になります!
記事にできそうなことがあったら、続編を執筆します。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?