Laravel 9 Vue JS CRUD App using Vite Example
Tags: laravel, vue, vite, crud
Published: 2022-07-24 06:52:00

July 24, 2022, Originally published at [laraveltuts.com](https://laraveltuts.com/laravel-9-vue-js-crud-app-using-vite-example/)・9 min read

Today, We are going to learn **Laravel 9 Vue JS CRUD App using Vite Example**. This tutorial will cover on laravel 9 Vue Js CRUD application using Vite latest laravel update with example.

**Vite** is a modern frontend build tool that provides an extremely fast development environment and bundles your code for production. When building applications with Laravel, you will typically use Vite to bundle your application’s CSS and JavaScript files into production ready assets.

**Vue.js** is an open-source model–view–view model front end JavaScript framework for building user interfaces and single-page applications. It was created by Evan You, and is maintained by him and the rest of the active core team members.

## Steps for Laravel 9 Vue JS CRUD App using Vite Example:
- Step 1: Installing fresh new Laravel 9 Application
- Step 2: Creating Database and Configuration
- Step 3: Creating Auth with Breeze
- Step 4: Creating Migration and Model
- Step 5: Creating Route
- Step 6: Creating Controller
- Step 7: Creating Vue Pages
- Step 8: Testing
- Step 9: Conclusion

### Step 1: Installing fresh new Laravel 9 Application
First, we are installing a fresh new laravel 9 application. To install a laravel application run the following command in terminal.

```
composer create-project laravel/laravel vuejs-crud-vite
cd vuejs-crud-vite
```
Note: “**vuejs-crud-vite**” is our laravel application name.

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*tFW6Xb5oC8LTj_jk.png)

### Step 2: Creating Database and Configuration
Now, we will create a database. First open phpmyadmin and create a database with name “**vuejs-crud-vite**” (you may use anything you like).

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*BbEQoMpbU9T0eNo5.png)

Now we are going to add the database details to the laravel application. Open **.env** file and enter the database details.

```
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=vuejs-crud-vite
DB_USERNAME=root
DB_PASSWORD=
```

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*hg-EIYmZyvp1S_G8.png)

### Step 3: Creating Auth with Breeze
Now we are going to create auth with breeze. Run the following command in terminal to install breeze library.

```
composer require laravel/breeze --dev
```

create authentication with the following command.

```
php artisan breeze:install vue
```

Install Node JS package.

```
npm install
```

Now run the vite command and make it keep running.

```
npm run dev
```

**Note: If error occurs then updated node to v16.16.0 and it worked**

Now open new terminal and run the migration.

```
php artisan migrate
```

### Step 4: Creating Migration and Model
Here, We are going to create a migration for Posts table. To create a posts migration run the following command.

```
php artisan make:migration create_posts_table
```

add the following fields to posts migration file.

```
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('body');
            $table->timestamps();
        });
    }
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
};
```

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*2KvHuHC9vdt7MR37.png)

Run the migration again to create posts table.

```
php artisan migrate
```

So now, We will create Post model. To create a Post model run the following command in terminal.

```
php artisan make:model Post
```

And add the following code to **Post.php** model.

```
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
    use HasFactory;
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'title', 'body'
    ];
}
```

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*-XuOirV7Jywgdt2-.png)

### Step 5: Creating Route
Now we will create a resources route for our CRUD application. Add the following route to **routes/web.php**

```
<?php
use Illuminate\Foundation\Application;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use App\Http\Controllers\PostController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
    return Inertia::render('Welcome', [
        'canLogin' => Route::has('login'),
        'canRegister' => Route::has('register'),
        'laravelVersion' => Application::VERSION,
        'phpVersion' => PHP_VERSION,
    ]);
});
Route::get('/dashboard', function () {
    return Inertia::render('Dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
require __DIR__.'/auth.php';
Route::resource('posts', PostController::class);
```

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*7hqOz4W2FTI7gj9p.png)

### Step 6: Creating Controller
In this step, we are going to create a Post Controller. Create a new file **PostController.php** in **app/Http/Controllers** folder and add the following code inside.

```
<?php
   
namespace App\Http\Controllers;
    
use Illuminate\Http\Request;
use Inertia\Inertia;
use App\Models\Post;
use Illuminate\Support\Facades\Validator;
   
class PostController extends Controller
{
    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function index()
    {
        $posts = Post::all();
        return Inertia::render('Posts/Index', ['posts' => $posts]);
    }
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function create()
    {
        return Inertia::render('Posts/Create');
    }
    
    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function store(Request $request)
    {
        Validator::make($request->all(), [
            'title' => ['required'],
            'body' => ['required'],
        ])->validate();
   
        Post::create($request->all());
    
        return redirect()->route('posts.index');
    }
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function edit(Post $post)
    {
        return Inertia::render('Posts/Edit', [
            'post' => $post
        ]);
    }
    
    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function update($id, Request $request)
    {
        Validator::make($request->all(), [
            'title' => ['required'],
            'body' => ['required'],
        ])->validate();
    
        Post::find($id)->update($request->all());
        return redirect()->route('posts.index');
    }
    
    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function destroy($id)
    {
        Post::find($id)->delete();
        return redirect()->route('posts.index');
    }
}
```

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*q8Z7elRO2DIx9dkY.png)


