laravel inertia vue
組み方をまとめておきたい
vueを流行らせるぞ!!!
sailは使わずに構築する
勝手に置き換えてね
適宜git commitしていくのがコツだよ
$ composer create-project laravel/laravel test-laravel-inertia-vue3-ts
$ cd test-laravel-inertia-vue3-ts
$ php artisan serv
これで http://localhost:8000 を見ればHOMEが開けるはず
次に Inertia.js を入れる
これは Laravel で Vue や React の SPA を使うためのもの
NUXT / NEXT の代わりに Laravel って思えばOK
Breeze や Jetstream といったテンプレートもあるが、置き換えが面倒くさいので手動で入れる
$ composer require inertiajs/inertia-laravel
$ touch ./resources/views/app.blade.php
app.blade.php
が基本となるHTML
このページが呼び出され、SPAが構築される
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
@vite('resources/js/app.js')
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
次にmiddlewareを作成する
このmiddlewareはSPA側とのグローバル変数定義だと思ってOK
$ php artisan inertia:middleware
これを web Kernel に追加する
protected $middlewareGroups = [
'web' => [
...,
\App\Http\Middleware\HandleInertiaRequests::class,
],
],
次にフロント側
$ npm install @inertiajs/vue3
resources/js/app.js
を上書きして以下に書き換える
これは各フレームワークのbootstrapの要素
(そのため、既存のbootstrap.jsは削除して問題ない)
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
createInertiaApp({
resolve: name => {
const pages = import.meta.glob('./pages/**/*.vue', { eager: true })
return pages[`./pages/${name}.vue`]
},
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})
vite に vue の解釈ができるようにする
$ npm install -D @vitejs/plugin-vue
vite.config.js に vue()
を増やす
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [
vue(),
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
],
});
適当にページを作ってみる
ページは resources/js/pages/...
に記載する
Laravel的には先頭大文字推奨なのだが、vueの流儀に則って小文字にする
<template>
<div>
<Head title="ようこそ" />
<h1>ようこそ</h1>
<p>こんにちは {{ name }} さん。</p>
</div>
</template>
<script setup>
import { Head } from '@inertiajs/vue3'
defineProps({ user: String })
</script>
このルーティングは web route に書き込む
これは blade とかと同じ書き方
変数を渡すと、defineProps として受け取れる
Route::get('/', function () {
return Inertia::render('index', [
'name' => '山田太郎',
]);
})->name('home');
これは controller に書くことも可能(推奨)
開発中の起動には2つのコマンドの常時実行が必要
$ npm run dev
$ php artisan serve
Inertia はデフォルトだと js なので ts に書き換えていく
$ npm install -D typescript @vue/tsconfig
$ touch tsconfig.json
tsconfig.json
は @vue/tsconfig
をベースにする
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": [
"resources/**/*.ts",
"resources/**/*.d.ts",
"resources/**/*.vue"
],
"compilerOptions": {
"baseUrl": ".",
"types": ["vite/client"],
"paths": {
"@/*": ["resources/js/*"]
}
}
}
resources/js
を resources/ts
に置き換える
app.js
は app.ts
に変更する
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import type { DefineComponent } from "vue";
createInertiaApp({
resolve: (name) => resolvePageComponent(
`./pages/${name}.vue`,
import.meta.glob<DefineComponent>("./pages/**/*.vue")
),
setup({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.mount(el)
},
})
先程作ったpage要素も ts に変換する
<script setup lang="ts">
import { Head } from '@inertiajs/vue3'
defineProps<{
name: string,
}>()
</script>
以下のjsパスをtsに書き換える
resources/views/app.blade.php
tsconfig.json
vite.config.ts
@vite('resources/ts/app.ts')
'resources/ts/app.ts'
"@/*": ["resources/ts/*"]
npm run dev
を実行してエラーが出なければ成功!!
vue の auto import を入れる
unplugin シリーズを入れると、NUXT と同じように無駄な import を書かなくて済むようになる
無くても問題はないが、入れて損は無い
$ npm install -D unplugin-vue-components unplugin-auto-import
vite.config.js
に組み込む
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from "@vitejs/plugin-vue";
import Components from 'unplugin-vue-components/vite';
import AutoImport from 'unplugin-auto-import/vite';
export default defineConfig({
plugins: [
vue(),
Components({
dts: 'resources/ts/types/components.d.ts',
dirs: ['resources/ts/components'],
}),
AutoImport({
dts: 'resources/ts/types/auto-imports.d.ts',
dirs: ['resources/ts/composables'],
imports: ['vue'],
}),
laravel({
input: ['resources/ts/app.ts'],
refresh: true,
}),
],
});
components は dirs
にあるvueコンポーネントをvueのどこからでも呼び出せるようになる
auto-import は imports
dirs
の設定にファイルを入れると、vueのどこからでも呼び出せるようになる
vueはプリセットがある
また、特定のフォルダ(composable)や外部ライブラリ(imports)にも使うことが可能
これらの生成ファイルは types ってフォルダに入れるのがおすすめ
なので resources/types/**
に型ファイルを作成するようにする
git に入れるものでは無いので .gitignore に入れておく
auto-imports.d.ts
components.d.ts
npm run dev
など、ビルドが走ったときにファイルが更新される
初めての起動時はIDEの再起動などが必要になる場合あり
試しに使ってみる
export const useCounter = () => {
const counter = ref<number>(0)
const increment = () => { counter.value ++ }
const decrement = () => { counter.value -- }
return {
value: readonly(counter),
increment,
decrement,
}
}
<template>
<div>
<Head title="ようこそ" />
<h1>ようこそ</h1>
<p>こんにちは {{ name }} さん。</p>
<Counter />
</div>
</template>
<script setup lang="ts">
import { Head } from '@inertiajs/vue3'
defineProps<{
name: string,
}>()
</script>
<template>
<div>
<p>counter: {{ counter.value }}</p>
<button @click="counter.increment()">+</button>
<button @click="counter.decrement()">-</button>
</div>
</template>
<script setup lang="ts">
const counter = useCounter()
</script>
こんな感じ
@inertiajs/vue3
も自動インポートに適用可能だが、名称がかぶると大変なので、一旦は適用しない
ziggy を入れる
これは Laravel の route()
関数をフロントでも使えるようにするもの
$ composer require tightenco/ziggy
$ npm install ziggy-js
$ npm install -D @types/ziggy-js
これを使えるようにする
公式だと、vueのpluginで入れるように書いてあるが、少々面倒くさい
また隠匿されるわけでもなく、route型も特に効かないので、auto-import で入れるほうが簡単
$ composer require tightenco/ziggy
$ npm install ziggy-js
$ npm install -D @types/ziggy-js
vite.config.js
の autoImport に生やす
AutoImport({
dts: 'resources/ts/types/auto-imports.d.ts',
dirs: ['resources/ts/composables'],
imports: [
'vue',
{
'ziggy-js': [['default', 'route']],
}
],
}),
これは import * as route fron 'ziggy-js'
と同義らしい
app.blade.php に @routes
を増やす
これにURL配列が展開される
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
@routes
@vite('resources/ts/app.ts')
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
そして indev.vue
にでも書いてみる
console.log(route('home'))
baseURLも勝手に展開される
残念ながら typehint はできないみたい...(調査中)
linterを整備していく
$ npm install --save-dev eslint eslint-plugin-vue eslint-config-standard vite-plugin-eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
"scripts": {
"lint": "eslint resources/**/*.{js,ts,vue}"
},
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'
import eslint from 'vite-plugin-eslint'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
const isProd = process.env.NODE_ENV = 'production'
export default defineConfig({
base: './',
plugins: [
vue(),
Components({
dts: 'resources/ts/types/components.d.ts',
dirs: ['resources/ts/components'],
}),
AutoImport({
dts: 'resources/ts/types/auto-imports.d.ts',
dirs: ['resources/ts/composables'],
imports: [
'vue',
{
'ziggy-js': [['default', 'route']],
}
],
eslintrc: {
enabled: true,
},
}),
!isProd && eslint({
lintOnStart: true,
include: 'resources/ts/**/*.{js,jsx,ts,tsx,vue}',
fix: true,
}),
laravel({
input: ['resources/ts/app.ts'],
refresh: true,
}),
],
})
{
"env": {
"node": true,
"commonjs": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:vue/vue3-recommended",
"./.eslintrc-auto-import.json",
"standard"
],
"parserOptions": {
"parser": "@typescript-eslint/parser",
"sourceType": "module"
},
"rules": {
"comma-dangle": ["warn", "only-multiline"],
"no-unused-vars": "warn",
"@typescript-eslint/no-unused-vars": "warn",
"vue/no-unused-vars": "warn",
"require-await": "warn",
"no-unreachable": "warn",
"vue/multi-word-component-names": "off",
"vue/no-v-model-argument": "off"
}
}
ついでに vite.config.js を vite.config.ts に置き換える
larastan
composer require nunomaduro/larastan --dev
includes:
- ./vendor/nunomaduro/larastan/extension.neon
parameters:
paths:
- app/
# Level 9 is the highest level
level: 5
# ignoreErrors:
# - '#PHPDoc tag @var#'
#
# excludePaths:
# - ./*/*/FileToBeExcluded.php
#
# checkMissingIterableValueType: false
pint は最初から入ってるみたい
{
"preset": "laravel",
"rules": {
"no_superfluous_phpdoc_tags": false,
"phpdoc_separation": false
}
}
lint と stan を追加する
"scripts": {
"lint": [
"./vendor/bin/pint"
],
"stan": [
"./vendor/bin/phpstan analyse --memory-limit=2G"
]
},
taiwind追加
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init
追記
/** @type {import('tailwindcss').Config} */
export default {
content: [
'./resources/**/*.{vue,js,ts,php}'
],
theme: {
extend: {},
},
plugins: [],
}
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
tsに css を食わせる
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'
import type { DefineComponent } from 'vue'
import '../css/app.css'
createInertiaApp({
postcss に食わせる
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
デフォルトのデザインが消えたが、ちゃんとtailwindの色がついている
stylelintをeslintに組み込む
npm install eslint-config-stylelint --save-dev
{
"extends": ["stylelint"]
}
{
"extends": "stylelint-config-standard",
"rules": {}
}
stylelintはまた今度やる
ui は primevue が tailwind 二対応したので、これを使う
テーマはここから選ぶ
npm install primevue
自動インポートは対応済み
import { PrimeVueResolver } from 'unplugin-vue-components/resolvers'
const isProd = process.env.NODE_ENV = 'production'
export default defineConfig({
base: './',
plugins: [
vue(),
Components({
dts: 'resources/ts/types/components.d.ts',
dirs: ['resources/ts/components'],
resolvers: [PrimeVueResolver()],
}),
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'
import type { DefineComponent } from 'vue'
import PrimeVue from 'primevue/config'
import Tailwind from 'primevue/passthrough/tailwind'
import '../css/app.css'
createInertiaApp({
resolve: (name) => resolvePageComponent(
`./pages/${name}.vue`,
import.meta.glob<DefineComponent>('./pages/**/*.vue')
),
setup ({ el, App, props, plugin }) {
createApp({ render: () => h(App, props) })
.use(plugin)
.use(PrimeVue, { unstyled: true, pt: Tailwind })
.mount(el)
},
})
tailwind.config.jsにはんえい
/** @type {import('tailwindcss').Config} */
export default {
content: [
'./resources/**/*.{vue,js,ts,php}',
'./node_modules/primevue/**/*.{vue,js,ts,jsx,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}
できた
デザインは pass throwgh で変えられるみたい
上書きは ptOptions
data-pc-section ってのがキー
それに対して未指定ならclassをつけられる
clockwork ide-helper lang を入れていく
composer require itsgoingd/clockwork
php artisan vendor:publish
'enable' => env('APP_DEBUG', env('CLOCKWORK_ENABLE', null)),
enable を DEBUGと連動させる
composer require --dev barryvdh/laravel-ide-helper
php artisan ide-helper:generate
php artisan ide-helper:generate
php artisan ide-helper:models --nowrite
php artisan ide-helper:meta
db に繋がってないとエラーだよ
ignore二追加する
_ide_helper.php
_ide_helper_models.php
.phpstorm.meta.php
composer require laravel-lang/common --dev
php artisan lang:add ja
php artisan lang:update
config を調整していく
- app.php
- 'timezone' => 'Asia/Tokyo'
- 'locale' => 'ja',
- 'faker_locale' => 'ja_JP'
自分以外をgitignoreするとき
*
!.gitignore
ziggy の ts化
ziggy は vendor:publish がないため、自作する
<?php
return [
'output' => [
'path' => 'resources/ts/types/ziggy.js'
],
];
php artisan ziggy:generate --types-only
resolvePageComponent で default layout を突っ込む方法
global に生やす方法