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

Webloader Laravel Package

machy8/webloader

Machy8 WebLoader is a PHP asset manager that combines, minifies, and caches CSS and JavaScript files, supports LESS/SCSS compilation, versioned caching, and easy integration with Laravel or Nette to speed up page loads.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install with Composer. v2.0.1 is the current patch; pin an explicit version rather than floating a constraint if anything downstream depends on the exact tag markup (v2.0.1 changed what the generate methods emit):

    composer require machy8/webloader:^2.0
    
  2. Create a writable, web-accessible cache directory. Bundles are written to disk and served as static files, so the directory must be both writable by PHP and reachable by the browser:

    mkdir -p public/assets/cache && chmod -R 775 public/assets/cache
    
  3. Read the README first, then skim src/WebLoader.php (the public API) and any minifier class. The library is small; the constructor (cache path + public cache URL) and the addFile/addFiles + generateCss/generateJs pair are the whole surface you need on day one.

  4. First use case — bundle and emit a stylesheet/script tag in a layout:

    use Machy8\WebLoader\WebLoader;
    
    $loader = new WebLoader(
        base_path('public/assets/cache'),   // filesystem path
        '/assets/cache'                     // public URL of that path
    );
    
    $loader->addFiles([
        resource_path('css/reset.css'),
        resource_path('css/app.css'),
    ]);
    
    echo $loader->generateCss('app');
    // <link rel="stylesheet" href="/assets/cache/app.abc123.css">
    

    As of v2.0.1 the emitted tags are plain HTML5 — no type="text/css" on <link>/<style> and no type="text/javascript" on <script> — so validated HTML stays warning-free out of the box.

  5. In Laravel, bind it as a singleton in a service provider (see below) so you configure paths once and reuse it across views and helpers.

Implementation Patterns

Service provider + config. Keep paths in config/webloader.php and bind one or more loaders:

// config/webloader.php
return [
    'cache_dir'  => public_path('assets/cache'),
    'cache_url'  => '/assets/cache',
    'minify'     => env('WEBLOADER_MINIFY', true),
];

// AppServiceProvider::register()
$this->app->singleton(WebLoader::class, fn () => new WebLoader(
    config('webloader.cache_dir'),
    config('webloader.cache_url')
));

Named bundles as separate instances. Different pages (admin vs. public, checkout vs. marketing) usually want different bundles. Either create a loader per request inside a Blade component, or expose a small WebLoaderFactory that hands out a fresh instance for a named bundle. Keeping bundles separate avoids shipping the checkout JS to the marketing page.

Blade component or directive for output. Don't scatter echo $loader->generate…() in views. Wrap it:

// app/View/Components/WebLoaderScripts.php
public function render()
{
    $loader = app(WebLoader::class);
    $loader->addFiles([...]);
    return '<x-raw-html :content="$loader->generateJs()" />';
}

or a simple @webloaderJs('app') directive that resolves the loader, adds the configured files, and echoes the tag.

Environment switch. Bundle in production, emit individual <link>/<script> tags in local so you get readable source and no cache staleness. A simple if (app()->isLocal()) helper that loops over files and prints raw tags is worth the 10 lines — it prevents most "why is my CSS change not visible" incidents.

Conditional, ordered additions. Order matters for JS. Add vendor/polyfill files before app code, and add page-specific files at the end of the chain. Because you can add files incrementally, one shared base bundle plus a per-page loader that appends only that page's files is clean.

Cache-busting. If the generated filename is content/mtime-derived, references update automatically. If you get stable filenames, append a version query string yourself using the bundle's mtime — otherwise browsers will serve stale bundles for a long time.

Pre-warm at deploy. Bundling on first request means the first visitor pays the cost and you risk concurrent writes. Add a deploy step (an artisan command that instantiates the loaders and calls the generate methods) so the cache directory is populated before traffic hits. Clear the cache directory in the same step to avoid stale bundles.

Keep it out of the Vite/Mix pipeline. If the app already uses Vite or Mix for JS, webloader is redundant and risks double-processing. It fits best in small/legacy apps, or as a thin CSS concatenator alongside another JS tool.

Gotchas and Tips

  • Writability is the #1 failure. If the cache directory is missing or not writable by www-data, you get a failed write or broken tag rather than an obvious error. Check permissions before debugging anything else, and add the directory to .gitignore but not to your deploy excludes.
  • v2.0.1 is a markup-only release, but it breaks assertions. The type attributes are gone from <link>, <script> and <style> output. Tests that snapshot full tags (assertSee('<script type="text/javascript" src=…')), Blade partials that hard-code the old markup, and any JS/regex that located bundles via type="text/javascript" will all fail on upgrade. Assert on the src/href URL or the file's existence instead of the whole tag.
  • Legacy doctypes and non-HTML5 sinks. If you feed generated tags into XHTML templates, HTML emails, or old feed/RSS markup that still demands type attributes, v2.0.1 output will validate as invalid there. Build the tag yourself around the generated URL in those paths rather than fighting the library.
  • The v2.0.1 release note has a typo (text="text/javascript" instead of type=). The change described is the real one, but it's a hint that the changelog is hand-written — read the actual diff of src/ when upgrading rather than trusting the notes to be exhaustive.
  • File path resolution. Relative paths can resolve against the library's base, not base_path(). Always pass absolute paths from base_path()/public_path()/resource_path(). Remote URLs (https://…) are almost certainly not supported — download or bundle them upstream instead.
  • CSS url() breakage. When CSS files from different directories are concatenated into one file in the cache dir, relative url(fonts/…) / url(images/…) references can resolve against the cache location and 404. Either keep the cache dir at the same depth/root as the sources, use absolute URLs in CSS, or post-process the output. This is the most common visual regression after switching to bundling.
  • Stale cache with no content awareness. Some bundlers key the filename on the list of source paths only. Editing a file contents won't regenerate the bundle. Clear the cache dir on deploy and verify by touching a CSS file and confirming the filename changes. If it doesn't, wire a manual version into your config.
  • Minifier limitations. Very new JS syntax (optional chaining, class fields, ??=, top-level await) can be mangled or left unminified. Leave those files out of minification, or minify upstream with a real tool and point webloader at the result.
  • PHP version compatibility. Test on your target PHP version; expect possible deprecation notices (dynamic properties, passing null to string params) from older code paths. If it's noisy, fork or pin the dependency with a patch.
  • Concurrency. Two simultaneous first requests can both write the cache. Most implementations write atomically (temp file + rename), but don't rely on it — pre-warming at deploy removes the race entirely.
  • No source maps. Debugging minified bundles in production is painful. Keep dev unbundled, or make sure the loader is disabled in local/test environments.
  • Attribute support. Check the generate methods for options to add defer/async/media/integrity. v2.0.1 only removed the type attribute; it didn't add attribute plumbing, so if these aren't supported, build the tag yourself around the generated URL rather than hacking the output string.
  • Silent degradation. Some versions return null/'' when a file is missing or the cache isn't writable. Assert the output in a feature test (bundle file exists, tag contains the cache URL) so a misconfigured directory fails CI rather than production.
  • Debugging recipe. When a tag looks wrong: (1) ls the cache dir and confirm a bundle was written, (2) diff its contents against your source files for missing additions, (3) inspect the filename to infer the hash input, (4) clear and regenerate, (5) check the browser network tab — a 404 on the cache URL usually means a path/URL mismatch between constructor arguments.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource