PHPackages                             tannhatcms/basset - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. tannhatcms/basset

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

tannhatcms/basset
=================

Dead-simple way to load CSS or JS assets only once per page, when using Laravel 10+.

1.4.0(6mo ago)0231MITPHP

Since Mar 20Pushed 6mo agoCompare

[ Source](https://github.com/TanNhatCMS/Laravel-Backpack-basset)[ Packagist](https://packagist.org/packages/tannhatcms/basset)[ Docs](https://github.com/laravel-backpack/basset)[ RSS](/packages/tannhatcms-basset/feed)WikiDiscussions dev Synced 1mo ago

READMEChangelog (1)Dependencies (8)Versions (40)Used By (1)

Basset 🐶 - the better `asset()` helper for Laravel
==================================================

[](#basset----the-better-asset-helper-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/5f391f070d1134d240a362650d7129c998a2d50c5bfa8478b9763c913af54358/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6261636b7061636b2f6261737365742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/backpack/basset)[![Total Downloads](https://camo.githubusercontent.com/9996af87de2fa938ede4172562b10d7830182c46af2ae705c4860010e1638399/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6261636b7061636b2f6261737365742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/backpack/basset)[![StyleCI](https://camo.githubusercontent.com/173332d67173bf3477e7830503a954bb1bd4075aee9d5d60fd2ac7ed89c3d162/68747470733a2f2f7374796c6563692e696f2f7265706f732f3432313738353134322f736869656c64)](https://styleci.io/repos/421785142)

**Easily use your CSS/JS/etc assets from wherever they are, not just your public directory:**

```
{{-- if you're used to Laravel's asset helper: --}}

{{-- just change asset() to basset() and you can point to non-public files too, for example: --}}

```

That's all you need to do. **Basset will download the file to the predefined disk, then output that disk path to your asset.**

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)

No more publishing package files. No more NPM bloat, just to download some files. It's a simple yet effective solution in the age of `HTTP/2` and `HTTP/3`.

Installation
------------

[](#installation)

```
composer require backpack/basset
php artisan basset:install
```

To check that Basset is running correctly, please run:

```
# recommended - this will tell you if anything is wrong & what to do:
php artisan basset:check
```

Optionally, you can also publish the config file to make changes in how Basset works:

```
# optional
php artisan vendor:publish --provider="Backpack\Basset\BassetServiceProvider"
```

#### Storage Symlink

[](#storage-symlink)

By default, Basset uses the `storage` directory to store cached assets in a directory that is publicly-accessible. So it needs you to run `php artisan storage:link` to create the symlink. The installation command will ask to run that, and to add that command to your `composer.json`. That will most likely make it work on your development/staging/production servers. If that's not the case, make sure you create the links manually wherever you need them, with the command `php artisan storage:link`.

Usage
-----

[](#usage)

### The `basset()` Helper

[](#the-basset-helper)

You can just use the `basset()` helper instead of Laravel's `asset()` helper, and point to CDNs and non-public files too. Use [Laravel's path helpers](https://laravel.com/docs/10.x/helpers#paths-method-list) to construct the absolute path to your file, then Basset will take care of the rest.

For local from CDNs:

```
{{-- instead of --}}

{{-- you can do --}}

```

Basset will:

- copy that file from the vendor directory to the basset disk (if needed)
- use the internalized file on all requests

### The `@basset()` Directive

[](#the-basset-directive)

For known asset types like CSS, JS, images and videos, among others, Basset makes it even shorter to load assets. No need to write the HTML for your ``, `` or ``, just use the `@basset()` directive and all of the needed HTML will be output for you:

```
{{-- instead of --}}

{{-- you can do --}}
@basset('https://cdn.com/path/to/file.js')
@basset('https://cdn.com/path/to/file.css')
@basset(resource_path('/path/to/file.jpg'))
@basset(resource_path('/path/to/file.pdf'))
```

These are the know file types;

File extensionHTML element`.js````.css````.jpg` `.jpeg` `.png` `.webp` `.gif` `.svg````.mp4` `.webm` `.avi` `.mp3` `.ogg` `.wav````.ico````.pdf````.vtt```Basset will:

- copy that file from the vendor directory to your basset directory (aka. internalize the file)
- use the internalized file on all requests
- make sure that file is only loaded once per pageload

### The `@bassetBlock()` Directive

[](#the-bassetblock-directive)

Easily move code blocks to files, so they're cached

```
+   @bassetBlock('path/or/name-i-choose-to-give-this')

      alert('Do stuff!');

+   @endBassetBlock()
```

Basset will:

- create a file with that JS code in your basset directory (aka. internalize the code)
- on all requests, use the local file (using ``) instead of having the JS inline
- make sure that file is only loaded once per pageload

### The `@bassetArchive()` Directive

[](#the-bassetarchive-directive)

Easily use archived assets (.zip &amp; .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 basset directory (aka. internalize the code)
- unarchive it
- on all requests, use the local file (using ``)
- make sure that file is only loaded once per pageload

*Note:* when referencing `.zip` archives, the [PHP zip extension](https://www.php.net/manual/en/book.zip.php) is required.

### The `@bassetDirectory()` Directive

[](#the-bassetdirectory-directive)

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 basset directory (aka. internalize the code)
- on all requests, use the internalized file (using ``)
- make sure that file is only loaded once per pageload

### The `basset` Commands

[](#the-basset-commands)

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:cache` 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:cache         # 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 `php artisan basset:cache` command to your deploy script.

Configuration
-------------

[](#configuration)

Take a look at [the config file](https://github.com/Laravel-Backpack/basset/blob/main/src/config/backpack/basset.php) for all configuration options. Notice some of those configs also have ENV variables, so you can:

- enable/disable dev mode using `BASSET_DEV_MODE=false` - when enabled Basset will check for changes in your url/files and update the cached assets
- change the disk where assets get internalized using `BASSET_DISK=yourdiskname`
- disable the cache map using `BASSET_CACHE_MAP=false` (needed on serverless like Laravel Vapor)

Deployment
----------

[](#deployment)

There are a lot of deployment options for Laravel apps, but we'll try to cover the gotchas of the most popular ones here:

### VPS / SSH / Composer available

[](#vps--ssh--composer-available)

- it is mandatory to run `php artisan storage:link` in production, for Basset to work; so it's recommended you add that to your `composer.json`'s scripts section, either under `post-composer-install` or `post-composer-update`;
- it is recommended to run `php artisan basset:fresh` after each deployment; so it's recommended you add that to your `composer.json`'s scripts section, either under `post-composer-update`;

### Laravel Forge

[](#laravel-forge)

It's just a managed VPS, so please see the above.

### Laravel Vapor

[](#laravel-vapor)

**Step 1.** In your `vapor.yml` include `storage: yourbucketname`

**Step 2.** In your Vapor `.ENV` file make sure you have

```
BASSET_DISK=s3
BASSET_CACHE_MAP=false

```

(optional) Before you deploy to Vapor, you might want to set up S3 on localhost to test that it's working. If you do, [the steps here](https://github.com/Laravel-Backpack/basset/pull/58#issuecomment-1622125991) might help. If you encounter problems with deployment on Vapor (particularly through GitHub actions) there are some [tips here](https://github.com/Laravel-Backpack/basset/pull/58#issuecomment-1622125991).

### FTP / SFTP / ZIP

[](#ftp--sftp--zip)

If you deploy your project by uploading it from localhost (either manually or automatically), you should:

- make sure the alias exists that would have been created by `php artisan storage:link`; otherwise your alias might point to an inexisting localhost path; alternatively you can change the disk that Basset is using, in its config;
- before each deployment, make sure to disable dev mode (`do BASSET_DEV_MODE=false` in your `.ENV` file) then run `php artisan basset:fresh`; that will make sure your localhost downloads all assets, then you upload them in your zip;

Why does this package exist?
----------------------------

[](#why-does-this-package-exist)

1. 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.

2. 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.

3. Avoid multiple loads of the same assets.

In Laravel, if your CSS or JS assets are loaded inside a blade file:

```
// card.blade.php

  Lorem ipsum

```

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](https://laravel.com/docs/8.x/blade#the-once-directive), which will echo the thing only once, no matter how many times that blade file loaded:

```
// card.blade.php

  Lorem ipsum

@once

@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.

FAQ
---

[](#faq)

#### Basset is not working, what may be wrong?

[](#basset-is-not-working-what-may-be-wrong)

Before making any changes, you can run the command `php artisan basset:check`. It will perform a basic test to initialize, write, and read an asset, giving you better insights into any errors.

The most common reasons for Basset to fail are:

1. **Incorrect APP\_URL in the `.env` file.**
    Ensure that APP\_URL in your `.env` matches your server configuration, including the hostname, protocol, and port number. Incorrect settings can lead to asset loading issues.
2. **Improperly configured disk.**
    By default, Basset uses the Laravel `public` disk. For new Laravel projects, the configuration is usually correct. If you're upgrading a project and/or changed the `public` disk configuration, it's advised that you change the basset disk in `config/backpack/basset.php` to `basset`. The `basset` disk is a copy of the original Laravel `public` with working configurations.
3. **Missing or broken storage symlink.**
    If you use the default `public` disk, Basset requires that the symlink between the storage and the public accessible folder to be created with `php artisan storage:link` command. During installation, Basset attempts to create the symlink. If it fails, you will need to manually create it with `php artisan storage:link`. If you encounter issues (e.g., after moving the project), recreating the symlink should resolve them.

Note for Homestead users: the symlink can't be created inside the virtual machine. You should stop your instance with: `vagrant down`, create the symlink in your local application folder and then `vagrant up` to bring the system back up.

#### Where are cached assets stored?

[](#where-are-cached-assets-stored)

Basset provides a few options out-of-the-box:

- **`basset` disk** - inside the storage directory (eg. `storage/app/basset`) \[DEFAULT\]
    - PROs: the Git history is clean - because your cached assets will NOT be tracked by Git;
    - CONs: you have to run `php artisan basset:cache` in your deploy script, which adds seconds to your deploy time; plus, it opens up a corner case on deployment - because assets are being re-cached upon deployment, if a CDN is down during deployment, the system will not be able to internalize it; if will however internalize it when the CDN is back on, and the page that loads the file gets accessed; we consider the tradeoffs minor and unlikely, which is why this is the DEFAULT;
    - How to enable: do nothing, or do `BASSET_DISK=basset` in your .env file;
- **`public_basset` disk** - inside the public directory (eg. `public/basset`)
    - PROs: you are certain the same assets you have on localhost will be in production, because the assets are commited to Git;
    - CONs: your Git history will be dirtier, because it will contain changes to libraries of CSS/JS files;
    - How to enable: do `BASSET_DISK=public_basset` in your .env file or `config/backpack/basset.php` config file;
- **custom** - you can completely customize what disk is used to store the assets - just change it in the config file; most common customizations:
    - store assets on a S3 bucket (using a custom disk);
    - store assets in `public_basset` disk, but add `public/basset` to .gitignore;

#### Can I track the assets in git, just like my source code? (aka NOT gitignore CSS and JS assets)

[](#can-i-track-the-assets-in-git-just-like-my-source-code-aka-not-gitignore-css-and-js-assets)

Yes, you can track the assets in your application repository and avoid downloading them on each deployment (aka. have them in git). The easiest way to do that is to set the `BASSET_DISK=public_basset` in your .ENV, or in the basset config file. This will store the assets in the `public/basset` directory by default and they will now be committed to git alongside the rest of your application code. But note that this has both PROs and CONs:

- PROs: This is advantageous as you know what assets are in your application right when you deploy, avoiding issues like a CDN being down at the deployment time and breaking your application production.
- CONs: As a downside, you must be 100% sure all assets are internalized on localhost, and commited to git. Otherwise, when a page is accessed in production, Basset will internalize that file in production alone (it always prioritizes having production in a working state), which means you'll have uncommitted changes in your production code. You will then have to fix merge conflicts in production, or do a git reset before each deployment.

To summarize - if you're 100% sure that `php artisan basset:cache` is pulling all assets your application needs, you can safely commit your assets to git. If not, you are exposing yourself to conflicts in production (which can be managed as well).

### Events

[](#events)

If you require customized behavior after each asset is cached, you can set up a listener for the `BassetCachedEvent` in your `EventServiceProvider`. This event will be triggered each time an asset is cached.

Change log
----------

[](#change-log)

Please see the [releases tab](https://github.com/Laravel-Backpack/basset/releases) for more information on what has changed recently.

Testing
-------

[](#testing)

```
$ composer test
```

Contributing
------------

[](#contributing)

Please see [contributing.md](contributing.md) for details and a todolist.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Antonio Almeida](https://github.com/promatik)
- [Pedro Martins](https://github.com/pxpm)
- [Cristian Tabacitu](https://github.com/Laravel-Backpack)
- [All Contributors](../../contributors)

License
-------

[](#license)

MIT. Please see the [license file](license.md) for more information.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance69

Regular maintenance activity

Popularity6

Limited adoption so far

Community18

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor2

2 contributors hold 50%+ of commits

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~32 days

Recently: every ~75 days

Total

31

Last Release

182d ago

Major Versions

0.18.0 → 1.0.02023-06-26

1.3.6 → 2.0.0-alpha.12025-01-14

1.3.7 → 2.0.0-alpha.32025-02-24

### Community

Maintainers

![](https://www.gravatar.com/avatar/bfa34fbe26304da44b94d720c13ab86b5b5841faac4a2cc9eeaaab4ee6ab193b?d=identicon)[TanNhatCMS](/maintainers/TanNhatCMS)

---

Top Contributors

[![tabacitu](https://avatars.githubusercontent.com/u/1032474?v=4)](https://github.com/tabacitu "tabacitu (116 commits)")[![promatik](https://avatars.githubusercontent.com/u/1838187?v=4)](https://github.com/promatik "promatik (113 commits)")[![pxpm](https://avatars.githubusercontent.com/u/7188159?v=4)](https://github.com/pxpm "pxpm (82 commits)")[![StyleCIBot](https://avatars.githubusercontent.com/u/11048387?v=4)](https://github.com/StyleCIBot "StyleCIBot (8 commits)")[![TanNhatCMS](https://avatars.githubusercontent.com/u/113796420?v=4)](https://github.com/TanNhatCMS "TanNhatCMS (6 commits)")[![phpfour](https://avatars.githubusercontent.com/u/171715?v=4)](https://github.com/phpfour "phpfour (3 commits)")[![malek77z](https://avatars.githubusercontent.com/u/82019078?v=4)](https://github.com/malek77z "malek77z (3 commits)")[![laravel-shift](https://avatars.githubusercontent.com/u/15991828?v=4)](https://github.com/laravel-shift "laravel-shift (2 commits)")[![jnoordsij](https://avatars.githubusercontent.com/u/45041769?v=4)](https://github.com/jnoordsij "jnoordsij (2 commits)")[![MrMohamedAbdallah](https://avatars.githubusercontent.com/u/51543900?v=4)](https://github.com/MrMohamedAbdallah "MrMohamedAbdallah (1 commits)")[![FrozenSilence](https://avatars.githubusercontent.com/u/58231895?v=4)](https://github.com/FrozenSilence "FrozenSilence (1 commits)")[![szepeviktor](https://avatars.githubusercontent.com/u/952007?v=4)](https://github.com/szepeviktor "szepeviktor (1 commits)")[![iljhli](https://avatars.githubusercontent.com/u/58231895?v=4)](https://github.com/iljhli "iljhli (1 commits)")[![o15a3d4l11s2](https://avatars.githubusercontent.com/u/934385?v=4)](https://github.com/o15a3d4l11s2 "o15a3d4l11s2 (1 commits)")

---

Tags

laravelassetsbassetLoad CSS onceLoad JS once

###  Code Quality

TestsPest

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tannhatcms-basset/health.svg)

```
[![Health](https://phpackages.com/badges/tannhatcms-basset/health.svg)](https://phpackages.com/packages/tannhatcms-basset)
```

###  Alternatives

[backpack/basset

Dead-simple way to load CSS or JS assets only once per page, when using Laravel 10+.

202832.4k6](/packages/backpack-basset)[grumpydictator/firefly-iii

Firefly III: a personal finances manager.

22.8k69.3k](/packages/grumpydictator-firefly-iii)[gehrisandro/tailwind-merge-laravel

TailwindMerge for Laravel merges multiple Tailwind CSS classes by automatically resolving conflicts between them

341682.2k18](/packages/gehrisandro-tailwind-merge-laravel)[digitallyhappy/assets

Dead-simple way to load CSS or JS assets only once per page, when using Laravel 8+.

13973.4k9](/packages/digitallyhappy-assets)[firefly-iii/data-importer

Firefly III Data Import Tool.

7545.8k](/packages/firefly-iii-data-importer)[nickurt/laravel-akismet

Akismet for Laravel 11.x/12.x/13.x

97139.6k2](/packages/nickurt-laravel-akismet)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
