Using Backpack for Laravel with VueJS (or even React)

Owen Melbourne
5 min readFeb 26, 2019

--

Update: Example code bases have been set up showing both a Vue setup and a React setup using a similar process to what is described below — you should be able to install these both have have a play.

Disclaimer: I’ve never used react before 😇

Recently a subject which has become popular within the Backpack scene is integrating Vue or React with Backpack. Really this is straightforward and isn’t any different to any other process, you install your library of choice, you add it to an asset pipeline, include your css/js into your webpage!

Although we’re discussing react and vue here — the process is basically the same for any other system you want to use.

It is really quite a normal process, write your components, include them, use them! Although it seems many people are getting confused, so to start with we will clear some things up.

Backpack works “alongside” any other library you want.

That does not mean — that you can compile Backpack with Webpack, Rollup, Browserify etc.

It simply means you can write custom functionality using any library you want, and then add it to your backpack install.

e.g. You want to create a widget for your admin dashboard in Vue which calls the Twitter API

There's a couple of things you’ll need to do this.

  1. Setup your asset pipeline to compile assets (e.g. Laravel Mix)
  2. Import your components into Backpack
  3. Create your component in the library of choice (e.g. Vue)

Setting up your asset pipeline

You’ll be happy to know that if you use Laravel Mix, then you need to do absolutely nothing different! The default webpack.mix.js should work for you out of the box!

mix
.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css');

Note: Remember that Laravel ships with an opinionated frontend setup, e.g. it ships with its own Bootstrap theme and Vue. However, just the same as if you wanted to use React you’d need to make your changes, maybe you don’t need jQuery or bootstrap, for example, then you might run — however this is down to you to figure out what your application needs.

php artisan preset:none

2. Import into Backpack

Once you’ve confirmed your build process is working e.g. npm run dev and you have outputted your app.css and app.js you can import them into the blade layout file, just as normal :)

Depending if you have published your views or not you might need an extra step. However effectively you need to publish the Backpack layout file which is stored within:

/vendor/backpack/base/src/resources/views/layout.blade.php

You must publish that to:

/resources/views/vendor/backpack/base/layout.blade.php

Once it’s published you can include your custom CSS and custom JS, I like to use the mix helper.

<link rel="stylesheet" href="{{ mix('css/app.css') }}">
<script src="{{ mix('js/app.js') }}"></script>

Feel free to put these in header/footer and make sure the loading order is correct for your application.

3. Creating your components

Now you’ve told Backpack to load your custom components you can go wild!

Just like any other Vue or React app, you need to create your component, then mount it to an element on the page. e.g.

In React:

// Import dependencies.
import
React, { Component } from 'react'
import ReactDOM from 'react-dom'

// Define your component.
class
HelloWorld extends Component {
render: () => ({
<div>Hello World</div>
})
}

// Look for the element on the page which says where you want it to appear.
const
element = document.getElementById('helloWorldComponent')

// Render the component if the element exists. (You don't want to throw an error if it doesn't exist on the page)
if
(element) {
ReactDOM.render(<HelloWorld />, document.getElementById('helloWorldComponent'))
}

In Vue:

// Import dependencies.
import
Vue from 'vue'

// Define your component.
Vue.component('hello-world', {
template: `<div>Hello World</div>`
})

// Look for the element on the page which says where you want it to appear.
const
element = document.getElementById('helloWorldComponent')

// Render the component if the element exists. (You don't want to throw an error if it doesn't exist on the page)
if
(element) {
new Vue({
el: element
})
}

Note: There are loads of ways to write/import your components, the key thing is to make sure you mount Vue/React onto a specific element on the page, otherwise it won’t know where to show it.

Et Voila!

Now you can include React/Vue components anywhere in Backpack!

Diving Deeper

So I know what some of you may be saying. How do I do X? How do I do Y?

Well, there are no specific answers, everything is up to you. Backpack doesn’t use Vue or React, which means you can handle it however you want. However, I can give you an example of a custom field in which theory can be reapplied elsewhere.

Custom fields

One of Backpacks features is the ability to add custom fields just by adding a new blade file into “/resources/views/vendor/backpack/crud/fields/

Using a Vue component is pretty much the same. Below is a pseudo example of how we can create a normal text field that has a character count on it. (Don’t copy/paste it won’t work)

Your crud controller will need to reference your new field — passing in any custom props you might need! e.g.

$this->crud->addField([
label: 'Title',
name: 'Page title'
type: 'counted_text',
limit: 100,
])

Then create your corresponding field — passing in the props/data e.g. /resources/views/vendor/backpack/crud/fields/counted_text.blade.php

<counted-text label="{{ $entry->label}}" name="{{ $entry->name }}" value="{{ $entry->value }}" :limit="{{ $entry->limit }}"></counted-text>

Now you need to load your JS component to replace the HTML that the blade field injected.

As you might have multiple instances of the component you won’t be able to bind the Vue instance to an ID, so you’ll need to bind it within a loop — commonly within your app.js.

document.querySelectorAll('counted-text').forEach(el => {
new Vue({
el,
components: {
'counted-text': require('./components/CountedText.vue')
}
});
});

Then your component code might look something like:

<template>
<div>
<label :for="name">
{{ label }}
<input :id="name" :name="name" v-model="model">
</label>
<span>Characters left: {{ left }}<span>
</div>
</template>

<script>
export default {
props: ['limit', 'value', 'name', 'label'],
data: () => ({
model: this.value
}),
computed: {
left() {
return this.limit - this.value
}
}
}
</script>

That's it! Your now good to go, obviously all the functionality is up to you to create, however, that's the basic theory, create a blade include that references your custom components so your library can hook in!

The key things you need to remember for your custom field component

  • You must populate a named input field, as the forms submit using a traditional form element and picked up in PHP, this means for visual fields you might need a hidden input element for example.
  • Make sure your component accepts the default attributes, e.g. old data, default data, hints, custom classes etc to make it as compatible as possible.
  • If you need to share state/data between multiple components you’ll need a central data store for ease rather than emitting events etc.

The End!

By this point, we’ve gone over how to import an asset pipeline into Backpack, and use custom components on the page.

Now it’s down to you to make something great :)

--

--