Vue.js3でSFC（単一ファイルコンポーネント）を使う環境の構築

# はじめに
本記事は、以下の記事（Vue.js2を使用）を、Vue.js3にアップグレードした記事になります。
 [Vue.jsのSFC（単一ファイルコンポーネント）＋PHPでWebアプリケーションを構築する - フロントエンド環境編
](https://qiita.com/ison12/items/b336766bd6ca01cd62a3)

Vue CLIは使っていませんので、悪しからず。

# Vue.js2をVue.js3にアップグレードするには
まず、前提となった記事で既にVue.js2で動作する環境が出来上がっているものとします。

## npmインストール
npmでVue.js2関連のライブラリをインストールしているので、まずはこれらを削除することにします。

```コマンドプロンプト
npm uninstall vue
npm uninstall vue-loader
npm uninstall vue-template-compiler
```

次に、Vue.js3に関連するライブラリをインストールします。

```コマンドプロンプト
npm install -D vue@next
npm install -D @vue/compiler-sfc
npm install -D vue-style-loader
npm install -D vue-loader@16.1.2
```

**HINT**

* vueは、vue@nextに置き換わりました。
* vue-template-compilerは、@vue/compiler-sfcに置き換わりました。
* vue-loaderは、ver16以降を指定します。  
* vue-style-loaderは単独でのインストールが必要になったので明示指定しています。

## webpack設定の書き換え
以下の通りに書き換えました（☆☆☆の部分）。

```webpack.common.js
// webpack common setting
const path = require('path');
const {VueLoaderPlugin} = require('vue-loader');

const prefixUri = "/hello-vuejs";
const settings = {
    resolve: {
        modules: [
            path.resolve('./src'),
            path.resolve('./node_modules')
        ]
    },
    entry: path.resolve(__dirname, 'src', 'main.js'),
    output: {
        path: path.resolve(__dirname, 'public'),
        filename: 'dist/bundle.js',
        publicPath: prefixUri + "/"
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            // this will apply to both plain `.js` files
            // AND `<script>` blocks in `.vue` files
            {
                test: /\.js$/,
                loader: 'babel-loader'
            },
            // this will apply to both plain `.css` files
            // AND `<style>` blocks in `.vue` files
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'css-loader'
                ]
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin()
    ]
};

module.exports = {
    prefixUri: prefixUri,
    settings: settings
};
```

## main.jsの書き換え
以下の通りに書き換えました（☆☆☆の部分）。

```main.js
// -----------------------------------------------------------------------------
// ライブラリのインポート
// -----------------------------------------------------------------------------
// VueJs
import { createApp, h } from 'vue'; // ☆☆☆

// -----------------------------------------------------------------------------
// GETパラメータの取得
// -----------------------------------------------------------------------------
let queryObject = {};

if (window.location.search) {

    // 1文字目がクエスチョン'?'になっているので、substringで2文字目以降を取得する
    const queryString = window.location.search.substring(1);
    // '&'キーワードで分解する
    var parameters = queryString.split('&');

    for (let i = 0, ilen = parameters.length; i < ilen; i++) {

        // '='キーワードでキーと値に分解する
        var element = parameters[i].split('=');

        // デコードを忘れずに実施する
        var paramName = decodeURIComponent(element[0]);
        var paramValue = decodeURIComponent(element[1]);

        queryObject[paramName] = paramValue;
    }
}

// ------------------------------------------------------------------------------
// 動的インポートを実施
// ------------------------------------------------------------------------------
// URL指定例）
// http://localhost:8080/hello-vuejs/index.html?componentPath=/Func/Hello/Front/View/Hello
// http://localhost:8080/hello-vuejs/index.html?componentPath=/Func/Goodbye/Front/View/Goodbye
if (typeof queryObject['componentPath'] !== 'undefined') {

    // componentPathを以下のルールで変換
    // 例）
    //    /Func/Hello/Front/View/Hello
    //     ↓
    //   ./Func/Hello/Front/View/Hello.vue
    const componentPath = queryObject['componentPath'];
    const componentId = componentPath.substring(componentPath.lastIndexOf('/') + 1);

    const componentLoadPromise = import("./" + componentPath.replace(/^\//, "") + ".vue");

    componentLoadPromise.then(function (value) {
        // 動的インポート完了

        const app = createApp(h(value.default)).mount('#app'); // ☆☆☆
    });

} else {
    console.warn('componentPathパラメータが見つかりませんでした。');
}
```

# 参考
[Vue.js3をプレビューしたソース](https://github.com/vuejs/vue-next-webpack-preview)
[Vue.js3での変更箇所をまとめた記事 - その1](https://blog.capilano-fw.com/?p=6393#Vue)
[Vue.js3での変更箇所をまとめた記事 - その2](https://vuejsdevelopers.com/2020/03/16/vue-js-tutorial/)

# 成果物
[Vue.js2の元のソース（前回作成したソース）](https://github.com/ison12/helloVuejs)
[Vue.js3のソース（今回作成したソース）](https://github.com/ison12/helloVuejs3)

# まとめ
VueCLIを使わないでVue.jsを使おうとすると途端に難易度が上がります。