### Step 7: Creating Vue Pages
In this last step we are create a Vue Js Pages — **Index.vue**, **Create.vue** and **Edit.vue**.

Create a new folder **Posts** inside **resources/js/Pages** and create below pages inside **Posts** folder.

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1258/0*7atXJkFwERxA-QwS.png)

**resources/js/Pages/Posts/Index.vue**

```
<script setup>
import BreezeAuthenticatedLayout from '@/Layouts/Authenticated.vue';
import { Head, Link, useForm } from '@inertiajs/inertia-vue3';
defineProps({
    posts: Array,
});
const form = useForm();
function destroy(id) {
    if (confirm("Are you sure you want to Delete")) {
        form.delete(route('posts.destroy', id));
    }
}
</script>
<template>
    <Head title="Dashboard" />
    <BreezeAuthenticatedLayout>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                Laravel 9 Vue JS CRUD App using Vite Example - LaravelTuts.com
            </h2>
        </template>
        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                    <div class="p-6 bg-white border-b border-gray-200">
                        <div className="flex items-center justify-between mb-6">
                            <Link
                                className="px-6 py-2 text-white bg-green-500 rounded-md focus:outline-none"
                                :href="route('posts.create')"
                            >
                                Create Post
                            </Link>
                        </div>
                        <table className="table-fixed w-full">
                            <thead>
                                <tr className="bg-gray-100">
                                    <th className="px-4 py-2 w-20">No.</th>
                                    <th className="px-4 py-2">Title</th>
                                    <th className="px-4 py-2">Body</th>
                                    <th className="px-4 py-2">Action</th>
                                </tr>
                            </thead>
                            <tbody>
                                <tr v-for="post in posts">
                                    <td className="border px-4 py-2">{{ post.id }}</td>
                                    <td className="border px-4 py-2">{{ post.title }}</td>
                                    <td className="border px-4 py-2">{{ post.body }}</td>
                                    <td className="border px-4 py-2">
                                        <Link
                                            tabIndex="1"
                                            className="px-4 py-2 text-sm text-white bg-blue-500 rounded"
                                            :href="route('posts.edit', post.id)"
                                        >
                                            Edit
                                        </Link>
                                        <button
                                            @click="destroy(post.id)"
                                            tabIndex="-1"
                                            type="button"
                                            className="mx-1 px-4 py-2 text-sm text-white bg-red-500 rounded"
                                        >
                                            Delete
                                        </button>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </BreezeAuthenticatedLayout>
</template>
```

**resources/js/Pages/Posts/Create.vue**

```
<script setup>
import BreezeAuthenticatedLayout from '@/Layouts/Authenticated.vue';
import BreezeLabel from '@/Components/Label.vue';
import BreezeInput from '@/Components/Input.vue';
import BreezeTextArea from '@/Components/Textarea.vue';
import { Head, Link, useForm } from '@inertiajs/inertia-vue3';
const form = useForm({
    title: '',
    body: ''
});
const submit = () => {
    form.post(route('posts.store'));
};
</script>
<template>
    <Head title="Dashboard" />
    <BreezeAuthenticatedLayout>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                Create Post
            </h2>
        </template>
        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                    <div class="p-6 bg-white border-b border-gray-200">
                        <div className="flex items-center justify-between mb-6">
                            <Link
                                className="px-6 py-2 text-white bg-blue-500 rounded-md focus:outline-none"
                                :href="route('posts.index')"
                            >
                                Back
                            </Link>
                        </div>
                        <form name="createForm" @submit.prevent="submit">
                                <div className="flex flex-col">
                                    <div className="mb-4">
                                        <BreezeLabel for="title" value="Title" />
                                        
                                        <BreezeInput 
                                            id="title" 
                                            type="text" 
                                            class="mt-1 block w-full" 
                                            v-model="form.title" 
                                            autofocus />
                                        <span className="text-red-600" v-if="form.errors.title">
                                            {{ form.errors.title }}
                                        </span>
                                    </div>
                                    <div className="mb-4">
                                        <BreezeLabel for="body" value="Body" />
                                        
                                        <BreezeTextArea 
                                            id="body" 
                                            class="mt-1 block w-full" 
                                            v-model="form.body" 
                                            autofocus />
                                        <span className="text-red-600" v-if="form.errors.body">
                                            {{ form.errors.body }}
                                        </span>
                                    </div>
                                </div>
  
                                <div className="mt-4">
                                    <button
                                        type="submit"
                                        className="px-6 py-2 font-bold text-white bg-green-500 rounded"
                                    >
                                        Save
                                    </button>
                                </div>
                            </form>
                    </div>
                </div>
            </div>
        </div>
    </BreezeAuthenticatedLayout>
</template>
```

