Should I use Laravel Jetstream with InertiaJS?

Elson Tan
6 min readNov 19, 2020
Immo Wegmann

InertiaJS is a recently hyped “glue between frontend & backend” for quickly writing Laravel applications with modern JS frameworks like VueJS without writing any APIs or do your frontend routing (no more fussy state management & vue router).

Laravel Jetstream, takes this a step further, by providing authentication, team settings, API support, two-factor authentication, some more scaffolding for InertiaJS / Livewire. With beautifully designed theme with Tailwind CSS, you can get a basic application up with, basically, one command.

Is this for me?

I came from Laravel Blade days where everything was handled by Laravel and simple server side requests, and then VueJS came along, and here we all are, hooked with the speed of SPAs. But, as our SPAs grew, there’s more state to manage, there are more API endpoints to write (if you’re using REST APIs), all those state management, frontend API requests, SPA authentication, authorization, things get messy in the end, at a point, why can’t we just go back to the simple request and response?

InertiaJS is created just to solve this.

Here are some considerations and how-tos for doing some stuff in Jetstream + InertiaJS after a month’s usage. Hopefully it will give you some idea on using it for your next project.

The Good Stuff

Sweet, Sweet Scaffolding

I always love how Laravel give developers a great head start with their application with basic scaffolding, like authentication(every application needs this right?)

Jetstream provides more than just authentication scaffolding, here’s some of the goodies you get right out of the box.

  1. Authentication, Login, Register, Forgot password, Email verification, Two-Factor Authentication(awesome)
  2. Profile Management, change your name, email, password, profile photo, delete your account
  3. Team Management, easily switch between teams and create teams.
  4. Easily manage API tokens, allow public or first-party API authentication with your application the awesome Laravel Sanctum
  5. Comes with a bunch of Vue components, JetButton, JetInput, oh yeah, there’s a modal component as well.

With all these basically you just need to worry about building your application, let Jetstream take care of the rest. (P/S all components are made with TailwindCSS)

Managing State? No more.

We are all used to scaffolding our Laravel + VueJS application with a simple state management using Vuex. InertiaJS takes that away, we just need to pass our data with Inertia::render()and accept it in props in your Vue component. Just like how Blade marries our controller, here’s an example …

ProjectTaskController.php

public function index(Project $project)
{
$tasks = ProjectTask::where('project_id', $project->id)
->paginate(10);

return Inertia::render('Tasks/Index', compact('tasks', 'project'));
}

resources/js/Pages/Tasks/Index.vue

<template>
<div>
<h1>Tasks in {{ project.name }}</h1>
<div v-for="task in tasks" :key="task.id">
{{ task.name }}
</div>
</div>
</template>

<script>
export default {
name: 'TaskShow',
props: ['tasks', 'project']
}
</script>

Oh, if you don’t want to reload data every time, Inertia provides a way to cache state.

Forget about Vue Router, use Inertia Link.

Building our Vue SPAs, vue-router is “the” essential package to-have. On Jetstream+Inertia is a different story. Inertia idea is built around not having to care about your API endpoints, your state, just focus on your application code like how we did with Blade components.

When you install Jetstream + InertiaJS, you wont need to setup vue-route at all. Routing is already built-in. Here’s a few examples on routing:

In Vue Component

<inertia-link href="/">Home</inertia-link><inertia-link :href="route('projects.index').url()">Projects</inertia-link>

Manual way

this.$inertia.visit(url)

Note Jetstream adds a package which allows you to access Laravel named routes using route() function in your frontend script.

Globally shared Data.

You must be wondering how do you flash session data to your Vue component when a form is submitted successfully, here’s the way

In your AppServiceProvider.php

