471 lines
11 KiB
Markdown
471 lines
11 KiB
Markdown
# Laravel + Vue.js + Vue Router Setup Guide
|
|
|
|
Panduan lengkap untuk setup Laravel dengan Vue.js 3, Vue Router, dan Tailwind CSS menggunakan Vite.
|
|
|
|
## Prerequisites
|
|
|
|
- PHP >= 8.1
|
|
- Composer
|
|
- Node.js >= 16.x
|
|
- NPM atau Yarn
|
|
|
|
## Step 1: Instalasi Laravel
|
|
|
|
```bash
|
|
# Buat project Laravel baru
|
|
composer create-project laravel/laravel project-name
|
|
|
|
# Masuk ke directory project
|
|
cd project-name
|
|
|
|
# Setup environment
|
|
cp .env.example .env
|
|
php artisan key:generate
|
|
```
|
|
|
|
## Step 2: Instalasi Dependencies Frontend
|
|
|
|
```bash
|
|
# Install Vue.js dan dependencies
|
|
npm install vue@latest vue-router@latest
|
|
|
|
# Install Vite plugins
|
|
npm install --save-dev @vitejs/plugin-vue
|
|
|
|
# Install Tailwind CSS
|
|
npm install --save-dev tailwindcss@latest @tailwindcss/vite
|
|
|
|
# Install utilities
|
|
npm install --save-dev axios concurrently
|
|
```
|
|
|
|
### Package.json Final
|
|
```json
|
|
{
|
|
"$schema": "https://json.schemastore.org/package.json",
|
|
"private": true,
|
|
"type": "module",
|
|
"scripts": {
|
|
"build": "vite build",
|
|
"dev": "vite"
|
|
},
|
|
"devDependencies": {
|
|
"@tailwindcss/vite": "^4.0.0",
|
|
"@vitejs/plugin-vue": "^6.0.1",
|
|
"axios": "^1.11.0",
|
|
"concurrently": "^9.0.1",
|
|
"laravel-vite-plugin": "^2.0.0",
|
|
"tailwindcss": "^4.0.0",
|
|
"vite": "^7.0.4"
|
|
},
|
|
"dependencies": {
|
|
"vue": "^3.5.19",
|
|
"vue-router": "^4.5.1"
|
|
}
|
|
}
|
|
```
|
|
|
|
## Step 3: Konfigurasi Vite
|
|
|
|
Buat/update `vite.config.js`:
|
|
|
|
```javascript
|
|
import { defineConfig } from "vite";
|
|
import laravel from "laravel-vite-plugin";
|
|
import tailwindcss from "@tailwindcss/vite";
|
|
import vue from '@vitejs/plugin-vue';
|
|
|
|
export default defineConfig({
|
|
plugins: [
|
|
laravel({
|
|
input: ["resources/css/app.css", "resources/js/app.js"],
|
|
refresh: true,
|
|
}),
|
|
tailwindcss(),
|
|
vue()
|
|
],
|
|
resolve: {
|
|
alias: {
|
|
vue: 'vue/dist/vue.esm-bundler.js',
|
|
},
|
|
},
|
|
});
|
|
```
|
|
|
|
## Step 4: Setup Tailwind CSS
|
|
|
|
Buat `tailwind.config.js`:
|
|
|
|
```javascript
|
|
/** @type {import('tailwindcss').Config} */
|
|
export default {
|
|
content: [
|
|
"./resources/**/*.blade.php",
|
|
"./resources/**/*.js",
|
|
"./resources/**/*.vue",
|
|
],
|
|
theme: {
|
|
extend: {},
|
|
},
|
|
plugins: [],
|
|
}
|
|
```
|
|
|
|
Update `resources/css/app.css`:
|
|
|
|
```css
|
|
@import 'tailwindcss';
|
|
```
|
|
|
|
## Step 5: Struktur Folder Frontend
|
|
|
|
Buat struktur folder berikut di `resources/js/`:
|
|
|
|
```
|
|
resources/js/
|
|
├── components/
|
|
│ └── App.vue
|
|
├── pages/
|
|
│ ├── Home.vue
|
|
│ ├── About.vue
|
|
│ └── Contact.vue
|
|
├── router/
|
|
│ └── index.js
|
|
└── app.js
|
|
```
|
|
|
|
## Step 6: Setup Vue Router
|
|
|
|
### `resources/js/router/index.js`
|
|
```javascript
|
|
import { createRouter, createWebHistory } from 'vue-router'
|
|
import Home from '../pages/Home.vue'
|
|
import About from '../pages/About.vue'
|
|
import Contact from '../pages/Contact.vue'
|
|
|
|
const routes = [
|
|
{
|
|
path: '/',
|
|
name: 'Home',
|
|
component: Home
|
|
},
|
|
{
|
|
path: '/about',
|
|
name: 'About',
|
|
component: About
|
|
},
|
|
{
|
|
path: '/contact',
|
|
name: 'Contact',
|
|
component: Contact
|
|
}
|
|
]
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
routes
|
|
})
|
|
|
|
export default router
|
|
```
|
|
|
|
### `resources/js/app.js`
|
|
```javascript
|
|
import { createApp } from 'vue';
|
|
import router from './router';
|
|
import App from './components/App.vue';
|
|
|
|
const app = createApp(App);
|
|
app.use(router);
|
|
app.mount('#app');
|
|
```
|
|
|
|
## Step 7: Buat Vue Components
|
|
|
|
### `resources/js/components/App.vue`
|
|
```vue
|
|
<template>
|
|
<div id="app">
|
|
<nav class="bg-blue-600 shadow-lg">
|
|
<div class="max-w-7xl mx-auto px-4">
|
|
<div class="flex justify-between h-16">
|
|
<div class="flex space-x-8">
|
|
<router-link
|
|
to="/"
|
|
class="flex items-center px-3 py-2 text-white hover:text-blue-200"
|
|
:class="{ 'border-b-2 border-white': $route.name === 'Home' }"
|
|
>
|
|
Home
|
|
</router-link>
|
|
<router-link
|
|
to="/about"
|
|
class="flex items-center px-3 py-2 text-white hover:text-blue-200"
|
|
:class="{ 'border-b-2 border-white': $route.name === 'About' }"
|
|
>
|
|
About
|
|
</router-link>
|
|
<router-link
|
|
to="/contact"
|
|
class="flex items-center px-3 py-2 text-white hover:text-blue-200"
|
|
:class="{ 'border-b-2 border-white': $route.name === 'Contact' }"
|
|
>
|
|
Contact
|
|
</router-link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="max-w-7xl mx-auto py-6 px-4">
|
|
<router-view />
|
|
</main>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
// Main app component
|
|
</script>
|
|
```
|
|
|
|
### `resources/js/pages/Home.vue`
|
|
```vue
|
|
<template>
|
|
<div class="home">
|
|
<div class="text-center">
|
|
<h1 class="text-4xl font-bold text-gray-800 mb-8">Welcome Home</h1>
|
|
<div class="bg-yellow-100 border-2 border-yellow-300 rounded-lg p-8 max-w-md mx-auto">
|
|
<p class="text-2xl font-bold text-gray-800">{{ message }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue'
|
|
const message = ref("Hello from Vue.js!")
|
|
</script>
|
|
```
|
|
|
|
### `resources/js/pages/About.vue`
|
|
```vue
|
|
<template>
|
|
<div class="about">
|
|
<h1 class="text-3xl font-bold text-gray-800 mb-6">About Us</h1>
|
|
<div class="bg-green-50 border border-green-200 rounded-lg p-6">
|
|
<p class="text-lg text-gray-700 mb-4">
|
|
This is our about page built with Laravel and Vue.js!
|
|
</p>
|
|
<button
|
|
@click="showMore = !showMore"
|
|
class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded transition duration-200"
|
|
>
|
|
{{ showMore ? 'Show Less' : 'Learn More' }}
|
|
</button>
|
|
<div v-show="showMore" class="mt-4 p-4 bg-white rounded border">
|
|
<p class="text-gray-600">
|
|
We're passionate about creating amazing web applications using modern technologies
|
|
like Laravel, Vue.js, and Tailwind CSS.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue'
|
|
const showMore = ref(false)
|
|
</script>
|
|
```
|
|
|
|
### `resources/js/pages/Contact.vue`
|
|
```vue
|
|
<template>
|
|
<div class="contact">
|
|
<h1 class="text-3xl font-bold text-gray-800 mb-6">Contact Us</h1>
|
|
<div class="max-w-md mx-auto bg-white shadow-md rounded-lg p-6">
|
|
<form @submit.prevent="submitForm" class="space-y-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Name</label>
|
|
<input
|
|
v-model="form.name"
|
|
type="text"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
required
|
|
>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
|
|
<input
|
|
v-model="form.email"
|
|
type="email"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
required
|
|
>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Message</label>
|
|
<textarea
|
|
v-model="form.message"
|
|
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 h-24"
|
|
required
|
|
></textarea>
|
|
</div>
|
|
<button
|
|
type="submit"
|
|
class="w-full bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded transition duration-200"
|
|
>
|
|
Send Message
|
|
</button>
|
|
</form>
|
|
|
|
<div v-if="submitted" class="mt-4 p-3 bg-green-100 border border-green-300 rounded text-green-700">
|
|
✅ Thank you for your message!
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive } from 'vue'
|
|
|
|
const form = reactive({
|
|
name: '',
|
|
email: '',
|
|
message: ''
|
|
})
|
|
|
|
const submitted = ref(false)
|
|
|
|
const submitForm = () => {
|
|
console.log('Form submitted:', form)
|
|
submitted.value = true
|
|
|
|
// Reset form after 3 seconds
|
|
setTimeout(() => {
|
|
submitted.value = false
|
|
Object.assign(form, { name: '', email: '', message: '' })
|
|
}, 3000)
|
|
}
|
|
</script>
|
|
```
|
|
|
|
## Step 8: Update Laravel Views
|
|
|
|
### `resources/views/welcome.blade.php`
|
|
```html
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Laravel + Vue.js</title>
|
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
|
</head>
|
|
<body class="bg-gray-50">
|
|
<div id="app"></div>
|
|
</body>
|
|
</html>
|
|
```
|
|
|
|
## Step 9: Setup Laravel Routes (SPA)
|
|
|
|
### `routes/web.php`
|
|
```php
|
|
<?php
|
|
|
|
use Illuminate\Support\Facades\Route;
|
|
|
|
// SPA Route - catch all and return main view
|
|
Route::get('/{any}', function () {
|
|
return view('welcome');
|
|
})->where('any', '.*');
|
|
```
|
|
|
|
## Step 10: Jalankan Development Server
|
|
|
|
```bash
|
|
# Terminal 1 - Laravel server
|
|
php artisan serve
|
|
|
|
# Terminal 2 - Vite dev server
|
|
npm run dev
|
|
```
|
|
|
|
Atau gunakan concurrently (jika sudah diinstall):
|
|
|
|
```bash
|
|
# Install concurrently jika belum
|
|
npm install --save-dev concurrently
|
|
|
|
# Tambahkan script di package.json
|
|
"scripts": {
|
|
"dev": "vite",
|
|
"build": "vite build",
|
|
"serve": "concurrently \"php artisan serve\" \"vite\""
|
|
}
|
|
|
|
# Jalankan keduanya sekaligus
|
|
npm run serve
|
|
```
|
|
|
|
## Struktur Project Final
|
|
|
|
```
|
|
project-name/
|
|
├── app/
|
|
├── resources/
|
|
│ ├── css/
|
|
│ │ └── app.css
|
|
│ ├── js/
|
|
│ │ ├── components/
|
|
│ │ │ └── App.vue
|
|
│ │ ├── pages/
|
|
│ │ │ ├── Home.vue
|
|
│ │ │ ├── About.vue
|
|
│ │ │ └── Contact.vue
|
|
│ │ ├── router/
|
|
│ │ │ └── index.js
|
|
│ │ └── app.js
|
|
│ └── views/
|
|
│ └── welcome.blade.php
|
|
├── routes/
|
|
│ └── web.php
|
|
├── package.json
|
|
├── vite.config.js
|
|
├── tailwind.config.js
|
|
└── composer.json
|
|
```
|
|
|
|
## Testing
|
|
|
|
Buka browser dan kunjungi:
|
|
- `http://localhost:8000` - Home page
|
|
- `http://localhost:8000/about` - About page
|
|
- `http://localhost:8000/contact` - Contact page
|
|
|
|
## Troubleshooting
|
|
|
|
### Error: "Component provided template option but runtime compilation is not supported"
|
|
- Pastikan `vue` alias sudah ditambahkan di `vite.config.js`
|
|
|
|
### Error: "Failed to parse source for import analysis"
|
|
- Pastikan `@vitejs/plugin-vue` sudah terinstall dan ditambahkan di plugins
|
|
|
|
### CSS tidak loading
|
|
- Pastikan `@vite` directive sudah benar di blade file
|
|
- Check jika Tailwind config sudah benar
|
|
|
|
### Router tidak bekerja
|
|
- Pastikan Laravel routes catch-all sudah ditambahkan
|
|
- Check browser console untuk error JavaScript
|
|
|
|
## Next Steps
|
|
|
|
- Tambahkan authentication
|
|
- Implementasikan API endpoints
|
|
- Setup state management (Pinia/Vuex)
|
|
- Tambahkan testing (Vitest)
|
|
- Deploy ke production
|
|
|
|
Selamat! Anda telah berhasil setup Laravel + Vue.js + Vue Router! 🎉
|