Are you curious how open-source Laravel packages are developed from scratch? Or are you unsure whether any specific functionality makes a good use case to be a Laravel package?
Let’s talk about these and other related questions today.
We all are fans of Laravel and its ecosystem for its simplicity and extensibility. Packages have been playing a major role in moving it forward. Especially official packages by Laravel, Spatie , Barry vd. , and others have made our lives and code better.
Why you should build a Laravel Package
Better coding skills
Open-source is magical. Putting your code out into the public makes you a bit vulnerable at the beginning but brings out the best of you. The fear of doing something wrong prevents every bit of you from doing the git push origin master
but it’s always worth it. Laracasts’ series on open source project management can help a lot if you’re not well-versed with GitHub.
More (and better) work
You will build you brand leading to more work.
"Talk is cheap. Show me the code." - Linus Torvalds (creator of Linux and Git)
As developers and clients see your code and benefit from it, you will get more recognition.
Save time
You will save yourself considerable amount of time when you convert a piece of code, that you are using in more than one projects, into a package. “DRY” approach isn’t a new thing. We know its benefits.
In short, open-source package development makes your developer life better.
Now that we have a better idea about the need to go ahead with package development, let’s make one together now.
On a side note, contributing to an existing solution is also a great way to start if there is already an open-source package/library of your choice.
A new Laravel package from scratch
Note:
I had said we will be building a real package. While thinking about an example, the only good option I could come up with was one of my own packages - Laravel Log Enhancer. It is short enough to cover quickly as well as plays with important parts of package development to learn the basics properly.
If you haven’t created any Laravel package before, I insist you to do this with me. It’ll be fun. Even if you make the same package, you’ll have more confidence and will be inspired to make changes or create a new one instantly. All the steps are undoable - you’ve nothing to lose. And true learning is all about doing the things practically. Our requirements are basic. If you’re already running any Laravel app locally, you’ve it all.
Let’s start.
1. New package directory
Create a directory with a name of the package. I will call it laravel-log-enhancer
.
mkdir laravel-log-enhancer && cd laravel-log-enhancer
2. Love for git
Initialize a git repository. We’ll need GitHub repo to put the package online.
git init
3. composer.json
Every package starts with a composer.json
file. Let’s create it. The easiest way to create it is to fire the init
command.
composer init
Or you can just copy it from this stub and make changes accordingly.
Commit the change. Not compulsory but we will do it after each unique step as a good habit.
4. Namespace and autoloading
We will put the main code of our package in src
directory.
mkdir src && cd src
By the way, just like Laravel web app development, there are no hard rules about directory structure here but a helpful convention to follow.
We will update our composer.json
file for 2 important things.
- When a Laravel project uses our package, we can inform it about the location of the files of the package to be loaded by putting the path in PSR-4 autoloading part of
composer.json
. - To make the installation easy for the developer, we will put the location of the service provider, that should be automatically detected by Laravel, in
extra
section of the file.
...
"autoload": {
"psr-4": {
"Freshbitsweb\\LaravelLogEnhancer\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Freshbitsweb\\LaravelLogEnhancer\\LaravelLogEnhancerServiceProvider"
]
}
}
...
By autoload, the parent Laravel web app knows about our base namespace i.e. Freshbitsweb\LaravelLogEnhancer
and the files location which is the src
directory. And Laravel’s awesome package discovery feature helps us remove a step from package installation process.
5. The service provider dilemma:
Many beginners stuck at this stage. Don’t worry. Let’s try to simplify this. A service provider is a file that can tell the parent Laravel application about various offerings of the package.
Common belief is that we always need a service provider for a package. That’s not the case. If your package doesn’t need to autoload any resources in advance, it can skip the service provider. But in most of the cases, for a package to be useful enough, service provider is required.
We will use it in our case to load the default configuration options of the package as well as offer an option to export those config options to the parent Laravel web app.
<?php
namespace Freshbitsweb\LaravelLogEnhancer;
use Illuminate\Support\ServiceProvider;
class LaravelLogEnhancerServiceProvider extends ServiceProvider
{
/**
* Publishes configuration file.
*
* @return void
*/
public function boot()
{
$this->publishes([
__DIR__.'/../config/laravel_log_enhancer.php' => config_path('laravel_log_enhancer.php'),
], 'laravel-log-enhancer-config');
}
/**
* Make config publishment optional by merging the config from the package.
*
* @return void
*/
public function register()
{
$this->mergeConfigFrom(
__DIR__.'/../config/laravel_log_enhancer.php',
'laravel_log_enhancer'
);
}
}
The code is quite simple here. In the boot
method, we put the code to allow the developer to export the config options by simply writing:
php artisan vendor:publish -tag=laravel-log-enhancer-config
And in the register
method, we tell the Laravel app to add the config options from our file into the web app config. Commit the update and let’s create our config file next.
6. Config options:
As a part of the convention, we will put our config file in config
directory inside root folder next to src directory.
mkdir config && cd config && touch laravel_log_enhancer.php
Put the following code in the file.
<?php
return [
'log_request_details' => true,
'log_input_data' => true,
'log_request_headers' => false,
'log_session_data' => true,
'log_memory_usage' => false,
'log_git_data' => false,
// You can specify the inputs from the user that should not be logged
'ignore_input_fields' => ['password', 'confirm_password'],
];
This file contains few configuration options just like a regular Laravel config file. Commit.
7. Package classes
Final piece of code, for actual enhancement of Laravel logs, is the LogEnhancer.php
file. To keep the length of the article digestible, I will directly link you to the actual class that you can copy. We also have RequestDataProcessor.php
in the package. Put both of them in the src
directory and you should be good to go.
8. Other important files
There are few other files that we need to add finally.
README file needs a special mention here. It is the face of the package. You should be writing detailed installation steps and other notes with proper flow in this file. Go through this GitHub guide for more.
Commit this change and now our package is ready to use.
What next? It’s time to release it.
How to release the package
If you haven’t pushed the package code to GitHub, do it first. If you don’t know how, this article can help.
Then, head over to Packagist , create an account or sign in, Click on Submit, specify the GitHub repo URL, … Steps are quite easy and self-explanatory. You should also enable Auto update of the package and consider Semantic versioning and releasing .
Congrats. We’re done. Breath for a few minutes. There’s more.
Next, there are many other things are not part of the package development but are important for the development lifecycle and maintenance. Let’s go through them quickly.
How to use the package locally
We don’t have to push the updates online before testing it locally. Composer repositories path to the rescue.
Not just the package, we can do it with any repository. Here’s a great article explaining the details.
Let’s do it. Install a fresh Laravel app next to your package directory.
laravel new laravel-with-package
Make changes in it’s composer.json
file
...
"repositories": [
{
"type": "path",
"url": "../laravel-log-enhancer"
}
],
...
Install the package by firing the following command.
composer require gauravmak/laravel-log-enhancer
Complete the installation steps and you can use the package now.
Testing
“I find that weeks of coding and testing can save me hours of planning.” -
Unknown
They say - do not use a package without tests. They’re right. As the package gets bigger in size and more contributors enter the scene, some random commit can break the code functionality somewhere down the line. And we never want it to happen, right?
And it’ not hard. All we need to do it to check if the package is doing what it is supposed to do after every change/commit. In this package, we are adding processors to the Monolog handlers so that more data can be logged.
Unfortunately, as of now, Monolog doesn’t provide a method to fetch the processors of a handler so we are limited but let’s create a base of the testing for this package so that you know how to add tests to your custom package.
To start, we will add requirements to the composer.json
file.
...
"require-dev": {
"phpunit/phpunit": "^7.0",
"orchestra/testbench": "~3.6.0"
},
"autoload-dev": {
"psr-4": {
"Freshbitsweb\\LaravelLogEnhancer\\Test\\": "tests"
}
},
...
We are basically testing a package which is outside a Laravel app. orchestral/testbench is a great package which can add the necessary dependencies so that we can test it as if we have all the Laravel goodies.
I have also added the following files to make the base of testing for our app.
Go through the README file of the testbench package for all details about how we can interact with Laravel while testing our package.
Integrations
There are so many helpful tools that integrate with GitHub repo and help us maintain the packages/libraries easily.
I suggest Travis CI for testing the package after each update and StyleCI for maintaing the code style.
I have integrated StyleCI in the package already. You should also consider adding badges to the README file.
Secret sauce of a successful package
You reap the benefits of making the package when more and more developers use it. And for that, there are so many factors starting from the basic idea behind the package to the stability and age of the package (stars).
If I were to decide on most important point for that, it would be the developer friendliness of the package. Yes, the exact reason why Laravel is popular.
Try to minimize the installation steps and the code that is required to use the package. Plus, it has to be readable enough that it doen’t need to annotated with long comments.
For example,
$users = User::with('roles')->get();
So simple, we know this operation involves join queries and other stuff. Still, you like to write it and read it. Do things on a similar level.
Final notes
That’s it for the day. We learned why package development is good for everyone and how to do it step-by-step using a real example. If you have any questions or get stuck anywhere, just add a comment below, I would be happy to help.
And If you think this can help other Laravel developers in your online network, I’d be happy to see you sharing this with them. Thanks.
Top comments (1)
Awesome!!! This is the only guide i was looking for.