Skip to main content

Inertia JS in less than 10 minutes

·1623 words·8 mins·

Laravel has been one of my most used frameworks when developing web applications and APIs. It provides you with all necessary tools to get started building your web application or API right away. From routing, to authentication, to queues, and everything in between.

Along with Laravel, Vue JS has been my most used frontend frameworks. It is an extremely simple and clean framework that provides you with all the basics of building a web application, without overcrowding the codebase.

Traditionally, the method for building web applications for me was to build a Laravel application that works as an API, and also build a Nuxt JS (which is plug-and-play framework built based on Vue JS) to work as the frontend.

This structure was working pretty well until I found out about Inertia JS.

Inertia JS is a tool that allows you to build a Laravel backend application that returns rendered Vue JS as the response.

In this tutorial, we try out Inertia JS and build a simple To-Do list to see how it works and how you can use it to simplify your next project!

Prerequisites
#

Having Vue JS knowledge or experience is preferred but not mandatory. But it is essential to have JavaScript knowledge and/or experience.

You will also need to have a laptop/PC with internet access, Node JS, and Laravel.

If you do not have any Laravel or Vue JS experience, I would recommend checking out those tutorials on my website:

Setting It Up
#

First, we open up our terminal and cd into where we will create our app. Next, create a Laravel project by running the following command:

laravel new todo-app

Assuming you have the latest version of Laravel (my installer version is 5.15.0), you should get asked to pick a Starter Kit, choose Vue JS. Next, choose Laravel’s built-in authentication as the authentication provider, and finally, Pest as our testing framework. For the sake of keeping this tutorial short, we will not work with authentication or testing.

Laravel should now start building the project and installing the dependencies. You will be asked if the installer should npm install and npm run build, choose Yes.

Next, create a new .env file from the .env.example file. Laravel will setup an SQLite Database for us and we will proceed with it for this tutorial.

Now open your project in your preferred IDE to get started!

Setting Up The Backend
#

To get started, head to the terminal again and cd into the project directory:

cd todo-app

We will need to create a Model for Tasks, a Migration for the database table, and a Controller to build the functionality. We can do that by running:

php artisan make:model -c -m 

This will trigger the create of a Model. The -c create a controller for that model, and -m creates a migration file.

When prompted to enter the model name, type in Task.

Now we should have the files necessary to start.

Migration
#

First, head to the migration file that was created, and add the following:

...
Schema::create('tasks', function (Blueprint $table) {
    $table->id();
    $table->string('title');
    $table->text('description')->nullable();
    $table->timestamps();
});
...

We added a Title and a Description.

Since we finished with writing our migration file. Run the following command:

php artisan migrate

Next, we can start working on the model

Model
#

In the Task model file, we simply need to add the fillable property with our properties:

...
class Task extends Model
{
    protected $fillable = [
        'title',
        'description',
    ];
}
...

And we’re done with the model.

We now can head to the controller file.

Controller
#

In the TaskController file, we will be adding 3 functions. One to display the tasks in a Vue page, one to create and store a new task, and another to delete a task.

First, import the Inertia and Task model files:

use App\Models\Task;
use Inertia\Inertia;

For the main page, create a function with the name index, inside it, query the tasks using the model and return the Vue JS file as follows:

public function index() {
    $tasks = Task::all();
    return Inertia::render('Tasks/Index', [
        'tasks' => $tasks,
    ]);
}

This finds the Task Index Vue file and renders it using Inertia JS then returns it to the client (browser).

To create the task creation or store function, we will do three things:

  1. Validate the input (title and description)
  2. Create the task
  3. Return a response
public function store(Request $request) {
    $validated = $request->validate([
        'title' => 'required|string|max:255',
        'description' => 'nullable|string',
    ]);

    Task::create($validated);

    return redirect()->route('tasks.index');
}

The return part returns a redirection to the task index function, which views all tasks.

Finally, we can create the destroy function which deletes a task:

public function destroy($id) {
    $task = Task::findOrFail($id);
    $task->delete();

    return redirect()->route('tasks.index');
}

This finds the task using the ID that will be provided in the path, which we will explore next.

Same as the store function, we return a redirect to the tasks index page.

Now that we are done building our controller, we can build the routes for each function.

Routes
#

Head to the web.php file and remove the preset routes there.

We can add our three routes as follows:

Route::get('/', [App\Http\Controllers\TaskController::class, 'index'])->name('tasks.index');
Route::post('/tasks', [App\Http\Controllers\TaskController::class, 'store'])->name('tasks.store');
Route::delete('/tasks/{id}', [App\Http\Controllers\TaskController::class, 'destroy'])->name('tasks.destroy');

One route for the main index page, one for the store function which uses the HTTP POST method, and one of the destroy function which uses the DELETE HTTP method.