public function register()
{
Inertia::share('flash', function () {
return [
'success' => Session::get('success'),
'error' => Session::get('error'),
];
});

In your controller you can session()->flash() as you used to. Then, you can access it via $page in your VueJS component, example below:

<div v-if="$page.flash.success" class="mx-auto max-w-7xl rounded text-white w-full my-5 p-3 bg-green-500 border border-green-600 shadow-sm">
{{ $page.flash.success }}
</div>

Jetstream automatically adds $page.user for authenticated user as well, you can check out more on Shared Data here.

Things to Watch Out

Tailwind CSS is the default, no Bootstrap.

Tailwind CSS, is an awesome framework, it allows you to create beautiful designs just by writing classes, yep, no more CSS.

<button class="bg-green-500 hover:bg-green-400 py-5 px-2 text-white rounded shadow-md">Hello</button>

The above code produces a nice green button with a little shadow, easy right?

Laravel and its ecosystem has always been opinionated, so does Jetstream, Jetstream scaffolding comes with TailwindCSS components by default, all the screens from login to your profile settings are made with Tailwind classes.

Honestly, its great to get started with until you need to manage your components, or create custom components for it. For those who come from Bootstrap, thats another Learning curve for you. There’s already people who raised this issue, seems like the team behind Jetstream is not planning to create a Bootstrap version anytime soon. P/S good news.. someone made a Bootstrap adapter for Jetstream.

Well, we can make use of Vue components alongside TailwindCSS to create components for different elements but from my personal experience, it’s hell when you want to manage your colours & sizes.

<template>
<input class="form-input p2 rounded-md shadow-sm" :value="value" @input="$emit('input', $event.target.value)" ref="input">
</template>
// how we use it
<jet-input v-model="something"/>

Laravel Jetstream provided the above “Input” component by default, we can reuse it, but its fixed towards design using rounded-md shadow-sm.

How are we going to change that if some part of our application design is not a rounded textbox with a shadow? Do we need to create a new component “NotRoundedInput” ? or customise the Vue component to accept props to create different size, colors, design?

Yes, you need to turn all those elements you are familiar with into components to be able re-use them. There are already some libraries that can take some of the load off, yet the effort and time consumed just to get basic components for normal use should be used for building the application itself.

Another Bad thing about not converting common HTML elements into reusable Vue components is you have to manage a long list of Tailwind classes in a single HTML and your code will become extremely verbose and hard to manage in future.

Jetstream Authentication Views are Blade.

Yep, its not built into InertiaJS VueJS, all authentications views are in Blade which can be found under resources/views/auth/

The annoying part is when InertiaJS trying to redirect back to Login when session timed out. It just opens in a Modal view.

Here’s quick trick to get around this, you just need to modify Http/Middleware/Authenticate

protected function redirectTo($request)
{
// redirect to login if intertia request and session expired
if (! $request->expectsJson() && Request::inertia()) {
abort(409, '', ['X-Inertia-Location' => url()->route('login')]);
} else if (! $request->expectsJson()) {
return route('login');
}
}

Redirecting PUT/PATCH/DELETE requests, you need a 303.

Something I just stumbled upon when doing PUT request that i didn’t knew it was a problem until I check out Inertia documents. When we are doing PUT/PATCH/DELETE requests in our controller methods, when its successful, normally we will do a route()->redirect() and yes this works with Inertia too since it will call the route (eg. show) and render the component with Inertia::render() . There’s one catch though, when i submit the form using

this.$inertia.put(route('projects.tasks.update', {project: this.project.id, task: this.task.id}), this.form)

It will fail as it will do a GET request towards the route(‘projects.tasks.update’) above in which only accepts PUT. Well that’s weird, why is this happening?

According to official docs, when redirecting after a PUT, PATCH or DELETE request you must use a 303 response code, otherwise the subsequent request will not be treated as a GET request. A 303 redirect is the same as a 302 except that the follow-up request is explicitly changed to a GET request.

However, if you are using their official Inertia adapters for Laravel this should not be a concern as its converted automatically. Then why doesn’t my setup with Jetstream work? Well i have to get around it using this in my update() method in a resource controller.

return redirect()->route('projects.tasks.index', compact('project'))
->setStatusCode(303);

Conclusion

Laravel Jetstream + InertiaJS for me personally, to kickstart a new project quickly, this package is a blessing, but i will not be considering moving a legacy application onto this new stack anytime soon.

There’s no right or wrong when using something, it all comes down to will it help you with your development?

Bonus: You can use Jetstream with Livewire too, and yea Taylor just released an Anti-Jetstream package as well. 🤷‍♂️

--

--

Elson Tan

Full Stack Web Dev // Certified AWS SA // I run a Web Dev Agency (nedex.io). Twitter @elsodev.