**resources/js/Pages/Posts/Edit.vue**

```
<script setup>
import BreezeAuthenticatedLayout from '@/Layouts/Authenticated.vue';
import BreezeLabel from '@/Components/Label.vue';
import BreezeInput from '@/Components/Input.vue';
import BreezeTextArea from '@/Components/Textarea.vue';
import { Head, Link, useForm } from '@inertiajs/inertia-vue3';
const props = defineProps({
    post: Object,
});
const form = useForm({
    title: props.post.title,
    body: props.post.body
});
const submit = () => {
    form.put(route('posts.update', props.post.id));
};
</script>
<template>
    <Head title="Dashboard" />
    <BreezeAuthenticatedLayout>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                Edit Post
            </h2>
        </template>
        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                    <div class="p-6 bg-white border-b border-gray-200">
                        <div className="flex items-center justify-between mb-6">
                            <Link
                                className="px-6 py-2 text-white bg-blue-500 rounded-md focus:outline-none"
                                :href="route('posts.index')"
                            >
                                Back
                            </Link>
                        </div>
                        <form name="createForm" @submit.prevent="submit">
                                <div className="flex flex-col">
                                    <div className="mb-4">
                                        <BreezeLabel for="title" value="Title" />
                                        
                                        <BreezeInput 
                                            id="title" 
                                            type="text" 
                                            class="mt-1 block w-full" 
                                            v-model="form.title" 
                                            autofocus />
                                        <span className="text-red-600" v-if="form.errors.title">
                                            {{ form.errors.title }}
                                        </span>
                                    </div>
                                    <div className="mb-4">
                                        <BreezeLabel for="body" value="Body" />
                                        
                                        <BreezeTextArea 
                                            id="body" 
                                            class="mt-1 block w-full" 
                                            v-model="form.body" 
                                            autofocus />
                                        <span className="text-red-600" v-if="form.errors.body">
                                            {{ form.errors.body }}
                                        </span>
                                    </div>
                                </div>
  
                                <div className="mt-4">
                                    <button
                                        type="submit"
                                        className="px-6 py-2 font-bold text-white bg-green-500 rounded"
                                    >
                                        Save
                                    </button>
                                </div>
                            </form>
                    </div>
                </div>
            </div>
        </div>
    </BreezeAuthenticatedLayout>
</template>
```

Create a new file **Textaarea.vue** inside **resources/js/Components**

**resources/js/Components/Textarea.vue**

```
<script setup>
    import { onMounted, ref } from 'vue';
    defineProps(['modelValue']);
    defineEmits(['update:modelValue']);
    const input = ref(null);
    onMounted(() => {
        if (input.value.hasAttribute('autofocus')) {
            input.value.focus();
        }
    });
</script>
<template>
    <textarea class="border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm" :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" ref="input"></textarea>
</template>
```

Add a Post Navigation in **Authenticated.vue** inside **resources/js/Layouts** folder.


```
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
  <BreezeNavLink :href="route('dashboard')" :active="route().current('dashboard')">Dashboard</BreezeNavLink>
  <BreezeNavLink :href="route('posts.index')" :active="route().current('posts.index')">Posts</BreezeNavLink>
</div>
```

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*1W9L42IkGOMRJtqW.png)

### Step 8: Testing
Now let’s test our Laravel 9 Vue JS CRUD App using Vite Example. Run the following command to start laravel server.

```
php artisan serve
```

Also run Vite in new terminal and keep it running.


```
npm run dev
```

or build.


```
npm run build
```

Now open any web browser and enter the following link to test the application.

```
http://127.0.0.1:8000/
```

**Note: Register a new user and then click posts from navigation.**

**Preview:**

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*KEnJQ8twtAOHTkzl.png)

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*S9Fz2CaCukEawspj.png)

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*kMVkKQqE23zc7hPH.png)

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*64MXsB0JGSerI80T.png)

![Laravel 9 Vue JS CRUD App using Vite Example](https://miro.medium.com/max/1400/0*dZATvb2tPN1_lgu3.png)


### Step 9: Conclusion
Today, We had learn **Laravel 9 Vue JS CRUD App using Vite Example**. Hope this tutorial helped you with learning Laravel 9. If you have any question you can ask us at comment section below. If you like the tutorial please subscribe our [YouTube Channel](https://www.youtube.com/channel/UCwIbFoGoht3Dom9Q1NkOS3A) and follow us on social network [Facebook](https://www.facebook.com/laraveltutscom) and [Instagram](https://www.instagram.com/laraveltuts/).