はじめに
昨年のQiita記事の投稿数が5しかないという結果を受けてなんとか5を6にしてやろうと書いた記事です。
最近、Laravel8, Vue3, Typescript, Vuetify でアプリを作成したので備忘録として残します。
手順
1. Laravel アプリの作成
curl -s "https://laravel.build/laravel-vue3-typescript-vuetify" | bash
2. docker-compose.ymlを整理
コンテナのビルドに時間かけるの嫌だったので、とりあえずlaravelのコンテナだけにしました。
docker-compose.yml
# For more information: https://laravel.com/docs/sail
version: "3"
services:
laravel.test:
build:
context: ./vendor/laravel/sail/runtimes/8.1
dockerfile: Dockerfile
args:
WWWGROUP: "${WWWGROUP}"
image: sail-8.1/app
extra_hosts:
- "host.docker.internal:host-gateway"
ports:
- "${APP_PORT:-80}:80"
environment:
WWWUSER: "${WWWUSER}"
LARAVEL_SAIL: 1
XDEBUG_MODE: "${SAIL_XDEBUG_MODE:-off}"
XDEBUG_CONFIG: "${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}"
volumes:
- ".:/var/www/html"
networks:
- sail
# depends_on:
# - mysql
# - redis
# - meilisearch
# - selenium
# mysql:
# image: 'mysql/mysql-server:8.0'
# ports:
# - '${FORWARD_DB_PORT:-3306}:3306'
# environment:
# MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
# MYSQL_ROOT_HOST: "%"
# MYSQL_DATABASE: '${DB_DATABASE}'
# MYSQL_USER: '${DB_USERNAME}'
# MYSQL_PASSWORD: '${DB_PASSWORD}'
# MYSQL_ALLOW_EMPTY_PASSWORD: 1
# volumes:
# - 'sailmysql:/var/lib/mysql'
# networks:
# - sail
# healthcheck:
# test: ["CMD", "mysqladmin", "ping", "-p${DB_PASSWORD}"]
# retries: 3
# timeout: 5s
# redis:
# image: 'redis:alpine'
# ports:
# - '${FORWARD_REDIS_PORT:-6379}:6379'
# volumes:
# - 'sailredis:/data'
# networks:
# - sail
# healthcheck:
# test: ["CMD", "redis-cli", "ping"]
# retries: 3
# timeout: 5s
# meilisearch:
# image: 'getmeili/meilisearch:latest'
# platform: linux/x86_64
# ports:
# - '${FORWARD_MEILISEARCH_PORT:-7700}:7700'
# volumes:
# - 'sailmeilisearch:/data.ms'
# networks:
# - sail
# healthcheck:
# test: ["CMD", "wget", "--no-verbose", "--spider", "http://localhost:7700/health"]
# retries: 3
# timeout: 5s
# mailhog:
# image: 'mailhog/mailhog:latest'
# ports:
# - '${FORWARD_MAILHOG_PORT:-1025}:1025'
# - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025'
# networks:
# - sail
# selenium:
# image: 'selenium/standalone-chrome'
# volumes:
# - '/dev/shm:/dev/shm'
# networks:
# - sail
networks:
sail:
driver: bridge
# volumes:
# sailmysql:
# driver: local
# sailredis:
# driver: local
# sailmeilisearch:
# driver: local
3. Sailを使ってローカルで立ち上げ
もし何かエラーでたら、こちらご覧ください。
./vendor/bin/sail up
4. Vue3系の設定
インストール
./vendor/bin/sail npm install vue@next vue-loader@next @vue/compiler-sfc
webpack.mix.js の編集
webpack.mix.js
const mix = require("laravel-mix");
/*
|--------------------------------------------------------------------------
| Mix Asset Management
|--------------------------------------------------------------------------
|
| Mix provides a clean, fluent API for defining some Webpack build steps
| for your Laravel applications. By default, we are compiling the CSS
| file for the application as well as bundling up all the JS files.
|
*/
mix.js("resources/js/app.js", "public/js")
.postCss("resources/css/app.css", "public/css", [
//
])
.vue(); //追記
5. コンポーネントの作成
app.blade.php の作成
app.blade.php
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
<div id="app"></div>
</body>
</html>
resources/js/components/App.vue
<template>
<div>{{ message }}</div>
</template>
<script>
import { defineComponent, ref } from "vue";
export default defineComponent({
setup() {
const message = "Hello World";
return {
message
};
}
});
</script>
6. ルーティング追加
routes/web.php
Route::get('/app', function () {
return view('app');
});
7. ビルド
./vendor/bin/sail npm run dev
とりあえず Vue3は導入できました。
8. Typescript
インストール
./vendor/bin/sail npm install typescript ts-loader @types/webpack-env -D
app.js を app.tsにファイル名変更
それと同時に、webpack.mix.jsも変更
webpack.mix.js
const mix = require('laravel-mix');
mix.ts('resources/js/app.ts', 'public/js') //mix.jsをmix.tsに、app.jsをapp.tsに変更
.postCss('resources/css/app.css', 'public/css', [
//
]).vue();
mix.ts に変更できてなかったら、ビルドした際にこんなエラー出るのできちんと変更しましょう。
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /var/www/html/resources/js/components/App.vue: Unexpected token, expected ","
tsconfig.json作成
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"typeRoots": ["./resources/js/@types"],
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
},
"include": [
"resources/js/**/*.ts",
"resources/js/**/*.tsx",
"resources/js/**/*.vue"
],
"exclude": ["node_modules"]
}
9. @types以下の作成
resources/js/@types/shims-vue.d.ts
declare module "*.vue" {
import {defineComponent} from "vue";
const component: ReturnType<typeof defineComponent>;
export default component;
}
10. App.vue 変更
App.vue
<template>
<div>{{ message }}</div>
</template>
<script lang='ts'> //変更
import { defineComponent, ref } from "vue"; //変更
export default defineComponent({
setup() {
const message = ref<string>("Hello World"); //変更
return {
message
};
}
});
</script>
11. Vuetify の導入
sail npm install vuetify@next -D
app.tsの変更
resources/js/app.ts
import "vuetify/styles";
import { createApp } from "vue";
import { createVuetify } from "vuetify";
import * as components from "vuetify/lib/components";
import * as directives from "vuetify/lib/directives";
import App from "./components/App.vue";
const app = createApp(App);
const vuetify = createVuetify({ components, directives });
app.use(vuetify);
app.mount("#app");
App.vueの変更
resources/js/components/App.vue
<template>
<v-app>
<v-card>
<v-card-title>{{ message }}</v-card-title>
</v-card>
</v-app>
</template>
<script lang="ts">
import { defineComponent, ref } from "vue";
export default defineComponent({
setup() {
const message = ref<string>("Hello World");
return {
message,
};
},
});
</script>
tsconfig.json
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": "./",
"typeRoots": ["resources/js/@types"],
"types": ["vuetify"], ← これを追記
"lib": ["esnext", "dom", "dom.iterable", "scripthost"]
},
"include": [
"resources/js/**/*.ts",
"resources/js/**/*.tsx",
"resources/js/**/*.vue"
],
"exclude": ["node_modules"]
}
sail npm run dev
これでいけるはず
レポジトリも載せておきます。
おわりに
僕はこれにvue-router を加えて開発しました。
次は nuxt3 x Vuetify3 x Typescript でやってみたいですね。
間違ってるところとか、これ通りにできなければ教えてください。
参考記事