Lazy load your Stimulus controllers on demand with Vite's glob imports. Automatically registers controllers as they appear in the DOM.
- ✨ Lazy Loading: Controllers are loaded only when needed
- 🚀 Turbo Integration: Automatically registers controllers on Turbo events
- 🔄 Dynamic DOM: Watches for new elements with MutationObserver
- 📦 Zero Config: Works out of the box with Vite's glob imports
- 🎯 Type Safe: Full TypeScript support
npm install @emaia/stimulus-dynamic-loaderimport { Application } from "@hotwired/stimulus";
import { registerControllers } from "@emaia/stimulus-dynamic-loader";
const Stimulus = Application.start();
const controllers = import.meta.glob("./**/*_controller.{js,ts}", {
eager: false
});
registerControllers(Stimulus, controllers)const options = {
// Custom Turbo events (optional)
turboEvents: [
"turbo:load",
"turbo:frame-render",
],
// Custom debounce wait time in ms (optional, default: 100)
debounceWait: 50,
};
registerControllers(Stimulus, controllers, options)const loader = new StimulusDynamicLoader({
application: Stimulus,
controllers: controllers,
});
// Later, if you need to disconnect
loader.disconnect();- Controller Discovery: Scans the DOM for
[data-controller]attributes - Path Mapping: Creates a map of controller names to file paths
- Lazy Loading: Dynamically imports controllers only when found in the DOM
- Auto Registration: Registers controllers with Stimulus automatically
- Event Listening: Responds to Turbo navigation and DOM mutations
- Debouncing: Prevents excessive registration attempts
- Controllers are loaded only once per name
- Duplicate controller names trigger a console warning
- Failed imports are logged with detailed error messages
- Case-insensitive controller name matching
- Automatically handles Turbo frame renders and stream updates
- MutationObserver watches for dynamically added elements
'./dropdown_controller.ts' → 'dropdown'
'./dropdown_controller.js' → 'dropdown'
'./dropdown_controller.tsx' → 'dropdown'
'./dropdown_controller.mjs' → 'dropdown'
// Flat
'./users_controller.ts' → 'users'
// Controllers folder
'./controllers/users_controller.ts' → 'users'
// Components folder
'./components/dropdown_controller.ts' → 'dropdown'
// Deep nested
'./controllers/admin/settings/billing_controller.ts' → 'admin--settings--billing'<!-- Flat -->
<div data-controller="users"></div>
<!-- Nested -->
<div data-controller="admin--users"></div>
<div data-controller="admin--settings--billing"></div>@hotwired/stimulus^3.0.0- Vite or similar bundler with
import.meta.globsupport
MIT