Building your first Laravel Nova Tool

Published on by

Building your first Laravel Nova Tool image

Recently, I took advantage of the Black Friday sale and, although I didn’t have a use for it, I purchased a Laravel Nova license. I had been impressed with what I had seen and was desperate to give it a try.

I decided it would be fun to port one of my open-source packages, Laravel Translation to a Nova Tool.

Related: Building a Laravel Translation Package.

If you were unaware, a Tool is Nova’s method of allowing developers to add additional custom functionality to what ships out of the box.

This article will walk you through the process I took when building it.

Nova Documentation

Not knowing where to start, I headed for the documentation. As you would expect from a Laravel product, the documentation is fantastic. There is a section dedicated to building tools as well as all the other ways of customizing Nova.

Within a few minutes, I had a grasp of what I needed to do.

Nova Scaffolding

Nova ships with a CLI command which generates the scaffolding of the tool for you, php artisan nova:tool. When running this command, you pass in the tool’s name in Packagist vendor/name format which it uses when generating the composer.json file. This means it will be ready to publish as soon as development has completed.

The full scaffolding of the tool includes everything needed to get started with development including service providers, starter JavaScript, and SASS files and its class which is used to register the tool in the application.

Nova Service Provider

A tool has its service provider where it can be bootstrapped. This acts much like a Laravel service provider. It extends Illuminate\Support\ServiceProvider used in a standard Laravel application. This means all the methods like loading routes, views, migrations, etc. are available to you.

Unlike a standard Laravel service provider, all the necessary wiring up of views and routes is provided out of the box.

// Views
$this->loadViewsFrom(__DIR__.'/../resources/views', 'nova-translation');
 
// Routes
Route::middleware(['nova', Authorize::class])
->prefix('nova-vendor/nova-translation')
->group(__DIR__.'/../routes/api.php');

As you can see, there is some Laravel Nova middleware automatically applied to the routes. The nova middleware group which applies any middleware defined in the nova.php configuration file and the Authorize::class which applies any custom authorization set in the tool class. More on this later.

The routes are also registered under your vendor prefix, so they don’t conflict with any other routes.

Finally, your routes are loaded from the routes/api.php file that is automatically generated with the tool.

Nova Tool Class

As previously mentioned, the tool class is created automatically for you. It is named using the studly-cased version of the name you provided when running php artisan nova:tool vendor/name.

You don’t have to do anything in here, but it is possible to modify the way you render your navigation or which assets should be loaded.

For my package, I didn’t need to make any changes to this file.

Nova Navigation

Nova makes it incredibly easy to add a link to your tool in the main sidebar of the application. Once again, this is generated automatically by providing a navigation.blade.php file containing a default navigation link and loading it from the tool class.

public function renderNavigation()
{
return view('nova-translation::navigation');
}

You are free to edit this file to suit your needs. Typically, this will involve updating the SVG icon rendered in the navigation. Conveniently, Nova ships with a set of icons you are free to use.

Laravel Nova Frontend

The Nova frontend is a Vue.js application. A new tool is initialized with a tool.js file where you can use Vue’s router to define any routes needed. From there, you are free to build the application as you wish. As you would expect, the route to the index of your app is defined for you, but you are free to update it if required.

Nova.booting((Vue, router) => {
router.addRoutes([
{
name: 'nova-translation',
path: '/nova-translation',
component: require('./views/LanguagesIndex'),
},
 
...
])
})

Tools are compiled using Laravel Mix, and a configuration file is included as part of the scaffolding. This allows you to run development and production builds, and even trigger a rebuild when files change using commands you are likely familiar with such as npm run watch.

One of the things I liked when developing the frontend was the ability to utilize all the Vue components from the core of Nova.

It’s incredibly useful to be able to pull in things like loading views which automatically handle the loading state of your component or dropdown components for building out the user interface.

<template>
<loading-view :loading="initialLoading"> // ships with Nova
<loading-card :loading="loading" class="card"> // ships with Nova
// show something custom in here when loading state changes
</loading-card>
</loading-view>
</template>
 
<script>
export default {
data() {
return {
initialLoading: true,
loading: false,
languages: {}
}
},
 
methods: {
listLanguages() {
Nova.request().get('/nova-vendor/nova-translation/languages')
.then((response) => {
this.languages = response.data;
this.initialLoading = false;
this.loading = false;
})
}
},
 
created() {
this.listLanguages()
},
}
</script>

As you can see above, I use the LoadingView and LoadingCard components that ship with Nova. I then pass the loading state of my component as a prop and the loading state transition is handled for me. The result is the loading animation being rendered while my data is prepared.

Registering a Nova Tool

With the tool built, the last stage of the process is to let Nova know about its existence by registering it to the application. This is done by adding the tool class to the registerTools method of the NovaServiceProvider.

protected function registerTools()
{
Nova::tools([
new Dashboard,
new ResourceManager,
new NovaTranslation,
]);
}

Laravel Community

Taking a step away from the technical implementation, I wanted to highlight something that happened during the development of this tool.

During the build, I wanted to implement the blue loading bar at the top of the page when carrying out an ajax-powered search. If you have used Nova before, it’s the same loader that appears when you search through any of your resources.

I was tired and burning the midnight oil trying to get it finished and could not figure it out. I decided to contact David on Twitter for some advice. Ten minutes later, I had a reply with exactly what I needed to know.

When you search the query string is updated and that bar shows up when navigating to new URLs.

— HEMPHILL (@davidhemphill) November 29, 2018

A big thank you to David for helping me through this issue, but also to the broader Laravel community. This is not, and certainly won’t be the last time I have been offered assistance from members of the community when in need.

Conclusion

The developer experience for Nova was fantastic. From not knowing where to start to have my package ported over only took a couple of evenings which is a testament to, not only the documentation but also the planning and execution of Nova itself. As with all things in the Laravel ecosystem, it’s been built with extreme care and attention to detail, making the onboarding experience for developers quick and painless. I, for one, can’t wait to start the next one!

If you want to look at the tool I built, check it out on Nova Packages and as always, if you have any questions, you can find me on Twitter.

Joe Dixon photo

Founder and CTO of ubisend. Proud Father to two tiny heroes, Husband, developer, occasional globetrotter.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

image
Tinkerwell

Version 4 of Tinkerwell is available now. Get the most popular PHP scratchpad with all its new features and simplify your development workflow today.

Visit Tinkerwell
Laravel Forge logo

Laravel Forge

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Forge
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
No Compromises logo

No Compromises

Joel and Aaron, the two seasoned devs from the No Compromises podcast, are now available to hire for your Laravel project. ⬧ Flat rate of $7500/mo. ⬧ No lengthy sales process. ⬧ No contracts. ⬧ 100% money back guarantee.

No Compromises
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $2500/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
LoadForge logo

LoadForge

Easy, affordable load testing and stress tests for websites, APIs and databases.

LoadForge
Paragraph logo

Paragraph

Manage your Laravel app as if it was a CMS – edit any text on any page or in any email without touching Blade or language files.

Paragraph
Lucky Media logo

Lucky Media

Bespoke software solutions built for your business. We ♥ Laravel

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel E-Commerce

E-Commerce for Laravel. An open-source package that brings the power of modern headless e-commerce functionality to Laravel.

Lunar: Laravel E-Commerce
DocuWriter.ai logo

DocuWriter.ai

Save hours of manually writing Code Documentation, Comments & DocBlocks, Test suites and Refactoring.

DocuWriter.ai
Rector logo

Rector

Your partner for seamless Laravel upgrades, cutting costs, and accelerating innovation for successful companies

Rector

The latest

View all →
Generate Code Coverage in Laravel With PCOV image

Generate Code Coverage in Laravel With PCOV

Read article
Non-backed Enums in Database Queries and a withSchedule() bootstrap method in Laravel 11.1 image

Non-backed Enums in Database Queries and a withSchedule() bootstrap method in Laravel 11.1

Read article
Laravel Pint --bail Flag image

Laravel Pint --bail Flag

Read article
Laravel Herd for Windows is now released! image

Laravel Herd for Windows is now released!

Read article
The Laravel Worldwide Meetup is Today image

The Laravel Worldwide Meetup is Today

Read article
Cache Routes with Cloudflare in Laravel image

Cache Routes with Cloudflare in Laravel

Read article