Creating Composer package for Laravel from scratch

Step-by-step instructions for those wanting to understand every little detail by actually doing it.

Let me guess. You are reading this piece because you have something reusable in your Laravel project, and you want to create a Composer package and actually reuse it in other projects. If so, hang on, you are in the right place.

Example project

In a project of mine, I’ve been using Hero Icons. For each icon I used, I created a Blade component, and rendered it wherever I needed that icon, like this:

# resources/views/components/heroicons/outline/bell.blade.php
<svg {{ $attributes }} xmlns="<http://www.w3.org/2000/svg>" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
    <path stroke-linecap="round" stroke-linejoin="round" d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" />
</svg>

# template using the icon
<x-hero-icons.outline.bell class="h-6 w-6" />

It worked pretty well, and I wanted to use the same approach in other projects. I found that just copying Hero icon components from project to project is pretty dumb, so I decided to extract them into a Composer package.

There are good tools that make package creation easier, but I decided to create this package manually, mainly to learn nuts and bolts by doing it.

Plan of attack

There is the best practice to follow:

  1. Create a package inside the project, extract reusable code there, and make the project use it.

  2. Only after everything works and is “good enough” (documented and unit-tested), move the package into its own Git repository and publish it.

In this article, I only cover the first step that takes place inside the project codebase and only the minimum steps needed by my example project. I will:

  1. Create an empty Composer package.

  2. Create a service provider class for the package that auto-registers itself in the project.

  3. Move the Blade components into the package.

  4. Register the package Blade component directory in the service provider.

  5. Reference the Blade components in the templates that use Heroicons.

Creating an empty Composer package

  1. Create the packages/osmianski/laravel-heroicons/composer.json:

     {
         "name": "osmianski/laravel-heroicons",
         "description": "Heroicons as Laravel Blade components",
         "license": "MIT",
         "authors": [
             {
                 "name": "Vlad Osmianski",
                 "email": "vlaosm@gmail.com",
                 "homepage": "<https://osmianski.com/>"
             }
         ],
         "keywords": ["Laravel", "Blade", "Heroicons"],
         "require": {
             "illuminate/support": "~10"
         },
         "autoload": {
             "psr-4": {
                 "Osmianski\\\\Heroicons\\\\": "src/"
             }
         }
     }
    
  2. Reference it in the project’s composer.json:

     {
             ...
         "require": {
                     ...
             "osmianski/laravel-heroicons": "@dev"
         },
             ...
         "repositories": {
             "osmianski/laravel-heroicons": {
                 "type": "path",
                 "url": "packages/osmianski/laravel-heroicons",
                 "options": {
                     "symlink": true
                 }
             }
         }
     }
    
  3. Run:

     composer update
    

Notice that the package name, osmianski/laravel-heroicons, differs from the root PHP namespace, Osmianski\\Heroicons\\. It’s on purpose.

The laravel- prefix tells you that this package is intended to be used in Laravel projects. If I had a framework-agnostic package (the one that works with any framework), it’s would have no prefix.

Creating the service provider

  1. Create the src\\HeroiconServiceProvider.php in the package directory:

     <?php
    
     namespace Osmianski\\Heroicons;
    
     use Illuminate\\Support\\ServiceProvider;
    
     class HeroiconServiceProvider extends ServiceProvider
     {
     }
    
  2. Make the service provider class auto-discoverable by the Laravel project:

     {
         ...
         "extra": {
             "laravel": {
                 "providers": [
                     "Osmianski\\\\Heroicons\\\\HeroiconServiceProvider"
                 ]
             }
         }
     }
    
  3. Run:

     composer update
    

Moving the Blade templates

  1. Move the Balde templates from the resources/views/components/heroicons project directory to the resources/views/components package directory.

  2. Register the Blade templates in the HeroiconServiceProvider::boot() method:

     public function boot(): void
     {
         $this->loadViewsFrom(__DIR__.'/../resources/views', 'heroicons');
    
         $this->publishes([
             __DIR__.'/../resources/views' => resource_path('views/vendor/heroicons'),
         ]);
     }
    
  3. Reference the package Blade templates in the project:

     <x-heroicons::outline.bell class="h-6 w-6" />
    

Here, x-heroicons matches the namespace specified in the second parameter of the loadViewsFrom() call.

And it works!

For more information on creating Composer packages for Laravel, check these resources: