Laravel 9 - Vite is not bundling my images even if I declared the entry point
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# Laravel 9 & Vite Mystery Solved: Why Your Images Aren't Bundled
As developers working with modern PHP stacks like Laravel, leveraging tools like Vite for asset bundling is essential for a fast and efficient frontend experience. When you dive into configuration files and start dealing with dynamic imports, itâs common to run into subtle mismatches between how the build process generates assets (the manifest) and how the application tries to reference them in Blade templates.
This post addresses a very specific, yet frustrating issue: why referencing an image using `Vite::asset()` fails with an "Unable to locate file in Vite manifest" error, even when you've set up dynamic imports like `import.meta.glob`.
## The Setup: Understanding the Vite Asset Pipeline
You are working on Laravel 9.27.0 and attempting to reference a static image (`resources/images/favicon.png`) directly in your master Blade file using Vite helpers. You correctly identified the setup steps suggested by documentation, which involve configuring dynamic imports within your main JavaScript entry point:
```javascript
// Example app.js setup
import.meta.glob([
'../images/**'
]);
```
And attempting to reference it in Blade:
```blade
{{ Vite::asset('resources/images/favicon.png') }}
```
The failure you encounteredâ`Unable to locate file in Vite manifest: resources/images/favicon.png`âtells us that while the *JavaScript* side is set up to scan for files, the Laravel Blade environment, when using `Vite::asset()`, is expecting a specific structure or configuration that isn't being met by this dynamic globbing approach for static file references.
## Why Dynamic Globbing Fails for Static References
The core misunderstanding often lies in separating *runtime asset loading* (what happens in the browser via JS) from *template asset referencing* (what Laravel/Blade needs to know at build time).
When you use `import.meta.glob`, you are instructing Vite to generate a manifest that maps dynamically imported modules. While this is powerful for loading components or assets based on runtime logic, it doesn't automatically populate the standard public asset map that Blade expects when using helpers like `Vite::asset()`.
For static filesâlike favicons, CSS bundles, or public imagesâthe most reliable method is to let Vite handle the *compilation* and *public serving*, but reference the file path directly where possible, or use Laravel's built-in asset helpers.
## The Correct Approach: Static Linking vs. Dynamic Importing
There are two primary ways to correctly handle assets in a Laravel/Vite environment: static linking for fixed files, and dynamic importing for component loading.
### Method 1: Referencing Public Assets Directly (Recommended for Favicons)
For simple, static assets like favicons that need to be served directly by the web server, it is often simpler and more robust to reference them using standard Laravel asset helper functions, relying on the fact that these files reside in your `public` directory or are correctly mapped by Vite's public assets setup.
If your image is intended to be publicly accessible, try referencing it relative to the public directory, ensuring Vite knows how to handle the final path:
```blade
{{ asset('images/favicon.png') }}
```
*Note: Ensure that the file structure places `favicon.png` directly within the directory Vite monitors for public assets.* This bypasses the complex manifest lookup and relies on Laravel's familiar asset pipeline, which is often more stable than forcing a dynamic globbing setup for simple inclusions.
### Method 2: Using Vite for Bundled Assets (For CSS/JS)
The `import.meta.glob` technique is best reserved for loading JavaScript or CSS bundles that are dynamically required based on runtime conditions. If you were importing a component, the asset would be loaded via the generated manifest path, not necessarily by direct file reference in Blade.
If you need to load an image *dynamically* based on user input (e.g., selecting a theme image), you should load the URL directly using the path Vite exposes:
```javascript
// In your JS file, load the asset based on a variable
const imagePath = import.meta.glob('../images/**')[0]?.default; // Example of dynamic loading logic
// Then use this path in the DOM manipulation.
```
## Conclusion: Trusting the Pipeline
The error you encountered stems from trying to force a runtime dynamic discovery mechanism (`import.meta.glob`) into a compile-time static referencing context (`Vite::asset()`). When dealing with simple, static assets like favicons, relying on Laravel's established asset helpersâwhich are designed to interface smoothly with the Vite build outputâis the most pragmatic solution.
Always ensure that your configuration aligns with what you are trying to achieve. For static file inclusion in Blade, simplify the reference path and let the core scaffolding handle the asset resolution. For complex component loading, embrace the power of dynamic imports within your JavaScript entry points. Remember, mastering the ecosystem means understanding *when* to use dynamic features and *when* to rely on standard framework helpers. For deeper insights into building robust applications with this stack, explore resources from [laravelcompany.com](https://laravelcompany.com).