backpack / basset
Dead-simple way to load CSS or JS assets only once per page, when using Laravel 10+.
Requires
- guzzlehttp/guzzle: ^7.5
- laravel/framework: ^10.1|^9.0
Requires (Dev)
- nunomaduro/collision: ^6.0|^7.2
- orchestra/testbench: ^7.22|^8.5
- pestphp/pest: ^1.22|^2.5
- pestphp/pest-plugin-laravel: ^1.4|^2.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ~9.0|~10.0
README
The dead-simple way to use CSS and JS assets in your Laravel projects.
// instead of <script src='https://cdn.com/path/to/file.js'> <link href='https://cdn.com/path/to/file.css'> // you can do @basset('https://cdn.com/path/to/file.js') @basset('https://cdn.com/path/to/file.css')
That will internalize the file (copy to storage/app/public/bassets
) and make sure that file is only loaded once per page.
Using Basset, you easily internalize and use:
- files from external URLs (like CDNs)
- files from internal, but non-public URLs (like the vendor directory)
- entire archives from external URLs (like Github)
- entire directories from local, non-public paths (like other local projects)
Installation
# install the package via Composer: composer require backpack/basset # if you haven't already, create the symbolic link from public to storage: php artisan storage:link
Note
By default Basset relies on the public disk, you may change it if you want to, but if you stick to the defaults, make sure your disk is properly setup onconfig/filsystems.php
, make sure it looks like the default one.
Usage
Now you can replace your standard CSS and JS loading HTML with the @basset()
Blade directive:
// for files from CDNs - <script src="https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js"> + @basset('https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js')
Basset will:
- copy that file from the vendor directory to your
storage
directory (aka. internalize the file) - use the internalized file on all requests
- make sure that file is only loaded once per pageload
Features
The package provides 4 Blade directives, @basset()
, @bassetBlock()
, @bassetArchive()
, @bassetDirectory()
, that will allow you to:
Easily self-host files from CDNs
- <script src="http://localhost/storage/basset/cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js"></script> + @basset('https://cdn.ckeditor.com/ckeditor5/36.0.1/classic/ckeditor.js')
Basset will:
- copy that file from the CDN to your
storage/app/public/basset
directory (aka. internalize the file) - use the local (internalized) file on all requests
- make sure that file is only loaded once per pageload
Easily use local files from non-public directories
+ @basset(resource_path('assets/file.css')) + @basset(resource_path('assets/file.js'))
Basset will:
- copy the file from the provided path to
storage/app/public/basset
directory (aka. internalize the file) - use the internalized file on all requests
- make sure that file is only loaded once per pageload
Easily move code blocks to files, so they're cached
+ @bassetBlock('path/or/name-i-choose-to-give-this') <script> alert('Do stuff!'); </script> + @endBassetBlock()
Basset will:
- create a file with that JS code in your
storage/app/public/basset
directory (aka. internalize the code) - on all requests, use the local file (using
<script src="">
) instead of having the JS inline - make sure that file is only loaded once per pageload
Easily use archived assets (.zip & .tar.gz)
+ @bassetArchive('https://github.com/author/package-dist/archive/refs/tags/1.0.0.zip', 'package-1.0.0') + @basset('package-1.0.0/plugin.min.js')
Basset will:
- download the archive to your
storage/app/public/basset
directory (aka. internalize the code) - unarchive it
- on all requests, use the local file (using
<script src="">
) - make sure that file is only loaded once per pageload
Easily internalize and use entire non-public directories
+ @bassetDirectory(resource_path('package-1.0.0/'), 'package-1.0.0') + @basset('package-1.0.0/plugin.min.js')
Basset will:
- copy the directory to your
storage/app/public/basset
directory (aka. internalize the code) - on all requests, use the internalized file (using
<script src="">
) - make sure that file is only loaded once per pageload
Easily internalize everything from the CLI, using a command
Copying an asset from CDNs to your server could take a bit of time, depending on the asset size. For large pages, that could even take entire seconds. You can easily prevent that from happening, by internalizing all assets in one go. You can use php artisan basset:internalize
to go through all your blade files, and internalize everything that's possible. If you ever need it, basset:clear
will delete all the files.
php artisan basset:internalize # internalizes all @bassets php artisan basset:clear # clears the basset directory
In order to speed up the first page load on production, we recommend you to add basset:internalize
command to the deploy script.
Why does this package exist?
- Keep a copy of the CDN dependencies on your side.
For many reasons you may want to avoid CDNs, CDNs may fail sometimes, the uptime is not 100%, or your app may need to work offline.
- Forget about compiling your assets.
Most of the times backend developers end up messing around with npm and compiling dependencies. Backpack has been there, at some point we had almost 100Mb of assets on our main repo. Basset will keep all that mess away from backend developers.
- Avoid multiple loads of the same assets.
In Laravel, if your CSS or JS assets are loaded inside a blade file:
// card.blade.php <div class="card"> Lorem ipsum </div> <script src="path/to/script.js"></script>
And you load that blade file multiple times per page (eg. include card.blade.php
multiple times per page), you'll end up with that script
tag being loaded multiple times, on the same page. To avoid that, Larvel 8 provides the @once
directive, which will echo the thing only once, no matter how many times that blade file loaded:
// card.blade.php <div class="card"> Lorem ipsum </div> @once <script src="path/to/script.js"></script> @endonce
But what if your script.js
file is not only loaded by card.blade.php
, but also by other blade templates (eg. hero.blade.php
, loaded on the same page? If you're using the @once
directive, you will have the same problem all over again - that same script loaded multiple times.
That's where this package comes to the rescue. It will load the asset just ONCE, even if it's loaded from multiple blade files.
Change log
Please see the releases tab for more information on what has changed recently.
Testing
$ composer test
Contributing
Please see contributing.md for details and a todolist.
Security
If you discover any security related issues, please email hello@backpackforlaravel.com instead of using the issue tracker.
Credits
License
MIT. Please see the license file for more information.