Preface

I will be writing about Laravel Nova, what it is (briefly), and how to use it with your open source Laravel application project.

I won’t be writing about customizing Laravel Nova in the context of an open source application. I mainly want to write about the questions I had, and the steps I took regarding setting up Laravel Nova, while conforming to its non-open source license terms.

If you are a maintainer of an open source Laravel application project (not a library or package) and you like Laravel Nova, or are considering buying a license and integrating it with your project, you might find this article useful.

What is Laravel Nova?

Laravel Nova is a “beautifully-designed administration panel for Laravel”, which was first announced by Taylor Otwell on July 25th, and came out on August 22nd earlier this year.

Taylor gave a demo of Laravel Nova in his keynote from Laracon US 2018, as seen here:

When I first watched the keynote and got introduced to Laravel Nova, I immediately fell in love with it!

A simple Composer package for an admin panel drop-in, plus its own code section in your repository under app/Nova/ , without tangling with your existing classes and codebase at all. Sign me up!

Open Source

As you have probably guessed, I love open source software! We use it every day, knowingly or unknowingly. There are probably dozens of articles about this, so I won’t go into detail.

Being someone who loves open source software and uses Laravel a lot, I have a few Laravel projects of my own that are open source on my GitHub.

One notably, which is an application (instead of a library/package). It’s actually more of a game than an application, but that’s not very important.

What is important, however, is that it has data! Structured data in a SQL database, accessed through Laravel’s own Eloquent ORM. Laravel Nova utilizes Eloquent to allow for a simple drop-in admin panel with minimal additional code, to generate beautiful CRUD forms for your data, where you can easily view and manage it!

I was actually looking for a proper administrative interface for my project’s data, although I have been making some custom admin pages by hand. After some consideration I went and bought Laravel Nova for my project, and tried to make it work the way I wanted it to.

Due to how Nova is licensed, inclusion of it in an open source project turned out to be a little complicated. You can’t just install it through a public central Composer repository (i.e. Packagist), because it doesn’t exist there. You need to download and install it manually. Redistribution of the release code is prohibited by the Terms of Service. For open source projects in particular, this proved a be a bit of a hassle to set up right.

For closed source projects where the code repositories are private, this is not really an issue. Since the documentation states you can put the package in ./nova in your project, you can pretty much leave it there and commit it to your (private) repo. Provided only people who are licensed to use Nova can access it.

There are a few ways to make this work, but I will show you how I did it.

Using Laravel Nova

Since we need to install (and update) Nova manually, by downloading a release behind an authentication wall, throwing it on your filesystem somewhere, and referencing to it from your application, a few questions and potential problems arose for my use case:

I need the Nova release code in order to use it. But, I can’t commit this to the open source repository (because redistributing is against the Terms of Service). How can I make my application recognize Laravel Nova as an installed Composer dependency for it to work, without redistributing the release code? As an open source project maintainer, my project has contributors. However, they’re not eligible to use my own Nova license, so they don’t have access to the Laravel Nova release code. How can I make sure my application works both with and without Laravel Nova? I have a deployment strategy. How can I make sure Laravel Nova gets included in the deployment pipeline for production usage? Note: For my project I use Deployer, so I will be writing about that.

I contemplated about these things for a while. And after buying a license and playing around with Nova locally, I think I have a pretty neat setup I want to share with you which answers the above questions.

There are some caveats and things to keep in mind when using this setup, since it isn’t perfect. But like I said, this is only my way to do it. I’m sure there are other ways to make it work, perhaps more elegantly than I have done.

Step 0: Get Laravel Nova

Before you can start using Laravel Nova at all, you’ll need a license. Laravel Nova isn’t free ($99 to $199 per site), however. So decide for yourself if Laravel Nova is something for your project.

After buying a license, you can download a zip file with the Nova contents. With this, you will need to store the code somewhere.

There are multiple possible ways to go with this. I’ll be sharing you my solution that takes the aforementioned questions in mind.

Step 1: Mirror the code privately for Composer

This is actually a tip from Barry vd. Heuvel on Twitter I saw the other day. You can create a free private BitBucket or GitLab repository where you can mirror the Nova release code, and have your project refer to that.

This solution works pretty well (I’m using a private GitLab repository), and you can commit the repository reference in your composer.json to your own repository. You can also commit and tag each release, so you can see what has been changed in the code between versions. Neat!

However, it wouldn’t let any other people (like contributors) get the package when installing Composer packages, due to the repository where the package is on being private and them not having access to it. They don’t even need Nova in the first place. So adding it as a hard dependency in this way is not going to work.

This is why we’re going to create a dummy package!

Step 2: Create a dummy package

We’ll create a dummy package to ensure Composer never complains when we don’t really have access to Laravel Nova, but still act as if we have it installed!

All we need for this is a simple JSON file at nova/composer.json :

With this, you can refer it as a Composer dependency with its path in your composer.json like so:

Running composer require laravel/nova will now resolve it properly as a dependency.

And any Nova packages you install through Composer will (should) also happily accept this dummy package as their laravel/nova dependency!

But be careful not to touch or resolve those classes outside of Nova, or else your application will probably break, because the required Nova files aren’t actually there.

You can commit these changes to nova/composer.json and composer.json to your public repository.

Step 3: Installing Laravel Nova

By doing this, we still haven’t installed Laravel Nova yet. Just a dummy package pretending as one. How do we really install it for ourselves?

This is where it gets a bit tricky. Since we want to install and use Nova locally, any dependencies of Nova will also be installed. This automatically results in changes in files like composer.lock , nova/composer.json (overwriting it with the real Nova composer.json ), and optionally (in my case) PhpStorm IDE files like .idea/ProjectName.iml and .idea/php.xml .

I don’t think these are changes which needs to be committed to the repository, since as far as the main repository is concerned only the dummy package needs to exist, and not Laravel Nova itself, nor any of its dependencies. So we need to do this locally. And just locally. And without accidentally committing these changes.

The way I’ve done this is being able to enable or disable Laravel Nova on the fly locally, changing the contents of the nova/ directory to Laravel Nova when I need it, or back to the dummy package when I don’t, and having Composer act on it.

This way I can enable it to test around with it locally and work on the dashboard, and disable it when I need to prepare for a release or commit actual changes in my Composer files (like adding a new package). By having a private mirror of Nova we can easily pull it in with git clone , which will also help down the road during deployments (more on that later).

After lots of tweaking and fiddling, I’ve made two Bash functions in order to facilitate this:

I put these in my .bash_aliases . Be sure to change the git clone URL to your own private Nova mirror!

The nova.enable function pulls in the Nova release code from my private repository, puts it in nova/ and installs the real package through Composer. And the nova.disable uninstalls it and reverts nova/ back to a dummy package.

You don’t have to use these functions, though. You can call the commands manually instead. But I found it convenient to come up with and use these.

Step 4: Setting up Laravel Nova for the first time

Now that we’ve got proper access to Laravel Nova, let’s set it up:

php artisan nova:install

This will publish Nova’s resources (config file, assets, language files and views), its service provider, register it, and generate a User resource (with an abstract Resource) under app/Nova/ . I won’t go into detail, so consult the official documentation for more about this.

The published config file should be versioned, so throw that in Git. Same with the NovaServiceProvider class. Revert the changes to your config/app.php where it registers the provider automatically, since we’re going to do that somewhere else.

We don’t really want the other published files in our repository (since they are also part of the Nova release codebase, especially the compiled js/css files which get places in public/nova-assets/ ).

Luckily we can easily ignore them by adding a few lines in our .gitignore file:

(I also added nova/ in there (after committing nova/composer.json !) so it doesn’t clog my git status .)

This also ensures we have the latest versions of all the assets whenever we (re)install Nova. Sweet!

Remember the service provider? Let’s register that one in AppServiceProvider , but only if we have Nova installed! We can check if class Laravel\Nova\Nova exists for this. (I honestly don’t know how (in)efficient this is, but it works. Maybe there’s a better way by checking Composer.)

With this, Nova will automatically register its routes, migration etc if you have it installed, and it won’t complain if you use the dummy package, provided by default in the repository.

Having all this, if you clone the project freshly now, you can call php artisan nova:publish (instead of php artisan nova:install ) to publish all the assets, without overwriting any assets you’ve put in version control (like the config file).

Now you’ll have Laravel Nova working for your open source Laravel project, without redistributing the Nova release code!

The only caveats are:

You need to manually enable Nova to use it, You need to selectively add files to Git, to not accidentally commit changes to your Composer lockfile (for example), You need to disable it when you need to prepare a deploy or commit changes to your Composer files.

Deployer integration

Because I use Deployer to run my deploys, I have created a task that allows me to install Nova on production whenever I run my deploy.

It does pretty much the same as mentioned above. Create a new task and run it after deploy:vendors :

Again, change the git clone URL to match your private Nova repository. Also make sure your deployment user on your production box has read access to the repository by using a deploy key.

PHPUnit coverage errors

If you’re like me and want to run PHPUnit with coverage, it’s going to complain because it can’t resolve some Nova classes you’re referring to in app/Nova/ and in your NovaServiceProvider . This is because it automatically scans and tries to resolve everything, regardless of actual usage in your application lifecycle.

A simple solution is to just exclude them in the filter section in phpunit.xml(.dist) :

This will also work in your CI pipeline if you have one (e.g. Travis). But obviously you’ll need something more sophisticated than this if you want to start testing your Nova classes. You will then need to pull in Nova there, so all the dependencies can be resolved in order to test the code and run coverage.