Laravel Jetstream: From blade to using Inertia & Vue
Tags: laravel, vue, php
Published: 2021-03-10 03:43:01

Laravel Jetstream + Inertia is an amazing foundation for building modern apps using Vue (auth, basic ui kit) without the struggles of SPA. This article assumes you followed the installation steps on [Laravel Jetstream's website](https://jetstream.laravel.com/2.x/installation.html) for Inertia and you are ready to jump in but you're a little new to Inertia or Vue.

### How do I work with Inertia?

Inertia may seem very different at first, but nothing actually changes with how you think about things like routes, controllers and views within Laravel. You still add a route to web.php, point it to a controller and return a view. 

The main difference is that you return `Inertia::render()` from a controller. This response will ultimately render a Vue component and pass it data defined in our Laravel controllers.. solving a complexity of using Vue + Laravel.

```php
Route::get('posts', 'PostsController@index')->name('posts.index');
```
```php
public function index()
{
    $posts = Post::all();

    return Inertia::render('Posts/Index', [
        'posts' => $posts
    ]);
}
```

### Where do I put views?
 
There is a `resources/js/Pages` folder created when you installed Jetstream. Add `Posts/Index.vue` within that folder to handle `Inertia::render('Posts/Index')`. Similar to `view('posts.index')`

### Where are my changes when I refresh?

Since we are using Vue, we need to compile our vue components / pages or the changes we make in .vue files will not show in the browser. It basically just means `npm install` to install dependencies and `npm run watch` to watch files for changes and re-compile. Luckily Laravel makes this user friendly. [docs](https://laravel.com/docs/mix)

### How do I access the view data?

The vue component will automatically receive the data we added to `Inertia::render()` within our controller just like when we say `view()->with()`. The key differences are we need to add each variable as a property in `props` so vue is aware and use [vue's template](https://vuejs.org/v2/guide/syntax.html) syntax instead of Blade.

```
resources/js/Pages/Posts/Index.vue
```
```html
<template>
    <app-layout>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                Posts
            </h2>
        </template>

        <div>
            <div class="max-w-7xl mx-auto py-10 sm:px-6 lg:px-8">
                <div v-for="post in posts" :key="post.id">
                    {{ post.title }}
                </div>
            </div>
        </div>
    </app-layout>
</template>

<script>
import AppLayout from '@/Layouts/AppLayout'

export default {
    props: ['posts'],

    components: {
        AppLayout
    },
}
</script>
```

- What is the `@` in the import? It's [an alias](https://laravel-news.com/laravel-mix-alias) defined in webpack.mix.js
- What is #header? Shorthand for [Vue's component slot](https://vuejs.org/v2/guide/components-slots.html)

### What is `<app-layout>`?

Jetstream comes with a lot of really useful vue components for things like form elements and modals, located in `resources/js/Jetstream`, but `<app-layout>` is in `resources/js/Layouts` and is the main shell that renders this: ![Laravel Jetstream Vue Inertia](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d587paw2blb01fdezrnm.png)

Adding your content within this vue component means you'll automatically have navigation in place and a nice starting point for your layout.

### How do I link to my page?

Jetstream installs [Ziggy](https://github.com/tightenco/ziggy) to handle using named routes within Inertia / Vue. Using Ziggy's `route` method & the `<inertia-link>` [component](https://inertiajs.com/links):
```html
<inertia-link :href="route('posts.index')">
    Posts
</inertia-link>
```
To add a link to the main navigation within the `<app-layout>`, open the layout file within `resources/js/Layouts/App.vue` and add a link:
```html
<!-- Navigation Links -->
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
    <jet-nav-link :href="route('dashboard')" :active="route().current('dashboard')">
        Dashboard
    </jet-nav-link>
                                
    <jet-nav-link :href="route('posts.index')" :active="route().current('posts.index')">
        Posts
    </jet-nav-link>
</div>
```
(`<jet-nav-link>` is a component in `resources/js/Jetstream`)

### How do I submit forms?

Inertia provides [a really helpful way](https://inertiajs.com/forms) of using ajax to submit forms. First, use `v-model` to [connect your inputs](https://vuejs.org/v2/guide/forms.html) to the [vue state](https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties) defined in the `data()` section of your vue component and [call a method](https://vuejs.org/v2/guide/events.html#Method-Event-Handlers) using the `@submit` event handler.

```html
<template>
  <form @submit.prevent="submit">
    <label for="title">Title:</label>
    <input id="title" v-model="form.title" />
    <label for="body">Body:</label>
    <input id="body" v-model="form.body" />
    <button type="submit">Submit</button>
  </form>
</template>

<script>
export default {
  data() {
    return {
      form: {
        title: null,
        body: null
      },
    }
  },
  methods: {
    submit() {
      this.$inertia.post('/posts', this.form)
    },
  },
}
</script>
```



### How does Inertia render Vue?
Laravel Jetstream sets the root view to app.blade.php in `app/Http/Middleware/HandleInertiaRequests` which is rendering:
```html
<body class="font-sans antialiased">
   @inertia
</body>
```

Which is outputting the root div Vue will attach to and passing it data:
```html
<div id="app" data-page="{{ json_encode($page) }}"></div>
```

### How is resources/js/Pages defined?

This mapping happens in `resources/app.js`

```js
resolveComponent: (name) => require(`./Pages/${name}`).default,
``` 

### Conclusion

Hope you found that helpful. I plan to write more about Jetstream as I find it to be extremely powerful. If you have feedback, I'd love to hear it on twitter.

https://twitter.com/dillingham_dev