smorken/frontend-assets
Smorken Frontend Assets is a Laravel package for registering, organizing, and rendering CSS and JavaScript assets. It provides helpers for asset collections and Blade integration, making it easier to manage frontend dependencies consistently across layouts and views.
Install (assuming a package on Packagist; otherwise add the VCS repo):
composer require smorken/frontend-assets
Auto-discovery — Laravel 5.5+ picks up the service provider automatically. If you're on an older skeleton, register Smorken\FrontendAssets\FrontendAssetsServiceProvider::class in config/app.php.
Publish the config (if the package ships one) and inspect it first:
php artisan vendor:publish --provider="Smorken\FrontendAssets\FrontendAssetsServiceProvider"
This is where CDN URLs, Bootstrap version, jQuery/Popper toggles, and SRI integrity hashes will live. Read this file before anything else — it tells you exactly which directives exist and what they emit.
First use case — replace hand-written CDN tags in your master layout with the package's Blade macros:
{{-- resources/views/layouts/app.blade.php --}}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@yield('title')</title>
@bootstrapCss
</head>
<body>
@yield('content')
@jquery
@popper
@bootstrapJs
</body>
</html>
Confirm the rendered HTML in view-source (or with curl) matches the versions you expect — this verifies both the macro registration and the config wiring in one step.
Single master layout. The whole point of the package is to centralize CDN <link>/<script> tags. Put every directive in one layout (layouts/app.blade.php) and let child views extend it. Don't scatter directives across partials — it makes version bumps and SRI updates a hunt.
Per-page asset stacking. Since directives output tags directly, combine with Blade stacks when you need page-specific CSS/JS on top of Bootstrap:
{{-- layout --}}
@bootstrapCss
@stack('styles')
{{-- page --}}
@push('styles')
<link rel="stylesheet" href="{{ asset('css/pricing.css') }}">
@endpush
Version pinning via config, not literals. Keep the Bootstrap/jQuery/Popper versions in config/frontend-assets.php and reference them through the env:
'version' => env('BOOTSTRAP_VERSION', '5.3.3'),
Then bump BOOTSTRAP_VERSION in .env per environment — no code changes, no accidental dev/prod drift.
Environment-aware override. For offline development or air-gapped CI, override directives in AppServiceProvider::boot() to fall back to local public/vendor assets:
if (app()->environment('local')) {
Blade::directive('bootstrapCss', fn () => '<link rel="stylesheet" href="/vendor/bootstrap/bootstrap.min.css">');
}
Register after the package provider so your definition wins.
Wrap it in a component for ergonomics. If you find yourself passing @bootstrapCss into many layouts, alias a component:
{{-- resources/views/components/layout.blade.php --}}
<head>@bootstrapCss ...</head>
{{-- usage --}}
<x-layout>@yield('content')</x-layout>
Test the rendered HTML. Add a feature test that hits GET / and asserts the expected CDN host and version string appear — this catches config-cache and SRI regressions cheaply:
$this->get('/')->assertSee('cdn.jsdelivr.net', false)
->assertSee('[email protected]', false);
integrity attribute, browsers silently drop the asset and you get an unstyled page. Always update version and integrity together (grab the hash from getbootstrap.com's download page).@jquery directive is a no-op or irrelevant for BS5; @popper is only needed for dropdowns/tooltips/popovers. Including jQuery anyway just bloats the page. Verify per-major-version behavior against the config.bootstrap.bundle.min.js if you're using the individual bundle's pieces; if using bootstrap.bundle.min.js (which bundles Popper), the @popper directive is redundant. Check what your config emits — double-loading Popper causes Uncaught SyntaxError: Identifier 'Popper' has already been declared.php artisan config:cache freezes the config the macros read. After changing CDN URLs or versions, run php artisan config:clear in local/staging; on production, redeploy rather than editing the cached file.Content-Security-Policy header, you must allow cdn.jsdelivr.net (or whichever host the config uses) in script-src/style-src. Confirm the host in the published config before writing the policy.FrontendAssetsServiceProvider::boot() — it will literally list each Blade::directive(...) and the string it returns. That's the entire public API; five minutes of reading covers all edge cases.Blade::directive() in your own provider. This is the cleanest extension point for pinning a version, swapping to a self-hosted CDN, or adding an @fontawesome directive in the same style.Cache-Control middleware, remember the HTML references a versioned URL, so busting the layout cache is only necessary when you bump version.How can I help you explore Laravel packages today?