【きっかけ】
- Laravel + Vue3 + Typescriptのセット、またVue3 + Typescript + vue-routerのセットの記事は探せば出てくるものの、4つ合わさった記事が見つからなかったので作成
【実行環境】
この記事で作成するプロジェクトの環境をDocker上で実現する記事を別途アップしています
「Docker上でLarevel + Vue3 + Typescriptを使いたかったから環境を作った」
(2022/12/08 追記)
【構築】
Laravelプロジェクト作成
- 今回はcomposerコマンドでプロジェクト「sample-project」を作成
composer create-project laravel/laravel sample-project
プロジェクト直下に移動
cd sample-project
パッケージインストール
npm install
Vue3インストール
npm install vue@next --save-dev
Typescriptインストール
npm install -D typescript ts-loader
vue-routerインストール
npm install vue-router@4
tsconfig.json作成
- プロジェクト直下にtsconfig.jsonを作成
- 内容は公式リファレンスを参照
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"moduleResolution": "node"
}
}
コンポーネントファイル作成
- resources/js/に<router-view>を配置するコンポーネントファイルを作成
- 今回はファイル名をApp.vueで作成
App.vue
<template>
<router-view></router-view>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
setup() {
}
})
</script>
- <router-view>にルーティングさせるコンポーネントファイルを作成
- 今回はresources/js/にディレクトリ「components」を作成し、その直下に
2つのコンポーネントファイル「Sano.vue」「Sena.vue」を作成
- 今回はresources/js/にディレクトリ「components」を作成し、その直下に
Sano.vue
<template>
<router-link to="/color/sena">遷移</router-link>
{{message}}
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
setup() {
const message = ref<string>("Yellow");
return {
message
};
}
});
</script>
Sena.vue
<template>
{{message}}
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
setup() {
const message = ref<string>("Purple");
return {
message
};
}
});
</script>
router.tsを作成
- resources/js/にrouter.tsを作成
- importのfromには該当コンポーネントファイルをresources/js/から見た相対パスで記載
- pathの階層は2階層以上が望ましい
- 最後に編集するweb.phpの設定のため
router.ts
import { createRouter,createWebHistory } from 'vue-router';
import sano from "./components/Sano.vue";
import sena from "./components/Sena.vue";
const routes = [
{ path: '/color/sano', name: 'sano', component: sano },
{ path: '/color/sena', name: 'sena', component: sena },
]
const router = createRouter({
history: createWebHistory(),
routes,
})
export default router;
app.ts作成
- resources/js/に存在するapp.jsの名称をapp.tsに変更
- app.tsの中身を変更
- 「App.vue」はさっき作成した<router-view>を配置するコンポーネントファイルのファイル名
app.ts
import { createApp } from "vue"
import router from './router';
import App from "./App.vue"
const app = createApp(App);
app.use(router);
app.mount("#app")
shims-vue.d.ts作成
- resources/js/にshims-vue.d.tsを作成
shims-vue.d.ts
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
webpack.mix.js編集
- プロジェクト直下に存在するwebpack.mix.jsの中身を編集
- app.jsと違いファイルの拡張子は変更しない
webpack.mix.js
// この部分を
mix.js('resources/js/app.js', 'public/js')
// 以下に差し替える
mix.ts('resources/js/app.ts', 'public/js').vue()
bladeファイル作成
- resources/views/にapp.blade.phpを作成
- ファイル名は任意
- headの要素にCSRF Tokenなど使いたいものは任意で追加
app.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<!-- 以下の1行がないとコンポーネントファイルの内容が反映されない -->
<script src="{{ asset('js/app.js') }}" defer></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
ルーティング編集
- routes/に存在するweb.phpを編集する
web.php
Route::get('/color/{any}', function () {
// さっき作成した「app.blade.php」から拡張子を除いた「app」をviewに記載
return view('app');
})->where('any', '.*');
-
以上の設定によって、
- localhost:8000/color/以下のURLにアクセスした際、必ずapp.blade.phpが開く
- app.tsに記載した
app.mount("#app")
によって、app.blade.phpの<div id="app"></div>
にApp.vueがマウントされているため、必ずApp.vueの内容が反映される - App.vueには
<view-router></view-router>
が存在するため、router.tsによって<view-router></view-router>
にはアクセスしたURLに対応するコンポーネントファイルの内容が反映される
となり、localhost:8000/color/以下のURLにアクセスした際はvue-routerの処理が優先される
- 簡潔に書くと、localhost:8000/color/までがLaravel側の処理、それ以降はvue-routerの処理となる
【動作確認】
Typescriptのコンパイル
npm run dev
Laravelプロジェクトを実行
php artisan serve
画面表示確認
-
http://localhost:8000/color/sanoにアクセスして以下の画面が表示されるか確認