vite-patterns — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited vite-patterns (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Asset bundling and dev-server patterns for Laravel apps using the official laravel-vite-plugin. Covers vite.config.js, the @vite Blade directive, HMR in development, env vars, aliases, manifests, production builds, code splitting, and bundling for Livewire / Filament / Alpine.
@rules/laravel/laravel.mdc@rules/laravel/livewire.mdc and @rules/laravel/filament.mdc when bundling assets for those layers@rules/php/core-standards.mdc for any PHP touched (Blade config exposure, service providers)laravel-vite-plugin only. Never introduce React/Vue plugins, SSR frameworks, library mode, Bun, or Next.js.VITE_-prefixed vars — those are inlined into the public bundle.npm, php artisan serve, and npm run dev / npm run build.vite.config.js with the laravel() plugin.@vite([...]) directive into Blade layouts.VITE_ env vars or Blade-side config.resolve.alias paths, code splitting, or dynamic imports.npm run dev) runs a Vite dev server that serves source filesas native ESM and pushes HMR updates. The laravel-vite-plugin writes a public/hot file; the @vite directive detects it and points <script> / <link> tags at the dev server instead of built files.
npm run build) bundles, hashes, and writes assets topublic/build/ plus a manifest.json. @vite reads the manifest and emits the hashed URLs. Cache-busting is automatic via the content hash in filenames.
VITE_ are statically inlined into the client bundlevia import.meta.env. Everything else stays server-side.
// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
],
refresh: true, // full-page reload on Blade/route/PHP changes
}),
],
});input lists every entrypoint. Add more for admin panels or per-sectionbundles (resources/js/admin.js).
refresh: true triggers a full reload when Blade views, routes, or PHPconfig change. Pass an array of globs to watch extra paths:
laravel({
input: ['resources/js/app.js'],
refresh: ['resources/views/**', 'app/Livewire/**'],
}),Load entrypoints in your layout <head>:
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html>
<head>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
{{ $slot }}
</body>
</html>@viteReactRefresh is needed — this is a Blade/Livewire/Alpine stack, notReact. Do not add it.
@vite emits a script pointing at the running dev server. Inproduction it resolves hashed URLs from the manifest. Same directive, both modes — you write it once.
them; for Blade-referenced static assets use Vite::asset('resources/...').
Tailwind compiles through the CSS entrypoint, so no extra Vite wiring is needed:
/* resources/css/app.css */
@import "tailwindcss";// resources/js/app.js
import './bootstrap';@vite(['resources/css/app.css', ...]) handles HMR for Tailwind classes in dev and outputs a hashed, purged stylesheet in the production build.
Run two processes:
php artisan serve # serves the Laravel app
npm run dev # Vite dev server + HMRpublic/hot. Add public/hot and public/build to.gitignore.
refresh enabled,Blade/PHP edits trigger a full-page reload.
laravel({ input: ['resources/js/app.js'], refresh: true }),
// server config:
server: {
host: '0.0.0.0',
hmr: { host: 'localhost' },
},Only VITE_-prefixed vars reach the client bundle via import.meta.env:
// resources/js/app.js
const apiUrl = import.meta.env.VITE_API_URL;
const mode = import.meta.env.MODE; // 'development' | 'production'# .env
VITE_API_URL="${APP_URL}/api"VITE_ is not a security boundary — these values are inlined into theshipped JS. Put only public values (public URLs, feature flags, public keys) here. API tokens, DB credentials, and signing keys stay server-side.
passing them from Blade instead of baking them at build time:
<script>
window.AppConfig = @json(['locale' => app()->getLocale(), 'csrf' => csrf_token()]);
</script>import { fileURLToPath, URL } from 'node:url';
export default defineConfig({
plugins: [laravel({ input: ['resources/js/app.js'], refresh: true })],
resolve: {
alias: {
'@': fileURLToPath(new URL('./resources/js', import.meta.url)),
},
},
});Then import Foo from '@/components/Foo';. Keep the alias list small — add an entry only when a real import path needs it.
npm run buildpublic/build/assets/ plus public/build/manifest.json.@vite reads the manifest to emit the correct hashed URLs — no manualversioning. The content hash in each filename is the cache-busting mechanism; changed files get new hashes, unchanged files keep theirs so browsers reuse cached copies.
public/build nor public/hot; build assets in deploy/CI.Vite splits dynamically imported modules into separate chunks automatically:
// load a heavy module only when needed
button.addEventListener('click', async () => {
const { renderChart } = await import('./chart.js');
renderChart(data);
});Group stable vendor code into its own chunk to improve cache reuse across deploys:
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['alpinejs', 'axios'],
},
},
},
},Avoid splitting every dependency into its own chunk — that produces many tiny requests. Group by stability instead.
For routes/modules likely needed soon, hint the browser with a dynamic import behind an idle callback so the chunk is fetched ahead of interaction:
requestIdleCallback?.(() => import('./chart.js'));This warms the chunk cache without blocking the initial render.
// resources/js/app.js
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();@vite bundle additive(custom Alpine components, hooks) and let Livewire manage its own assets per @rules/laravel/livewire.mdc. Do not bundle a second Alpine copy — Livewire already includes one; if you import Alpine yourself, follow Livewire's guidance to avoid a duplicate instance.
Filament theme + its asset pipeline for panel styling rather than forcing it through your app entrypoint (@rules/laravel/filament.mdc). Reserve your Vite bundle for front-end (non-panel) views.
npm ci
npm run build # writes public/build + manifest.jsonRun npm run build in CI before deploying; ship public/build/. Missing manifest entries surface at render time as a Vite manifest not found exception, so the build step must succeed before the app boots in production.
vite.config.js declares every entrypoint via the laravel() plugin withrefresh configured for the watched paths.
@vite([...]); no @viteReactRefresh present.npm run dev + php artisan serve give working HMR locally; public/hot andpublic/build are gitignored.
VITE_-prefixed (public) vars are inlined client-side; secrets stay server-side.npm run build produces a hashed public/build/ + manifest.json, and CIruns the build before deploy.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.