Now we can start working on our Frontend.

Setting Up The Frontend
#

You will use the directory resources/js/pages to add the Vue files. First, remove the files in that directory. Next, create a new directory Tasks.

For the styling, I will be using Flowbite, a UI Component library that uses TailwindCSS

Let us begin by working on the Index file. Create a file Index.vue in the resources/js/pages/Tasks directory.

Create Task Form
#

Inside the Index.vue file, we will begin by adding a form to create the task.

<template>
    <div class="container mt-12 mx-auto">
        <h1 class="text-3xl font-bold mb-5">Tasks App</h1>
        <form @submit.prevent="createTask">
            <div class="mb-5">
                <label for="title" class="block mb-2.5 text-sm font-medium text-heading">Title</label>
                <input v-model="createTaskForm.title" id="title" class="bg-neutral-secondary-medium border border-default-medium text-heading text-sm rounded-base focus:ring-brand focus:border-brand block w-full px-3 py-2.5 shadow-xs placeholder:text-body" placeholder="Task title" required />
            </div>
            <div class="mb-5">
                <label for="description" class="block mb-2.5 text-sm font-medium text-heading">Description</label>
                <textarea v-model="createTaskForm.description" id="description" rows="4" class="bg-neutral-secondary-medium border border-default-medium text-heading text-sm rounded-base focus:ring-brand focus:border-brand block w-full px-3 py-2.5 shadow-xs placeholder:text-body" placeholder="Task description"></textarea>
            </div>
            <div class="text-right">
                <button type="submit" class="text-white bg-brand box-border border border-transparent hover:bg-brand-strong focus:ring-4 focus:ring-brand-medium shadow-xs font-medium leading-5 rounded-base text-sm px-4 py-2.5 focus:outline-none">Submit</button>
            </div>
        </form>
    </div>
</template>

Next, we can create a script to add the functionality. Inside, we will use the Inertia function useForm which helps us build the form functionality easily. We will import the function, create a form and place the title and description as attributes, and then create the createTask function:

<script setup>
import { useForm } from '@inertiajs/vue3';

const createTaskForm = useForm({
    title: '',
    description: '',
});

const createTask = () => {
    createTaskForm.post('/tasks', {
        onFinish: () => {
            createTaskForm.reset();
        },
    });
};

</script>

You can test it by filling up the form and submitting. If it works well, the inputs will become empty.

Viewing Tasks
#

Next, we will build the viewing functionality. If you remember, in the index function in the backend, we queried the tasks using the model. We can use this data in the Vue file by using props as follows:

const props = defineProps({
    tasks: Array,
});

We can place the props in the beginning of the script tag, right under the import for cleaner code.

Next, we can add a list to view all the tasks. Head back to the HTML and add the following code right below the form we created previously:

<div class="mt-10">
    <h2 class="text-2xl font-semibold mb-5">Task List</h2>
    <ul>
        <li v-for="task in props.tasks" :key="task.id" class="mb-4 p-4 border border-default-medium rounded-base">
            <h3 class="text-xl font-bold mb-2">{{ task.title }}</h3>
            <p class="text-body">{{ task.description }}</p>
        </li>
    </ul>
</div>

Go back to your browser and fill up the form again. After submitting, the list of tasks should appear right under the form.

Deleting Tasks
#

The final step now is to create the delete functionality.

In the list we created to view the tasks. Right under the description, add a delete button as follows:

...
<button @click="deleteTask(task.id)" class="mt-3 text-white bg-red-600 box-border border border-transparent hover:bg-red-700 focus:ring-4 focus:ring-red-400 shadow-xs font-medium leading-5 rounded-base text-sm py-1.5 px-2 focus:outline-none">Delete</button>
...

To create the functionality, we can use the useForm function again but using the DELETE HTTP method and with the ID provided in the function argument:

const deleteTask = (taskId) => {
    useForm().delete(`/tasks/${taskId}`, {});
};

Open your browser again and you should see a delete button. Click on the delete for one of the tasks and that task should be deleted.

And we are now done! We built a simple app without having to create a full on API, a separate app for our frontend, and with much less code!

Conclusion
#

Inertia JS has been my go-to tool for quick project that I have to build and complete ASAP. It is easy to use, simple, and allows me to use my two favorite frameworks!

While I used it on Laravel and Vue JS in this tutorial. It also works with other backend frameworks like Django and other frontend frameworks like React and Svelte.

It is great if you need to build a web application fast and simple. I would not really recommend if you require an API or more segregation between your backend and frontend. But for most few-page apps that only require a working web application with no API, it fits the needs perfectly!

Thank you for reading this tutorial. I hope you learned a new thing today. See you in the next one!

Hazem Hadi
Author
Hazem Hadi