Stimulus controller and AssetMapper conventions for Symfony bundle assets
php artisan boost:add-skill symkit/routing-bundle
Save this content to: .cursor/rules/bundle-ux.mdc
# Bundle UX — Stimulus & AssetMapper
## File Naming
- `{name}_controller.js` (snake_case) in `assets/controllers/`
- Stimulus identifier: `vendor--bundle-name--controller` (auto-generated, mandatory namespace)
## Controller Rules
- `/* stimulusFetch: 'lazy' */` mandatory on non-critical controllers
- `disconnect()` cleanup mandatory: abort controllers, destroy instances, `removeEventListener`
- Values: camelCase JS (`debounceValue`) → kebab-case HTML
- Targets: camelCase JS (`inputTarget`) → kebab-case HTML
## Communication
- **Events** (loose coupling, preferred): `CustomEvent` with `bubbles: true`, format `{noun}:{verb}`
- **Outlets** (tight coupling): parent-child only
## Distribution
- Always provide `assets/dist/` with pre-compiled output
- `package.json` with `symfony.controllers` metadata (critical for discovery)
- CSS class names prefixed with bundle name (`acme-blog-`)
- JS packages via `importmap:require` only
## FORBIDDEN
- `node_modules`, `package.json` npm, jQuery, npm/yarn
- `DOMContentLoaded`, `window.onload`, `document.querySelector` (incompatible Turbo)
- Manual `data-controller` / `data-action` / `data-*-target` in Twig (use helpers)
- `"fetch": "eager"` for heavy controllers
- `removeComments: true` in tsconfig (breaks `stimulusFetch: 'lazy'`)
- Business logic in controllers — delegate to server via fetch
- Assets in `public/` — use `assets/` + AssetMapper
- Bare `<script src="">` in Twig templates
- CDN links for JS/CSS libraries — use AssetMapper or inline for self-contained pages
## After Every Change
Run `make quality` to validate the full pipeline.
{name}_controller.js (snake_case) in assets/controllers/vendor--bundle-name--controller (auto-generated, mandatory namespace)/* stimulusFetch: 'lazy' */ mandatory on non-critical controllersdisconnect() cleanup mandatory: abort controllers, destroy instances, removeEventListenerdebounceValue) → kebab-case HTMLinputTarget) → kebab-case HTMLCustomEvent with bubbles: true, format {noun}:{verb}assets/dist/ with pre-compiled outputpackage.json with symfony.controllers metadata (critical for discovery)acme-blog-)importmap:require onlynode_modules, package.json npm, jQuery, npm/yarnDOMContentLoaded, window.onload, document.querySelector (incompatible Turbo)data-controller / data-action / data-*-target in Twig (use helpers)"fetch": "eager" for heavy controllersremoveComments: true in tsconfig (breaks stimulusFetch: 'lazy')public/ — use assets/ + AssetMapper<script src=""> in Twig templatesRun make quality to validate the full pipeline.
How can I help you explore Laravel packages today?