LaravelでTypeScript + Vue 3を導入する方法

## 目的
LaravelでVueを導入する場合、従来だとlaravel/ui → php artisan ui vueで立ち上げる流れですが、
このパッケージがてVue 2をデフォルトで入れてくるので、Vue 3のCompositional APIでTypeScriptを使った開発がしたい人（著作者）には何だか粋じゃない感じがします。

ので、LaravelでTypeScript + Vue 3を使う方法を解説します！

## まずはVue.jsを
1. laravelプロジェクトのRoot Directoryにcdして
1. npm install vue@next vue-loader@next @vue/compiler-sfcでVue関連のNPMパッケージをDevにインストール

```json:package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production"
    },
    "devDependencies": {
        "@vue/compiler-sfc": "^3.2.23",
        "axios": "^0.21",
        "laravel-mix": "^6.0.6",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "vue": "^3.2.23",
        "vue-loader": "^16.8.3"
    }
}

```

1. resources/js/componentsのフォルダーを作り、そこにApp.vueとかお好きなComponent名を作る
1.  webpack.mix.jsのSCSSのレンダーの後に、.vue()を実行する。これはWebpackに.vueのモジュールのCompilingを可能にしてくれる機能です。

```javascript:webpack.mix.js
const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]).vue();


```
https://laravel-mix.com/docs/6.0/vue


1. resources/js/app.jsを編集し添付写真のようにcreateAppでVueを起動させる

```javascript:app.js

import { createApp } from "vue";
import App from "./components/App.vue";

const app = createApp(App);

app.mount("#vue-app");
```
6. npm install && npm run devでWebpackにCompileをさせます。

要注意！
\<script>タグでapp.jsを読み込むが、HTMLのdivの後にしないとHMTLがレンダーされる前に実行され、Vueがタグを見つけられないというエラーを出します

ここまででJavaScriptのみのVue 3のセットアップが終わります。

## TypeScriptを導入

まず大胆に、resoucres/js/app.jsの拡張を.tsに変更します。

```typescript:resources/js/app.ts
import { createApp } from "vue";
import App from "./components/App.vue";

const app = createApp(App);

app.mount("#vue-app");

```

そしてwebpack.mix.jsでJavaScriptのCompilerからTypeScriptのCompilerに変更します。
また、'resources/js/app.js'を'resources/js/app.ts'に。

```javascript:webpack.mix.js

const mix = require('laravel-mix');
mix.ts('resources/js/app.ts', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]).vue();

```

npm install typescript -Dを実行すると、自動でts-loaderも入るはず。
出なければ npm install ts-loaderで追加。
-Dのオプションは--save-devと一緒。Vueも含め、Webpack MixがCompileしてくれるので、DevのDependenciesで十分。


```json:package.json
{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "npm run production",
        "production": "mix --production"
    },
    "devDependencies": {
        "@vue/compiler-sfc": "^3.2.23",
        "axios": "^0.21",
        "laravel-mix": "^6.0.6",
        "lodash": "^4.17.19",
        "postcss": "^8.1.14",
        "ts-loader": "^9.2.6",
        "typescript": "^4.5.2",
        "vue": "^3.2.23",
        "vue-loader": "^16.8.3"
    }
}


```

./にtsconfig.jsonを追加します。Vueの標準設定でいいが、念のために'resources/js/**/*'を追加することで全ての.tsファイルをCompileしてよーということになるので、しておいた方がいいと思われます。

```json:tsconfig.json

{
    "compilerOptions": {
        "target": "ES2015",
        "module": "ES2015",
        "strict": true,
        "jsx": "preserve",
        "moduleResolution": "node",
    },
    "include": ["./resources/js/**/*"]
}


```

## 問題発生：.vueのモジュールのTypeを指定しないとエラーになるど！

なので、上記のtsconfigにまずtypeRootsの設定でTypeを自動で読み込むフォルダーの場所を指定しましょう。


```json:tsconfig.json

{
    "compilerOptions": {
        "target": "ES2015",
        "module": "ES2015",
        "strict": true,
        "jsx": "preserve",
        "moduleResolution": "node",

        "typeRoots": ["./resources/js/@types"]

    },
    "include": ["./resources/js/**/*"]
}


```

そして'./resources/js/'のところに'@types'というフォルダーを作って、shims-vue.d.tsというファイルを入れます。
名前についてですが、任意かと思うのですが、Vue.jsのTypeScriptのDocumentsでは上記の名前にしているので、それに合わせて命名しましょう。

```typescript:./resources/js/@types/shim-vue.d.ts

declare module "*.vue" {
    import type { DefineComponent } from "vue";
    const component: DefineComponent<{}, {}, any>;
    export default component;
}


```

上記の設定でTypeScriptに.vueのモジュールのTypeを教えているのです。


最後に、npm install && npm run devであちこーこーのTypeScript + Vueのアプリが出来上がります！