{"_id":"@emaia/stimulus-lazy-loader","_rev":"2-685a316f1de984163cc68c48cf9bbaa3","name":"@emaia/stimulus-lazy-loader","dist-tags":{"latest":"2.0.0"},"versions":{"1.1.0":{"name":"@emaia/stimulus-lazy-loader","version":"1.1.0","keywords":["stimulus","hotwire","turbo","lazy-loading","dynamic-import","vite"],"author":{"name":"Ednilson Maia"},"license":"MIT","_id":"@emaia/stimulus-lazy-loader@1.1.0","maintainers":[{"name":"emaia","email":"eu@emaia.dev"}],"homepage":"https://github.com/emaia/stimulus-lazy-loader","bugs":{"url":"https://github.com/emaia/stimulus-lazy-loader/issues"},"dist":{"shasum":"1c74998adb0a13ab1ca92ed68a4b8cbe1e2cf0f5","tarball":"https://registry.npmjs.org/@emaia/stimulus-lazy-loader/-/stimulus-lazy-loader-1.1.0.tgz","fileCount":8,"integrity":"sha512-+mWX0SV3oThDYEAlbtupyDQ+dPNHqhwyF1KBrB21cLxJWmt1z4t1a3ux6d2dsmboX9xnvcE0zoBfAp/dmI02kQ==","signatures":[{"sig":"MEUCIQDjxPOOBtPlsnQiapuNvHIGJu8UUXASMSMQbIr0Hy9SHwIgNa/GIK3LbwUuP25dGSB3ZQSJInR3nDaQPg3oclDN2z4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":14815},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js"},"./loader":{"types":"./dist/loader.d.ts","import":"./dist/loader.js","require":"./dist/loader.js"}},"gitHead":"e27676692e74fb2b16694a3388ccebe5f1d19fde","scripts":{"test":"vitest","build":"tsc","test:run":"vitest run","test:watch":"vitest --watch","test:coverage":"vitest --coverage","prepublishOnly":"bun run build"},"_npmUser":{"name":"emaia","email":"eu@emaia.dev"},"repository":{"url":"git+https://github.com/emaia/stimulus-lazy-loader.git","type":"git"},"_npmVersion":"10.9.4","description":"Dynamic lazy-loading for Stimulus controllers with Turbo support","directories":{},"_nodeVersion":"22.21.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^5.0.12","jsdom":"^27.2.0","vitest":"^1.2.2","typescript":"^5.3.3","@types/jsdom":"^27.0.0","@hotwired/stimulus":"^3.2.2","@vitest/coverage-v8":"1"},"peerDependencies":{"@hotwired/stimulus":"^3.0.0"},"_npmOperationalInternal":{"tmp":"tmp/stimulus-lazy-loader_1.1.0_1782920128175_0.5058396109115526","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@emaia/stimulus-lazy-loader","version":"2.0.0","description":"Dynamic lazy-loading for Stimulus controllers with Turbo support","type":"module","sideEffects":false,"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./loader":{"types":"./dist/loader.d.ts","import":"./dist/loader.js"}},"scripts":{"build":"tsc","test":"vitest","test:run":"vitest run","test:watch":"vitest --watch","test:coverage":"vitest run --coverage","prepublishOnly":"bun run test:run && bun run build"},"repository":{"type":"git","url":"git+https://github.com/emaia/stimulus-lazy-loader.git"},"homepage":"https://github.com/emaia/stimulus-lazy-loader","bugs":{"url":"https://github.com/emaia/stimulus-lazy-loader/issues"},"keywords":["stimulus","hotwire","turbo","lazy-loading","dynamic-import","vite"],"peerDependencies":{"@hotwired/stimulus":"^3.0.0"},"devDependencies":{"@hotwired/stimulus":"^3.2.2","@types/jsdom":"^27.0.0","@vitest/coverage-v8":"1","jsdom":"^27.2.0","typescript":"^5.3.3","vite":"^5.0.12","vitest":"^1.2.2"},"author":{"name":"Ednilson Maia"},"license":"MIT","publishConfig":{"access":"public"},"_id":"@emaia/stimulus-lazy-loader@2.0.0","gitHead":"ff9bf50e5e16f9db98b9945b2302417a4fd7be08","_nodeVersion":"22.21.1","_npmVersion":"10.9.4","dist":{"integrity":"sha512-TTKgLGZKrwzIFlhuDjPjjmiDHvgjSmHoDiU0Trokz2Wj/e//UhR+LMl/I5oEA0IewPCxD9/b7P8oUod1CUKHjQ==","shasum":"1db89ee6c2f3d108d72ed1c37b9c0e6eabe3a7ed","tarball":"https://registry.npmjs.org/@emaia/stimulus-lazy-loader/-/stimulus-lazy-loader-2.0.0.tgz","fileCount":13,"unpackedSize":45350,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIFegHZR3YRVezcMx4qJy0vIYayYMGuvtAKUL7Fw8dAGxAiAo29TAshr/ksBv9tyiWNpY6R/jGu/02qe+2/oEpZwEvA=="}]},"_npmUser":{"name":"emaia","email":"eu@emaia.dev"},"directories":{},"maintainers":[{"name":"emaia","email":"eu@emaia.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/stimulus-lazy-loader_2.0.0_1786540702188_0.8940036820180592"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-01T15:35:27.898Z","modified":"2026-08-12T13:18:22.466Z","1.1.0":"2026-07-01T15:35:28.382Z","2.0.0":"2026-08-12T13:18:22.322Z"},"bugs":{"url":"https://github.com/emaia/stimulus-lazy-loader/issues"},"author":{"name":"Ednilson Maia"},"license":"MIT","homepage":"https://github.com/emaia/stimulus-lazy-loader","keywords":["stimulus","hotwire","turbo","lazy-loading","dynamic-import","vite"],"repository":{"type":"git","url":"git+https://github.com/emaia/stimulus-lazy-loader.git"},"description":"Dynamic lazy-loading for Stimulus controllers with Turbo support","maintainers":[{"name":"emaia","email":"eu@emaia.dev"}],"readme":"# Stimulus Lazy Loader\n\nLoad [Stimulus](https://stimulus.hotwired.dev/) controllers on demand with Vite glob imports. The loader discovers controllers in the initial document and watches later DOM changes without requiring Turbo-specific hooks.\n\n## Features\n\n- Lazy dynamic imports for controllers that appear in the DOM\n- Optional static eager modules for critical controllers\n- Incremental discovery scoped to added or changed DOM subtrees\n- Automatic support for Turbo Drive, Frames, Streams, and morphs\n- Concurrent import deduplication\n- Complete disconnect semantics for pending loads and DOM observation\n- TypeScript declarations for the public API and registry entries\n\n## Installation\n\n```bash\nnpm install @emaia/stimulus-lazy-loader\n```\n\n## Lazy Controllers\n\n```typescript\nimport { Application } from \"@hotwired/stimulus\"\nimport { registerControllers } from \"@emaia/stimulus-lazy-loader\"\n\nconst application = Application.start()\nconst controllers = import.meta.glob(\"./**/*_controller.{js,ts}\")\n\nregisterControllers(application, controllers)\n```\n\nVite transforms each lazy glob entry into an importer function. The loader calls an importer only after its controller identifier appears in `data-controller`.\n\n## Eager And Lazy Controllers\n\nCritical controllers can be included in Vite's static module graph while all other controllers remain lazy:\n\n```typescript\nimport { Application } from \"@hotwired/stimulus\"\nimport { registerControllers } from \"@emaia/stimulus-lazy-loader\"\n\nconst application = Application.start()\n\nconst lazyControllers = import.meta.glob(\n  \"./**/*_controller.{js,ts}\",\n)\n\nconst criticalControllers = import.meta.glob(\n  [\n    \"./navigation_controller.ts\",\n    \"./turbo/progress_controller.ts\",\n  ],\n  { eager: true },\n)\n\nregisterControllers(application, {\n  ...lazyControllers,\n  ...criticalControllers,\n})\n```\n\nThe eager entries are spread last, replacing matching lazy entries in the registry. They are registered during loader initialization even when their identifiers are not yet present in the DOM.\n\nDo not combine the eager glob with `import: \"default\"`. Eager module objects and lazy importer functions have different shapes, which lets the loader distinguish them safely. A default-exported controller class is also a function and would be ambiguous with a lazy importer.\n\nUse eager loading selectively. It removes the dynamic chunk boundary but increases startup download, parsing, and execution for every page that includes the entrypoint. Heavy or conditional controllers should normally remain lazy.\n\n## Registry Precedence\n\nWhen multiple paths resolve to the same Stimulus identifier, the later registry entry wins. Resolution happens before eager modules are registered, so a later lazy application override can replace an earlier eager vendor controller:\n\n```typescript\nregisterControllers(application, {\n  ...vendorControllers,\n  ...criticalVendorControllers,\n  ...applicationControllers,\n}, {\n  warnOnDuplicate: false,\n})\n```\n\n## Options\n\n```typescript\nregisterControllers(application, controllers, {\n  // Warn when two paths resolve to the same identifier. Default: true.\n  warnOnDuplicate: false,\n\n  // Log when a data-controller identifier has no registry entry. Default: true.\n  warnOnMissing: false,\n})\n```\n\n## Explicit Loading\n\nUse `loadController()` to start a known lazy import before its element is added:\n\n```typescript\nconst loader = registerControllers(application, controllers)\n\nawait loader.loadController(\"editor\")\n```\n\nAutomatic and explicit requests for the same exact identifier share one registration promise. Case and underscore variants that resolve to the same registry entry also share one module import, while each exact token is still registered separately so Stimulus can connect it. A failed import clears its module state so a later call can retry. A rediscovery received while an import is in flight is replayed once after that load settles; when the import fails, this replay causes one automatic retry for that in-flight cycle.\n\nFor stricter registry validation in TypeScript, provide Vite's module generic:\n\n```typescript\nimport type { ControllerModule } from \"@emaia/stimulus-lazy-loader\"\n\nconst controllers = import.meta.glob<ControllerModule>(\n  \"./**/*_controller.{js,ts}\",\n)\n```\n\nThe default Vite inference uses `unknown`, so the main API also accepts a runtime-validated `ControllerRegistryInput`.\n\n## Cleanup\n\n```typescript\nconst loader = registerControllers(application, controllers)\n\nloader.disconnect()\n```\n\n`disconnect()` is idempotent. It stops DOM observation, discards pending mutation records, rejects pending public loads with an `AbortError`, and prevents imports from registering controllers after shutdown. Dynamic import downloads cannot be physically cancelled once the browser has started them.\n\nCalls to `loadController()` after disconnect also reject with `AbortError`.\n\n## How Discovery Works\n\n1. Builds an identifier map from the supplied registry paths.\n2. Resolves duplicate identifiers before registering eager winners.\n3. Observes `document` for inserted elements and `data-controller` changes.\n4. Scans the initial document once.\n5. Scans only added subtrees or directly changed elements afterward.\n6. Imports each normalized lazy module once and registers each exact Stimulus identifier once concurrently.\n\n`MutationObserver` already batches synchronous DOM changes. The loader therefore adds no debounce delay. Observing `document` also keeps discovery active when Turbo replaces the entire `<body>`.\n\n## Controller Paths\n\n```text\n./dropdown_controller.ts                         -> dropdown\n./controllers/user_card_controller.js            -> user-card\n./components/modal_controller.ts                  -> modal\n./controllers/admin/settings/billing_controller.ts -> admin--settings--billing\n./javascript/admin/dashboard_controller.js         -> javascript--admin--dashboard\n```\n\n```html\n<div data-controller=\"dropdown\"></div>\n<div data-controller=\"user-card\"></div>\n<div data-controller=\"admin--settings--billing\"></div>\n```\n\nMatching is case-insensitive for path lookup. Underscores in file names become dashes and nested directories become Stimulus `--` namespace separators.\n\nThe path prefix is discarded through the first exact directory segment named `controllers/` or `components/`. Later segments remain part of the Stimulus namespace. Names such as `mycontrollers/` and `webcomponents/` are also ordinary namespace segments. Otherwise, only a leading `./` or `../` is removed. Run the glob from the controllers directory, or include a `controllers/` segment, when preceding directories should not appear in the identifier.\n\n## Upgrading\n\nSee [UPGRADE.md](UPGRADE.md) for version-specific migration instructions and behavioral changes.\n\n## Visual State\n\nLazy loading cannot guarantee that `connect()` runs before the first paint. Initial visibility and layout should be represented in server-rendered HTML and CSS with tools such as `hidden`, `inert`, state attributes, or skeletons. Use eager loading only when a controller must be available with the application entrypoint, not as a substitute for a safe initial DOM state.\n\n## Requirements\n\n- `@hotwired/stimulus` 3.x\n- Vite with `import.meta.glob`, or an equivalent registry supplied by another bundler\n\n## License\n\nMIT\n","readmeFilename":"README.md"}