Introduction
This tutorial demonstrates the integration of Vue into Laravel using Vite, streamlining the development of dynamic user interfaces. We'll also guide you through implementing CRUD operations, enabling efficient data management. You'll gain a comprehensive understanding of how Vue, Laravel, and Vite can collaborate to create sophisticated web applications with powerful CRUD functionalities.
2: Install Vue in Laravel using Vite:
Requirements:
- Laravel 9 or above
- node 14 or above
Steps:-
2.1: create Laravel project
composer create-project --prefer-dist laravel/laravel LaravelReact
2.2: Install vue and vite vue-plugin
npm i
npm install vue@next vue-loader@next
npm i @vitejs/plugin-vue
2.3: Update vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
vue(),
laravel([
'resources/css/app.css',
'resources/js/app.js',
]),
],
});
2.4: Create a dynamic route
In web.php add this route. this route will handle all routes that we will make using vue routing
Route::get('/{any}', function () {
return view('app');
})->where('any', '.*');
2.5: Update Layout blade file
add vite directives and div with id app here is example
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel 9 vite with vue</title>
</head>
<body>
<div id="app"></div>
@vite('resources/js/app.js')
</body>
</html>
2.6: Install Dependencies
install Following Packages
npm i bootstrap jquery toastr
2.7: Update resources/js/app.js
import { createApp } from 'vue';
import 'bootstrap/dist/css/bootstrap.min.css'
import 'toastr/build/toastr.min.css'
import App from './Pages/App.vue'
createApp(App).mount("#app")
We will use bootstrap for styling. And toastr is a toast library we will use to show messages when we delete, add, update posts.
2.8: Create new root page i.e [App.vue]
resources/js/Pages/App.vue
<template>
<h1>
Laravel 9 vite with vue 3
</h1>
</template>
#7 Run following commands
Vue integration is done here.
npm run dev
php artisan serve
3: Create Model, migration, and controller
php artisan make:model Post -mc
This command will create a Post model, migration for posts table and PostController
//in posts migration
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('description');
$table->timestamps();
});
php artisan migrate
4: Create CRUD API`s
4.1: create routes in routes/api.php
Route::get('/posts', [PostController::class, 'index']);
Route::get('/posts/delete/{id}', [PostController::class, 'delete']);
Route::get('/posts/get/{id}', [PostController::class, 'get']);
Route::post('/posts/save', [PostController::class, 'save']);
Route::post('/posts/update', [PostController::class, 'update']);
4.2: create Api's in PostController
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
function index()
{
return response(['status' => 'success', 'posts' => Post::all(), 'code' => 200]);
}
function save(Request $request)
{
$request->validate(['title' => 'required', 'description' => 'required']);
$post = new Post();
$post->title = $request->title;
$post->description = $request->description;
$post->save();
return response(['status' => 'success', 'post' => $post, 'code' => 200]);
}
// get post by id
function get($id)
{
$post = Post::find($id);
return response(['status' => 'success', 'post' => $post, 'code' => 200]);
}
function update(Request $request)
{
$request->validate(['title' => 'required', 'description' => 'required']);
$post = Post::find($request->id);
$post->title = $request->title;
$post->description = $request->description;
$post->save();
return response(['status' => 'success', 'post' => $post, 'code' => 200]);
}
function delete($id)
{
$post = Post::find($id);
$post->delete();
return response(['status' => 'success', 'message' => 'deleted successfully', 'code' => 200]);
}
}
5: Create pages and and integrate Api's
Create 3 pages in resources/js/Pages/Post. posts.vue for post list, createpost.vue for create post and editpost.vue for edit post.
5.1 Create routes in resources/js/routes.js
import PostsList from "./Pages/Post/posts.vue";
import CreatePost from "./Pages/Post/createpost.vue";
import EditPost from "./Pages/Post/editpost.vue";
export const routes = [
{
path: "/",
name: "PostsList",
component: PostsList,
},
{
path: "/create-post",
name: "CreatePost",
component: CreatePost,
},
{
path: "/edit-post/:id",
name: "EditPost",
component: EditPost,
},
];
This code define all the routes for vue. path specifies the URL path for this route. Name assigns a unique name to this route, which can be used for programmatic navigation. component associates the route with the Vue component indicating that this component should be displayed when the route is accessed.
5.1.1: Update app.js
import { createApp } from 'vue';
import { createRouter, createWebHashHistory } from "vue-router";
import { routes } from "./routes";
import 'bootstrap/dist/css/bootstrap.min.css'
import 'toastr/build/toastr.min.css'
import App from './Pages/App.vue'
let app = createApp(App)
const router = createRouter({
history: createWebHashHistory(),
routes: routes,
})
app.use(router);
app.mount("#app")
This code sets up a Vue.js web application with routing, using Vue Router, and associates the defined routes with components.
5.1.2: Update App.vue
<template>
<h1 class="alert alert-danger text-center">Laravel-10 & Vue-3 CRUD</h1>
<div class="container">
<RouterView></RouterView>
</div>
</template>
<script>
export default {
name: "App",
};
</script>
The <RouterView> component is a placeholder where the content of the currently active route will be rendered.
Set Axios BaseUrl
resources/js/Pages/config/axios.js
import axios from 'axios';
const instance = axios.create({
baseURL: 'http://localhost:8000/', // Your API base URL
});
export default instance;
5.2: posts.vue page
<template>
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h1>Posts</h1>
<router-link to="/create-post" class="btn btn-secondary"
>Create</router-link
>
</div>
</div>
<div class="card-body">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>#</th>
<th>Title</th>
<th>Description</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="(post, key) in posts" :key="post.id">
<td>{{ key }}</td>
<td>{{ post.title }}</td>
<td>{{ post.description }}</td>
<td>
<router-link
:to="{
name: 'EditPost',
params: { id: post.id },
}"
class="btn btn-info"
>Edit</router-link
>
<button
type="button"
class="btn btn-danger ms-2"
v-on:click="deletePost(post.id)"
>
Delete
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
import axios from "../config/axios.js";
import toastr from "toastr";
export default {
name: "Posts",
data() {
return {
posts: [], // Initial state
};
},
mounted() {
this.getPosts();
},
methods: {
async getPosts() {
let res = await axios.get("/api/posts");
this.posts = res.data.posts;
},
async deletePost(id) {
let res = await axios.get(`/api/posts/delete/${id}`);
toastr.success(res.data.message);
this.getPosts();
},
},
};
</script>
5.3 createpost page
<template>
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h1>Create Posts</h1>
<router-link to="/" class="btn btn-secondary">Back</router-link>
</div>
</div>
<div class="card-body">
<form action="">
<div class="form-group">
<label for="title">Title;</label>
<input type="text" name="title" id="title" class="form-control" v-model="post.title" />
</div>
<div class="form-group">
<label for="description">Description;</label>
<input type="text" name="description" id="description" v-model="post.description"
class="form-control" />
</div>
<button type="button" class="btn btn-secondary mt-2" v-on:click="savePost()">Save</button>
</form>
</div>
</div>
</template>
<script>
import axios from "../config/axios.js";
import toastr from "toastr";
export default {
name: 'Posts',
data() {
return {
post: {} // Initial state
};
},
methods: {
async savePost() {
try {
let res = await axios.post('/api/posts/save', this.post);
toastr.success('Post saved Successfully')
this.post = {}
} catch (error) {
let errors = error.response.data.errors
for (let key in errors) {
toastr.error(errors[key])
}
}
},
}
}
</script>
5.3: editpost page
<template>
<div class="card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h1>Edit Posts</h1>
<router-link to="/" class="btn btn-secondary">Back</router-link>
</div>
</div>
<div class="card-body">
<form action="">
<div class="form-group">
<label for="title">Title;</label>
<input type="text" name="title" id="title" class="form-control" v-model="post.title" />
</div>
<div class="form-group">
<label for="description">Description;</label>
<input type="text" name="description" id="description" v-model="post.description"
class="form-control" />
</div>
<button type="button" class="btn btn-secondary mt-2" v-on:click="updatePost()">Save</button>
</form>
</div>
</div>
</template>
<script>
import axios from "../config/axios.js";
import toastr from "toastr";
export default {
name: 'Posts',
data() {
return {
post: {} // Initial state
};
},
mounted() {
this.getPost(this.$route.params.id);
},
methods: {
async updatePost() {
try {
let res = await axios.post('/api/posts/update', this.post);
toastr.success('Post updated Successfully')
this.getPost(this.$route.params.id)
} catch (error) {
let errors = error.response.data.errors
for (let key in errors) {
toastr.error(errors[key])
}
}
},
async getPost(id) {
let res = await axios.get(`/api/posts/get/${id}`);
this.post = res.data.post
}
}
}
</script>
Conclusion:
By following all these steps you will be able to setup and use Vue in Laravel as well you will be able to perform Laravel Vue CRUD opertaion. Please provide your feedback at comment below.