agallou/grunt-hash-assets-bundle
Symfony bundle adding a Twig grunt_asset() function to reference files renamed by grunt-hash (e.g., main.54e79f6f.css). Looks up matching hashed assets in web/assets and returns the correct /assets URL; throws if missing or ambiguous.
Install the Bundle Add the package via Composer in your Laravel project (though technically designed for Symfony, it can be adapted):
composer require agallou/grunt-hash-assets-bundle
Register the bundle in config/bundles.php (Symfony) or manually load it in Laravel’s service provider.
Configure the Bundle
Publish the default config (if available) or define it in config/packages/grunt_hash_assets.yaml (Symfony) or config/grunt_hash_assets.php (Laravel):
return [
'assets_dir' => public_path('assets'),
'assets_base_path' => '/assets',
];
Run Grunt
Ensure grunt-hash is installed in your project’s package.json:
npm install grunt-hash --save-dev
Configure Grunt to hash assets (see grunt-hash docs) and run:
grunt hash
Use the Twig Function
In your Blade templates (or Twig if using Symfony), leverage the grunt_asset function:
<link rel="stylesheet" href="{{ grunt_asset('css/main.css') }}">
This resolves to /assets/main.[hash].css dynamically.
Asset Pipeline
grunt hash in your build pipeline (e.g., post-build in package.json or Laravel’s post-autoload-dump).Laravel-Specific Adaptations
grunt_asset:
// app/Helpers/AssetHelper.php
if (!function_exists('grunt_asset')) {
function grunt_asset($path) {
$config = config('grunt_hash_assets');
$files = glob($config['assets_dir'] . '/' . $path);
if (count($files) !== 1) {
throw new \RuntimeException("No or multiple files found for: {$path}");
}
return $config['assets_base_path'] . '/' . basename($files[0]);
}
}
AppServiceProvider@boot():
require app_path('Helpers/AssetHelper.php');
Caching Strategies
main.54e79f6f.css).assets_base_path to match your CDN endpoint (e.g., /cdn/assets).Dynamic Asset Loading
assets_dir in config/grunt_hash_assets.php per environment:
'assets_dir' => env('ASSET_PATH', public_path('assets')),
File Naming Conflicts
main*.css (e.g., main.min.css and main.css).main.[hash].css) or enforce naming conventions in your build process.Grunt Configuration Mismatch
assets_dir in the bundle config matches Grunt’s output directory (e.g., dist/ vs. web/assets/).Blade vs. Twig
Case Sensitivity
Main.css vs. main.css).Verify Grunt Output
grunt hash --verbose
Log Bundle Behavior
\Log::debug('Searching for files in:', [$config['assets_dir'], $path]);
Test Edge Cases
my asset.css).Custom Hashing Logic
{{ grunt_asset('css/main.css', { hash: false }) }}
Asset Manifests
mix-manifest.json) for more robust asset resolution:
$manifest = json_decode(file_get_contents(public_path('mix-manifest.json')), true);
return $manifest[$path] ?? $path;
Symfony-Laravel Hybrid
// app/Facades/GruntAsset.php
public static function asset($path) {
return app('grunt_hash_assets.twig')->getFunction('grunt_asset')->getCallable()($path);
}
How can I help you explore Laravel packages today?