Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Skeleton Laravel Package

mrshanebarron/skeleton

A Laravel package skeleton offering a clean starting point for building reusable packages, with standard structure, service provider setup, and sensible defaults for testing, configuration, and distribution.

View on GitHub
Deep Wiki
Context7

Getting Started

First, orient yourself on what this package actually is. The repo is described as a "Laravel UI component package," but its own description frames it as a package scaffold — a starting point for building reusable Laravel packages. Those are two different jobs, and your first step is to decide which one you're doing:

  • Bootstrapping a new package — clone/copy the skeleton into a fresh repo, then strip the sample code.
  • Consuming it as a dependency — composer require mrshanebarron/skeleton, publish config, use whatever components/commands it exposes.

If you're consuming it, don't assume a documented public API exists. Read src/ before you write anything against it.

Minimal install (consumer path):

  1. composer require mrshanebarron/skeleton
  2. Confirm auto-discovery — Laravel 11+ writes it to bootstrap/providers.php; older apps need the provider in config/app.php. If you see no provider registered, that's your first bug.
  3. Publish only what you need:
    php artisan vendor:publish --provider="MrShanebarron\Skeleton\SkeletonServiceProvider" --list
    
    Use --list first — you do not want to blind-publish migrations and assets into the repo. On v1.0.1 the config file is sb--prefixed (config/sb-skeleton.php or similar); on v1.0.0 it was not.
  4. Verify the merged view:
    php artisan tinker
    >>> config('sb-skeleton')
    

Minimal scaffold (author path):

  1. Clone the repo, rename the vendor/namespace throughout (composer.json, src/, the service provider class name, tests).
  2. Run composer install and composer dump-autoload; confirm PSR-4 maps to your namespace.
  3. php artisan test (or vendor/bin/phpunit) — the basic test setup is part of the value here.
  4. Delete the sample config/migration/route before you add your own, otherwise you'll ship placeholder files.

Where to look first, in order:

  • composer.json — the actual package name, PSR-4 root, and Laravel/PHP constraints. This is your compatibility truth; ignore the description.
  • The service provider's register() / boot() — mergeConfigFrom(), publishes(), container bindings, view/component registration.
  • config/sb-*.php — the only real knob surface.
  • src/ — if it's genuinely a UI package, look for View/Components/ and Blade views under resources/views/.
  • tests/ — the skeleton's tests double as usage documentation.

First use case: publish the config, set your .env-backed values into config/sb-skeleton.php, then render the package's component or resolve its class in tinker to confirm it boots. That's it — a 15-minute sanity loop.

Implementation Patterns

Config-first, always. Drive the package from config/sb-*.php, never from hardcoded values or direct env() calls in your app code. Keep secrets in .env and reference them from config:

// config/sb-skeleton.php
'api_key' => env('SB_API_KEY'),

This is the only pattern that survives php artisan config:cache.

Commit your published config. Publish once, commit, and merge new keys by hand on upgrade. Re-publishing on deploy with --force will silently discard your customisations, and mergeConfigFrom() is shallow — new nested keys added by a release won't appear in your published file until you diff it.

Per-environment and per-tenant overrides. For staging/prod divergence, set config in your own provider before the package resolves its singleton:

// AppServiceProvider::register()
$this->app['config']->set('sb-skeleton.driver', 'redis');

For per-request or multi-tenant overrides, set → resolve → use → reset, or bind a fresh instance. Do not leave mutated config lying around; queue workers and Octane will carry it into the next request.

UI component usage (if that's what you're here for):

<x-skeleton::button variant="primary">Save</x-skeleton::button>

Publish views only if you need to restyle: vendor:publish --tag=views. Otherwise rely on the package's shipped Blade and override via your own component wrapper — that survives upgrades cleanly.

Testing patterns:

  • Config: set it before resolving anything.
    config()->set('sb-skeleton.mode', 'fake');
    
  • Contracts/services: bind a fake in the container and assert on recorded calls rather than hitting anything real.
  • Components: use Laravel's component test helpers ($this->blade('<x-skeleton::foo />')) and assert the rendered output, not internal state.

Deploy workflow. Put these in order in your deploy script:

php artisan config:clear
# only if you don't keep local customisations:
# php artisan vendor:publish --tag=config --force
php artisan config:cache
php artisan queue:restart      # if workers hold config
php artisan octane:reload      # if using Octane

Extension points worth using, in preference order:

  1. Container rebinding of the package's interfaces/contracts — cleanest override.
  2. Overriding published config.
  3. Listening to events it dispatches.
  4. Subclassing internals — last resort, breaks on patch releases.

If you're authoring from the skeleton: treat it as a template, not a dependency. Vendor it as a git template or run composer create-project, then immediately rename the namespace and delete sample artifacts so nothing collides with the real package later.

Gotchas and Tips

The v1.0.1 config rename is the number-one trap. The config file is now sb--prefixed. Consequences for anyone who installed v1.0.0:

  • The old unprefixed file sits on disk, no longer merged. config('sb-skeleton.…') falls back to package defaults silently — no error, no deprecation warning.
  • Symptom: "my credentials came back empty after composer update" or "why is it using defaults in prod?"
  • Fix: config:clear, diff old file against vendor/mrshanebarron/skeleton/config/sb-*.php, port your keys, delete the old file, then config:cache.
  • The array key namespace may have changed too — not just the filename. Audit your own code, .env comments, and deploy scripts for references to the old key.

config:cache hides .env. Any package code (or yours) calling env() directly instead of config() will return null in production. This is the classic "works locally, broken on the server" cause. If you're authoring a package from this skeleton, this is the single most important rule to enforce in review.

Singletons capture config at resolve time. Changing config after the package's singleton is built does nothing. Call app()->forgetInstance(SomeClass::class) first, or bind a new instance.

--force overwrites, it doesn't merge. Back up customised published files before any vendor:publish --force. Better: don't publish-and-customise at all — override in your own provider.

Untagged vendor:publish pulls everything. It will drag migrations, assets, and views into your repo. Always use --tag. If you don't know the tag, --list it.

Octane and queue workers hold config in memory. After any config change deployment, php artisan queue:restart and php artisan octane:reload. Without this, you'll spend an hour debugging a change that's already live.

Debugging one-liners:

php artisan tinker --execute="dump(config('sb-skeleton'));"   # merged view
php artisan config:show sb-skeleton                          # Laravel 9+
php artisan about                                            # confirm no stale config cache
composer show mrshanebarron/skeleton                         # actual installed version

Release-hygiene signal. A user-visible filename reaching a 1.0.0 tag is a QA gap on the publish path. Expect further 1.0.x churn — pin ^1.0.1 rather than ^1.0, and read changelogs on every bump rather than auto-merging.

Add a deploy-time assertion. The rename failure is silent; make it loud. Two lines in a provider's boot() or a deploy check:

abort_unless(config('sb-skeleton.api_key'), 500, 'sb-skeleton config not loaded — check for orphaned config file.');

Scaffold-specific pitfall: if you copy the skeleton as a starting point, the sb- config prefix and the sample namespace will follow you. Rename both in the same commit or you'll end up with two packages writing to the same config path.

Zero stars, single maintainer. No community to lean on. Budget for fork-and-own cost if you build something load-bearing on it, and keep your usage surface thin — config reads and published views, not subclassed internals.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox